Monday, September 10, 2012

I'm in ur memoryz scannin' yur kodez.

So I've been slowly working on hacking my pnkbstrk.sys tracer script. It's going pretty well, much better than I thought it would have. In this post I'm going to explain how I built my script along with some of the 'interesting' things I've seen the driver do.

Basically I'm tracing the functions I think are important. Out of the five or so that I created breakpoints for, only three really displayed anything of interest so far. One function that calls KeTickCount I could have *sworn* would be called for doing some anti-debugging checks in kernel mode never ended up being called. I guess it is something that is triggered either randomly, or by a PB admin? Anyways, the three which were interesting were; MD5Update, strlen and memcpy. To see them all check out the latest 'testing.py' in my auto_ghast github repo. (At least when github comes back up...)

In the mean time here is the pykd code next to the ida function and windbg result of MD5Update.
MD5Update bp + ida + windbg result
You should be able to guess how I got the various addresses by looking at the IDA function call and the pykd code. But just to make sure, I'll explain. First we need to get the RVA of where we will set the initial breakpoint. At first I buggered it up and set my bp at the function entry, which when looking up the address of values by using the offset + ebp, I got the totally wrong address. I needed to set the breakpoint after the function prolog. In this case ee00c373. You'll notice my RVA is 0x6373, this is due to subtracting from the base address, in IDA that would be ee006000 (so ee00c373-ee006000 = 0x6373). But the code will automatically determine the base address by looking up the PnkBstrK.sys driver information when it's loaded. This makes it so there is no need to re-calculate every time the driver is reloaded (which happens to be every time the game is started).

The first value that's retrieved is the length which we dereference ebp+0x10 to get the value. This ends up being 69 bytes. The second value is the buffer address. Which in IDA you can see as being called arg_buf. This is at ebp+0x0c, for this we don't have a value, but yet another address. So we run loadBytes at the address of arg_buf with our length value and print it out. As you can see in the windbg results this happens to be that mysterious MD5 sum I saw a long time ago. The rest is printing out the MD5Context structure which, if you look at the testing.py code you'll see how I extract the various members of the structure.

So yeah, that's MD5Update all nicely traced :). Next up was strlen. In this particular run, it basically strlen's the same weird md5 value we see in MD5Update.
strlen doin it's thang
Yeah, pretty obvious. Saving the best for last, we have memcpy. This was the most interesting as I saw it basically incrementing through 0x1000 bytes at a time, doing a memcpy *directly* from userland addresses into a kernel address (pretty sure that's a big no-no but whatever), where, I'm sure it's doing some analysis/checks. Check it out:
memcpy, now things are starting to get interesting...
So yeah I think tracing to see what it does with these blobs of memory after it memcpy's will reveal some very interesting things about PnkBstrK.sys.  Until next time!