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...):

2009-06-09

pyNanomites - part2 : Building the protected binary

Now that we saw how the Nanomites protection is working (at least for a basic implementation), I will explain how to code a simple implementation using pefile and pydasm.

First things first: what are pefile and pydasm? Well... they are python libraries! I bet you wouldn't have find it ;) More seriously, pefile is a library allowing to easily work on PE (Portable Executable) files. pydasm is a python interface to libdasm which allows to get the assembly out of binary data.

The first step is to parse the code section of the binary in order to find the jxx instructions (for the simplicity of this POC, only jmp instructions will be replaced). The sections will be enumerated until the one named .text (the code section) is found. This will be done with the sections list generated by pefile when opening a PE file:

pe = pefile.PE(os.sys.argv[1])
for section in pe.sections:
...

To calculate an instruction address, the virtual address of the code section should be added to the image base value and the offset of the instruction. Once a jmp instruction is found, the destination address is retrieved from the instruction and put in the database. This will result in the following code:

for section in pe.sections:
if section.Name.find(".text") != -1:
start = section.VirtualAddress
data = pe.get_memory_mapped_image()[start:start + section.SizeOfRawData]

offset = 0
while offset < len(data):
instr = pydasm.get_instruction(data[offset:], pydasm.MODE_32)
str = pydasm.get_instruction_string(instr, pydasm.FORMAT_INTEL,
start + pe.OPTIONAL_HEADER.ImageBase + offset)
dst = getJmpDest(str)
if len(dst) != 0:
table_jmp[start + pe.OPTIONAL_HEADER.ImageBase + offset] = dst
offset += instr.length


The last part is to change the jmp instructions with int3 instructions. This is simply done by writing 0xCCCC at the instruction's offset using the set_word_at_rva() function from pefile:

for k in table_jmp.keys():
pe.set_word_at_rva(k - pe.OPTIONAL_HEADER.ImageBase, 0xCCCC)
pe.write(os.sys.argv[2])

As this is a simple POC, the table will be written to a text file:

f = open(filename, 'w')
for i in table.keys():
f.write(hex(i))
f.write(" %s\n" % (table[i]))
f.close()

In the last post of this series, we are going to implement the parent process using pydbg.

pyNanomites - part1 : The Nanomites

For the first series of posts, I will be talking about the Nanomites protection used by Armadillo and how to recreate this protection using python.

I will only make a quick explanation and let you read the blog post on ring3circus. Armadillo is using the Debug Blocker technique in order to restraint a debugger to attach. When the protected binary is launched, a second process is created and will attach on the first process. As only one debugger at a time is allowed to debug a process, any other debugger will fail to attach.

Okay... this is not really efficient because you will answer that you just have to detach the debugger and attach your own. I totally agree and so do Armadillo's developers. This is why they invented the Nanomites. The idea is to benefit from the fact that one of the process is attached to the protected one as a debugger and use some functionalities brought by this.

When the binary is passed to Armadillo to protect it, all the jump instructions in user-marked parts of the code section will be replaced by the int3 instruction (user-land breakpoint interrupt) and a database containing the type and address of each jump is created. This database is encrypted several time and protected by multiple anti-reversing protections.

During the process execution, each breakpoint interruption will be catched by the parent process as it is attached as a debugger. The child process' context will be analyzed and the execution flow will by redirected to the corresponding destination address.

I will stop this quick description here and let you read the full description and an explanation on how to bypass it on ring3circus. Next time we will see how to generate the protected binary (ie. replacing jxx by int3) using pefile and pydasm.

2009-06-08

__start

Hi,

This message is the first on this blog and I hope that it will not be the last.

The idea behind this blog opening is to speak about reverse engineering, programming and computer security.

Well... let's start this new journey into the web2.0