pmeerw's blog

Sat, 04 May 2019

Rewriting Windows binary with Python's pefile

Using Python module pefile to rewrite a Windows PE/PE+ file (I think both 32-bit and 64-bit are supported, tested 64-bit only). The goal is to append a new section, change the executable's entry point to the new section, jump back to the original entry point (OEP).

#!/usr/env python3

import pefile

def adjust_SectionSize(sz, align):
  if sz % align: sz = ((sz + align) // align) * align
  return sz

pe = pefile.PE('../hello.exe')

last_section = pe.sections[-1]

new_section = pefile.SectionStructure(pe.__IMAGE_SECTION_HEADER_format__)

# fill with zeros
new_section.__unpack__(bytearray(new_section.sizeof()))

# place section header after last section header (assume there is enough room)
new_section.set_file_offset(last_section.get_file_offset() + last_section.sizeof())

new_section.Name = b'.test'
new_section_size = 100

new_section.SizeOfRawData = adjust_SectionSize(new_section_size, pe.OPTIONAL_HEADER.FileAlignment)
new_section.PointerToRawData = len(pe.__data__)

new_section.Misc = new_section.Misc_PhysicalAddress = new_section.Misc_VirtualSize = new_section_size
new_section.VirtualAddress = last_section.VirtualAddress + adjust_SectionSize(last_section.Misc_VirtualSize, pe.OPTIONAL_HEADER.SectionAlignment)

new_section.Characteristics = 0x40000000 | 0x20000000 | 0x20 # read | execute | code

# create new section data containing jump to OEP
reljmp = pe.OPTIONAL_HEADER.AddressOfEntryPoint - (new_section.VirtualAddress + 5)
print('rel jmp %08x' % (reljmp))
new_section_data = bytearray(new_section.SizeOfRawData)
new_section_data[0] = 0xe9
new_section_data[1:4] = reljmp.to_bytes(4, byteorder='little', signed=True)

# change address of entry point to beginning of new section
pe.OPTIONAL_HEADER.AddressOfEntryPoint = new_section.VirtualAddress

# increase size of image
pe.OPTIONAL_HEADER.SizeOfImage += adjust_SectionSize(new_section_size, pe.OPTIONAL_HEADER.SectionAlignment)

# increase number of sections
pe.FILE_HEADER.NumberOfSections += 1

# append new section to structures
pe.sections.append(new_section)
pe.__structures__.append(new_section)

# add new section data to file
pe.__data__ = bytearray(pe.__data__) + new_section_data

pe.write('../hello_patched.exe')

posted at: 10:33 | path: /programming | permanent link

Made with PyBlosxom