Showing posts with label anti-reversing. Show all posts
Showing posts with label anti-reversing. Show all posts

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.