Soft Function Hooking with windbg and pykd

There are a lot of ways to modify the execution of a program, including at least using Windows Compatibility Toolkit (a good reference is Mark Baggett’s Derbycon talk), modifying the environment, manual patching the binary before it runs, and function hooking.  Function hooking generally refers to any method where you’re able to intercept and modify function calls of a running process. A simple example of a function hook might be “every time the program calls AESEncrypt, first save the plaintext to a file and then call AESEncrypt”.

There are also many different ways to function hook, and in my opinion there isn’t really a “best” way – it just depends on what you’re trying to do. For example, if you’re doing something to try to be sneaky, one of the best ways may be like Joe outlines here:

  1. Reflectively load your DLL using powershell so nothing needs to ever touch disk
  2. In your DLL, write a C function that contains the functionality to execute. Optionally, return control to the original function
  3. Overwrite the first bytes of the function to jump to your DLL

However, if your goal is to change the behavior of a program and you don’t care about stealth (e.g. you’re just using hooking as an aid to testing) there are easier ways to accomplish the same goal. “soft” function hooking usually refers to attaching a debugger to a program and using the debugger’s functionality to modify the behavior. I’ve seen this approach elsewhere – in gray hat python, they use this technique with pydbg and immunitydbg.

I learned about pykd because of mona for windb. I messed with pykd last week, and I like it quite a bit (at least more than windbg plugin alternatives I’ve used like powerdbg). There are pluses and minuses when compared with something like immunity debugger. Pykd doesn’t currently have nearly the number of convenience functions immunitydbg has (for example, you have to store your strings in memory manually). UPDATE:  In this case I was looking for something like remotevirtualalloc and didn’t see it. But @corelanc0d3r pointed me at windbglib, which has these exact convenience functions.   But Windbg is just a more powerful debugger. For example, immunitydbg is awesome, but it doesn’t work with 64 bit processes, following children processes, kernel debugging, etc.

Here is a simple example. I ran into a situation where a team’s test box had a hard coded a test server to listen only on localhost. This can be a pain to debug, because a lot of my tools are on other boxes and plus I can’t do things like see what’s actually going on with wireshark. This is a quick script that modifies the behavior of inet_addr, which is where this binary passed the hard coded localhost to (if you’re wondering why I didn’t just patch it – that was an option too, but there was some other important stuff right next to it in .data and ‘localhost’ was too small to fit my IP). So this hook simply grabs the current IP and passes it as the arg to inet_addr instead of “localhost”

Some things I got a bit stuck on

  1. Use the second argument with setBP to have a callback function on the breakpoints, and then use this to modify things. Note you can’t mess with execution within the function itself. Before going this route I tried to use the EventHandlers (like onBreakPoint) and ended up with weird errors.
  2. Within your callback function, if you return True (or nothing), execution will halt, and if you return False then execution will continue
#!/usr/bin/python
import pykd
import socket
#pykd script to modify inet_addr calls to a supplied IP address

def getAddress(localAddr):
    res = pykd.dbgCommand("x " + localAddr)
    if res.count("\n") > 1:
        print "[-] Warning, more than one result for", localAddr
    return res.split()[0]

class handle_inet(pykd.eventHandler):
	def __init__(self):
		#pykd.eventHandler.__init__(self)
		self.localAddr = socket.gethostbyname(socket.gethostname())
		print "[+] Using ip address: " + self.localAddr

		bp_init = getAddress("WS2_32!inet_addr")
		self.bp_init = pykd.setBp(int(bp_init, 16), self.handle_inet_begin)
		self.bp_end = None
		pykd.go()

	def handle_inet_begin(self, args):
		print args
		print "[+] At start of inet_addr."
		ow_len = len(self.localAddr) + 1

		#just save our string below us on the stack. We'll restore it on return
		#ret_addr = pykd.dbgCommand("k1").split("\n")[1].split()[1] #k doesn't work in win7, wtf
		self.ret_addr = pykd.dbgCommand("dd esp L1").split()[1]

		print "[+] saving return ptr: " + self.ret_addr

		self.bp_end = pykd.setBp(int(self.ret_addr, 16), self.handle_inet_end)
		self.stack_addr = pykd.reg("esp") + 500

		print "[+] using this stack address to save our string: " + hex(self.stack_addr)

		self.old_stack = pykd.loadBytes(self.stack_addr, ow_len)
		print "[+] Writing over old stack stuff"
		pykd.dbgCommand("ea " + hex(self.stack_addr) + " \"" + self.localAddr + '"')
		#null terminate
		pykd.dbgCommand("eb " + hex(self.stack_addr) + "+" + hex(len(self.localAddr)) + " 00")

		#esp + 4 is the IP address parameter for inet_addr
		pykd.dbgCommand("ed esp+4 " + hex(self.stack_addr))

        #Since this is a conditional bp, this makes the debugger continue
		return False

	def handle_inet_end(self, bp):
		if self.bp_end == bp:
                        print "[+] Call complete"
			old_stack = " ".join([hex(i)[2:] for i in self.old_stack])
			pykd.dbgCommand("eb " + hex(self.stack_addr) + " " + old_stack)
			print "[+] Old stack stuff restored"
			self.bp_end = None
		#Since this is a conditional bp, this makes the debugger continue
		return False

d_handle = handle_inet()

If you know windbg basics and python, this should be really familiar – I have a tiny bit of python to grab the IP, and then inside the handlers I’m pretty much just running windbg commands sequentially. I ran this in the debugger itself. Here’s a side tip. You can run put commands in a textfile for them to run in windbg (similar to gdb’s -x arg). So you can do this to load this pykd script automatically.

> type windbg.txt
.load pykd.pyd
!py local_listen.py
> windbg -c "$$><windbg.txt" server1.exe

Capture

Another options would be to run this directly from the command line, which is also doable. Just use the pykd “attachProcess” or “startProcess” functions and go from there.

Using windbg to beat my dad at chess

My dad is awesome. He always beats me at chess. With a huge nod to this uninformed post – introduction to reverse engineering win32 applications where they debug minesweeper, I decided to dive into the windows 7 chess game and see if I could give myself a bit of an advantage. I wasn’t sure exactly what I wanted to do other than that. I’ll be using Windows 7 32 bit, and the file is at C:\Program Files\Microsoft Games\Chess\. This tutorial will probably not work with anything but Windows 32 bit. This is a beginner tutorial.

Recon and Defining what we want to do

Following the uninformed post, I wondered if chess might contain symbols also, as this would make my life easier. I have this set in my config, but if you don’t then you will want to set your symbol path.

0:000> .sympath srv*c:\debug*http://msdl.microsoft.com/download/symbols
Symbol search path is: srv*c:\debug*http://msdl.microsoft.com/download/symbols
Expanded Symbol search path is: srv*c:\debug*http://msdl.microsoft.com/download/symbols
0:000> .reload /f *
0:000> lm
start    end        module name
001b0000 00474000   Chess      (pdb symbols)          c:\debug\Chess.pdb\1467728C9EEA429C9FA465213785E17C1\Chess.pdb
6e030000 6e06c000   OLEACC     (pdb symbols)          c:\debug\oleacc.pdb\DC8A57A3E8C648228F2C3650F2BE1D672\oleacc.pdb
6f900000 6f972000   DSOUND     (pdb symbols)          c:\debug\dsound.pdb\F38F478065E247C68EDA699606F56EED2\dsound.pdb

Awesome, we have a chess.pdb. In the uninformed post they use windbg to look at functions, but I find IDA Pro easier to read. Loading chess.exe into IDA we see quite a few functions right off the bat that look interesting. It looks like there’s a Pawn class, a knight class, a bishop class, etc

Pawn::GetCaptureMoves(int const * *)   .text 0102D605 00000017 R . . . B . .
Pawn::GetShadowRadius(void)            .text 0102D621 00000007 R . . . . . .
Knight::Knight(ESide)                  .text 0102D62D 0000001D R . . . B . .
Knight::Clone(void)                    .text 0102D64F 0000002B R . . . . . .
Knight::GetPassiveMoves(int const * *) .text 0102D67F 00000017 R . . . B . .
Knight::CanJump(void)                  .text 0102D69B 00000003 R . . . . . .
Knight::GetPieceType(void)             .text 0102D6A3 00000004 R . . . . . .
Knight::GetShadowRadius(void)          .text 0102D6AC 00000007 R . . . . . .
Bishop::Bishop(ESide)                  .text 0102D6B8 0000001D R . . . B . .
Bishop::Clone(void)                    .text 0102D6DA 0000002B R . . . . . .
Bishop::GetPassiveMoves(int const * *) .text 0102D70A 00000017 R . . . B . .
Bishop::GetPieceType(void)             .text 0102D726 00000004 R . . . . . .
Rook::Rook(ESide)                      .text 0102D72F 0000001D R . . . B . .
Rook::Clone(void)                      .text 0102D751 0000002B R . . . . . .

So there seem to be two outliers, knights and pawns. Knights have extra moves like canjump, and pawns can move certain places depending on other pieces, so this makes sense. Also, this gives us a big clue that these classes contain some of the logic we can use to determine which piece can move where.

So how should I beat my dad? He’s not a grandmaster, so maybe if I made bishops move like queens for me that would do the trick. There is also a board class, so another idea I had was to replace the bishops with queens when the board was setup, but that’s not the route I went.

There’s this function getpassivemove common to all the classes

0:010> x chess!*getpassivemove*
009bd781 Chess!Rook::GetPassiveMoves = <no type information>
009bd7f8 Chess!Queen::GetPassiveMoves = <no type information>
009bd67f Chess!Knight::GetPassiveMoves = <no type information>
009bd5d6 Chess!Pawn::GetPassiveMoves = <no type information>
009bd87b Chess!King::GetPassiveMoves = <no type information>
009bd70a Chess!Bishop::GetPassiveMoves = <no type information>

Setting a bp here it’s tough to tell what’s going on because it’s hit so frequently, but the functions are really simple, and for the most part they look VERY similar between pawn/rook/knight/king/etc classes

So let’s just replace the first instruction to jump to the other function. I had mona loaded into windbg here, but you can also do this with the metasploit asm shell or nasm.

What this does is modify the Chess!Bishop::GetPassiveMoves function and has it immediately jump to Chess!Queen::GetPassiveMoves. (The addresses on your box will certainly be different)

0:010> !py mona asm -s "mov eax, 0x0076d7f8#jmp eax"
Hold on...
Opcode results : 
---------------- 
 mov eax, 0x0076d7f8 = \xb8\xf8\xd7\x76\x00
 jmp eax = \xff\xe0
 Full opcode : \xb8\xf8\xd7\x76\x00\xff\xe0 

[+] This mona.py action took 0:00:02.172000

0:010> eb 0076d5d6 b8 f8 d7 76 00 ff e0
0:010> uf Chess!bishop::GetPassiveMoves
Flow analysis was incomplete, some code may be missing
Chess!bishop::GetPassiveMoves:
0076d5d6 b8f8d77600      mov     eax,offset Chess!Queen::GetCaptureMoves (0076d7f8)
0076d5db ffe0            jmp     eax
0:010> g

Sure enough, this works. When we run we can move anywhere with our bishops

powerful_bishop

Problems

At this point, even though we can move anywhere, we still have two problems we need to solve. 1) both black and white can move anywhere, so this doesn’t give me an advantage. What I really want is just white to be able to move anywhere 2) We can’t just write to this address because of ASLR and also because it’s a read only section of memory.

What does it mean for us that ASLR is enabled? Any static addresses will likely change from run to run of the chess game. Looking for non-aslred modules, there are none. By the way, I’m using mona here.

0:000> !py mona noaslr
Hold on...
No aslr & no rebase modules :
[+] Generating module info table, hang on...
    - Processing modules
    - Done. Let's rock 'n roll.
----------------------------------------------------------------------------------------------------------------------------------
 Module info :
----------------------------------------------------------------------------------------------------------------------------------
 Base       | Top        | Size       | Rebase | SafeSEH | ASLR  | NXCompat | OS Dll | Version, Modulename & Path
----------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------

So for us, we can’t really rely on any hard coded addresses.

Additionally, even if we solved ASLR, our hard jump strategy will also fail because both white and black call the GetPassiveMoves function. We need a way to only modify that function for white.

Figuring out Whose Turn it is

Getting turn info took a bit of shooting in the dark also, but because of symbols it was relatively easy to track down.

First I put a breakpoint here:

bp Chess!GameState::GetTurn +3 "r eax; g"

This is called a lot, and it seems to return 2 or 0 for white, and 0, 1, or 2 for black. This function will probably work, but there’s another turn function too named toggleturn, so lets try that. This function seems perfect – it’s called once after every move. We can see it’s testing the value in [ecx+4] so we inspect that, and sure enough it’s 1 before a white move and 0 before a black move

bp Chess!GameState::toggleturn
dd ecx + 4

Programatically Changing the Game

I’m going to programattically debug the process. The way the uninformed post did things was cool, but it’s (more) difficult to go route way because we’re not messing with data, we’re messing with the program which is non writable. So how do we programatically debug?

There are a ton of ways. Mona uses this and it looks awesome: http://pykd.codeplex.com/. I’m a python guy, so usually I’d go that route, but I’m trying to learn powershell so I decided to try going that route and use this http://powerdbg.codeplex.com/. For the powershell to work you need to install this module.

The first thing I want to do is change the hard coded value to something I can switch back and forth. So I tried setting a breakpoint that I could disable per turn

bp Chess!Bishop::GetPassiveMoves "r eip=Chess!Queen::GetPassiveMoves;g"

This was waaaay too slow for the game to be playable. I had to figure out something else. This is when I noticed just how similar the getpassivemoves functions are

0:012> uf Chess!Bishop::GetPassiveMoves
Chess!Bishop::GetPassiveMoves:
00c5d70a 8bff            mov     edi,edi
00c5d70c 55              push    ebp
00c5d70d 8bec            mov     ebp,esp
00c5d70f 8b4508          mov     eax,dword ptr [ebp+8]
00c5d712 c700f07ec300    mov     dword ptr [eax],offset Chess!Bishop::sPassiveMoves (00c37ef0)
00c5d718 a1e87ec300      mov     eax,dword ptr [Chess!Bishop::sPassiveMovesCount (00c37ee8)]
00c5d71d 5d              pop     ebp
00c5d71e c20400          ret     4
0:012> uf Chess!queen::GetPassiveMoves
Chess!Queen::GetCaptureMoves:
00c5d7f8 8bff            mov     edi,edi
00c5d7fa 55              push    ebp
00c5d7fb 8bec            mov     ebp,esp
00c5d7fd 8b4508          mov     eax,dword ptr [ebp+8]
00c5d800 c700b880c300    mov     dword ptr [eax],offset Chess!Queen::sPassiveMoves (00c380b8)
00c5d806 a1b080c300      mov     eax,dword ptr [Chess!Queen::sPassiveMovesCount (00c380b0)]
00c5d80b 5d              pop     ebp
00c5d80c c20400          ret     4

They’re very close, and they’re the exact same number of bytes. We can just edit things on the fly, replacing the queen’s code with the bishop’s code and back again.

Import-Module PowerDbg

#global vars, populated later
$bishop_code = ""
$queen_code = ""


function bishop_to_queen
{
    $command =  "eb Chess!Bishop::GetPassiveMoves+a " + $queen_code
    Invoke-DbgCommand $command
}

function bishop_restore
{
    $command = "eb Chess!Bishop::GetPassiveMoves+a " + $bishop_code
    Invoke-DbgCommand $command
}


New-DbgSession -command 'C:\Program Files\Microsoft Games\Chess\Chess.exe'
Load-PowerDbgSymbols "srv*c:\debug*http://msdl.microsoft.com/download/symbols"


#get the bytes for the different bishop and queen functions
$bishop_array = (Invoke-DbgCommand "db Chess!Bishop::GetPassiveMoves+a L7").Split(" ")[2..8]
$bishop_code = [string]::join(" ", $bishop_array)

$queen_array = (Invoke-DbgCommand "db Chess!queen::GetPassiveMoves+a L7").Split(" ")[2..8]
$queen_code = [string]::join(" ", $queen_array)


bishop_to_queen


$white_turn = $true
Invoke-DbgCommand "bp Chess!GameState::ToggleTurn"


#this loops once per turn
while($true)
{
    if ($white_turn -eq $true)
    {
        $white_turn = $false
        bishop_to_queen
    }
    else
    {
        $white_turn = $true
        bishop_restore
    }

    $ret_error = Invoke-DbgCommand "g"

    if ($ret_error.Contains("No runnable debugees"))
    {
        break;
    }

}

And there we go, a runnable chess game where white bishops are super powerful. There are a few quirks, like if a bishop gets a king into checkmate with a queen move it doesn’t seem to register and you can kill the king and keep playing, but overall pretty good :)

king_killed

I am still a noob at reversing, but this was still a fun afternoon :)

Redirecting STDIN on windbg

I learned how to use gdb on Linux before I knew anything about debugging on Windows. In those days, some of the first memory manipulation problems I tried were these one: http://community.corest.com/~gera/InsecureProgramming/. An example is stack2:

int main() {
	int cookie;
	char buf[80];

	printf("buf: %08x cookie: %08x\n", &buf, &cookie);
	gets(buf);

	if (cookie == 0x01020305)
		printf("you win!\n");
}

This is a very easy problem, but imagine it’s difficult enough that it’s hard to figure out in your head and imagine how you might solve it (or see what’s going on) using a debugger. With Linux this solution might looks something like:

gdb stack2
(gdb) run < payloadfile

Where payloadfile might be programmatically generated and have a bunch of special characters with shellcode and whatnot.

Programs that process STDIN are a lot rarer in the Windows world, but they certainly exist. Debugging this under Windows is also a slightly more difficult problem. With some common debuggers like Ollydbg or cygwin’s gdb I’m not sure redirecting STDIN from a file is possible. Last year I asked on openrce and didn’t get a response: http://www.openrce.org/forums/posts/1859.

Solution 1: Following Children

What I ended up doing in my ‘real’ problem is attaching the debugger to cmd.exe and following the child process (this is not the default). This solution is nice, in that it also should work with stdout type things you’d want to do with windbg.

0:001> .childdbg
Processes created by the current process will not be debugged
0:001> .childdbg 1
Processes created by the current process will be debugged

Now the process will break when cmd spawns the child. So in cmd you can simply.

stack2.exe < payloadfile

After the breakpoint, you can do an lm to see our image is loaded and run as normal. A more concise one liner to doing this would be (note: there’s a kb article, but they leave out the /o option which tells the debugger to follow children… so is kinda important).

windbg /o cmd.exe /c "stack2.exe < payloadfile"

This is one of many reasons being able to attach to children processes is a must for me in using a debugger. Too bad a lot of good debuggers (e.g. ollydbg1, cygwin gdb, immunitydbg) don’t support following child processes. A solution I’ve seen more than once is to actually patch the executable and put it to sleep, just so you can attach to the process (e.g. https://www.corelan.be/index.php/2012/02/29/debugging-fun-putting-a-process-to-sleep/). If it works, great, but it seems like a kludge – and when you start debugging complicated server applications this approach doesn’t seem practical.

Solution 2: Crash Dump

In linux, analyzing the crash might give enough information to debug an exploit without having to attach to a debugger at the start. This isn’t the same as redirecting STDIN, but at the same time, it might have most of the information you need.

$ ulimit -c unlimited
$ ./stack2 < payloadfile
SEGFAULT
$ gdb ./stack2 core

Doing something similar in Windows, you can set windbg (or a lot of other things including olly, gdb) as the default SEH debugger. In windbg you can do this by just using the -I arg.

> windbg -I

This is great for most realistic scenarios, but depending on how the program was compiled it may not always work. For example, cygwin generates a stacktrace and there isn’t a normal crash (keep this in mind when fuzzing cygwin compiled things – you might not be detecting crashes correctly). How to debug these on a crash varies, but in cygwin’s case you can attach gdb on the error by setting the CYGWIN configuration error_start parameter like this: export CYGWIN=”$CYGWIN error_start=gdb -nw %1 %2″

Follow

Get every new post delivered to your Inbox.

Join 39 other followers