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.

No comments:

Post a Comment