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″

pydbg reverseme solution

Last week I wrote a keygen here.

This is an almost identical problem, but the binary has been patched to allow debugging (I may do this programmaticly as well, but not yet). I wanted to solve this with programmatic debugging. Here is the exe:
Ice9pch3.

The code simply sets a breakpoint and prints the key to the screen. Also it patches the process memory so that the serial is valid.

import sys
import ctypes

from pydbg import *
from pydbg.defines import *


print "This is a very stupid keygen that uses a debug method and grabs the key from memory"
print "prints out the valid key, and writes it to memory"
print "Basically, pydbg 'hello, world'"
print "-------------"

if len(sys.argv) != 2:
    print "Error. USAGE: keygen.py C:fullpathice"
    sys.exit(-1)

def handler_breakpoint(mdbg):
    valid_str = ""
    #the valid serial is at 004030C8
    addr = 0x004030C8
    while 1:
        tmp = mdbg.read(addr, 1)
        addr += 1
        if tmp != "x00":
            valid_str = valid_str + tmp
        else:
            break
    print "The valid string is: ", valid_str
    print "Writing this to memory..."
    #write this to memory at 004030b4
    #def write (self, address, data, length=0)
    wdata = ctypes.create_string_buffer(valid_str)
    mdbg.write(0x00403198, wdata, len(valid_str))
    #checking the write
    #print mdbg.read(0x00403198, len(valid_str) + 1)
    return DBG_CONTINUE

dbg = pydbg()
dbg.set_callback(EXCEPTION_BREAKPOINT, handler_breakpoint)
dbg.load(sys.argv[1])
dbg.debug_event_iteration()
#at 004011FF in execution, 
#def bp_set (self, address, description="", restore=True, handler=None):
dbg.bp_set(0x004011F5)
dbg.debug_event_loop()

Updated solution. I change a register now to circumvent the isdebuggerpresent call.

import sys
import ctypes

from pydbg import *
from pydbg.defines import *


print "This is a very stupid keygen that uses a debug method and grabs the key from memory"
print "prints out the valid key, and writes it to memory"
print "Basically, pydbg 'hello, world'"
print "-------------"

if len(sys.argv) != 2:
    print "Error. USAGE: keygen.py C:fullpathice"
    sys.exit(-1)

def handler_breakpoint(mdbg):
    if mdbg.get_register("EIP") == 0x004011F5:
        valid_str = ""
        #the valid serial is at 004030C8
        addr = 0x004030C8
        while 1:
            tmp = mdbg.read(addr, 1)
            addr += 1
            if tmp != "x00":
                valid_str = valid_str + tmp
            else:
                break
        print "The valid string is: ", valid_str
        print "Writing this to memory..."
        #write this to memory at 004030b4
        #def write (self, address, data, length=0)
        #wdata = ctypes.create_string_buffer(valid_str)
        mdbg.write(0x00403198, valid_str, len(valid_str))
        #checking the write
        #print mdbg.read(0x00403198, len(valid_str) + 1)
    if mdbg.get_register("EIP") == 0x40106e:
        mdbg.set_register("EAX", 0)
    return DBG_CONTINUE

dbg = pydbg()
dbg.set_callback(EXCEPTION_BREAKPOINT, handler_breakpoint)
dbg.load(sys.argv[1])
dbg.debug_event_iteration()
#0x40106e is the point where we can circumvent the isdebugger present call
dbg.bp_set(0x40106e)
#at 004011FF in execution, 
#breakpoing for reading writing final compare
dbg.bp_set(0x004011F5)
dbg.debug_event_loop()
Follow

Get every new post delivered to your Inbox.

Join 34 other followers