2009-06-16

pyNanomites - part3 : Running the protected binary

Here we are for the last part of this series of posts about a proof of concept implementation of the nanomites protection.
As I said before, we will use a python library in order to implement the debugger. The best way to implement a debugger in python is... pydbg! This library is part of Paimei, a reverse engineering framework created by Pedram Amini and is available for Windows and OS X since a few months. This Swiss army knife will be use a lot of times in this blog and I encourage you to read the documentation and play with it. Here is an extract of the documentation:

PyDbg exposes most of the expected debugger functionality and then some. Hardware / software / memory breakpoints, process / module / thread enumeration and instrumentation, system DLL tracking, memory reading/writing and intelligent dereferencing, stack and SEH unwinding, exception and event handling, endian manipulation routines, memory snapshot and restore functionality, disassembly (libdasm) engine, and more...


The first step in the script will be to retrieve the table from the file. I won't explain this code as it would be useless:


def getJmpTable(filename):
jmpTable = {}
f = open(filename, 'r')
for line in f:
elem = line.rsplit(' ')
jmpTable[elem[0].rstrip('L')] = elem[1].rstrip('\n')
return jmpTable


As pydbg is well written, it is really easy to implement the debugger. The first step is to set a callback for the desired exception, which in our case is the breakpoint exception.


dbg = pydbg()
dbg.set_callback(EXCEPTION_BREAKPOINT, brkHandler)


Then we just have to load the binary into pydbg and launch the process:


dbg.load(os.sys.argv[1])
dbg.debug_event_loop()


Before describing our breakpoint exception's handler, I have to explain something about pydbg. If you look into the source code at pydbg.py:1528 (I'm looking at the OS X version while writting this post) you will see a call to bp_is_ours. This check is a little bit anoying in our case as we want to have our callback call for the breakpoints (int3 instructions) even if they are not set by pydbg. Here you have two options:
  1. modify pydbg code
  2. consider that this is only a POC... and use a loop to set the breakpoints from the table
Back to our handler... When a debugger is attaching to a process, a new thread is created and the function ntdll!DbgBreakPoint is called (more informations can be found on nezumi's blog). This means that the first time our handler is called, we just have to pass.
The next step is to retrieve the context of the thread who triggered the exception and check if eip is corresponding to an address in the table. If it is the case, eip is modified and the context is restored.


def brkHandler(pydbg):
if pydbg.first_breakpoint:
return DBG_CONTINUE
ctx = pydbg.get_thread_context(pydbg.open_thread(pydbg.dbg.dwThreadId))
eip = hex(ctx.Eip).rstrip('L')
if jmpTable.has_key(eip):
ctx.Eip = int(jmpTable[eip], 16)
pydbg.set_thread_context(ctx, pydbg.open_thread(pydbg.dbg.dwThreadId))
return DBG_CONTINUE


That's it, that's all. As you can see it is quite easy to use pefile, pydasm and pydbg in order to implement some POC or help while reverse engineering softwares.

To conclude, two links (hurry up to get the French one before such content become illegal in France...):

No comments:

Post a Comment