ESP trick is an old way to defeat some packer, this procedure is really simple: first look for a PUSHAD near the entrypoint, step over the PUSHAD, follow ESP into memory and then set an hardware breakpoint on access to this location. Wait for a POPAD which accesses this location and then look for a near JMP.
How to do this within a debugger is quite obvious but this time we want achieve this objective in a different way, we wanna use PyEmu.
Ok warm-up ended… let’s code…
Step 1, define our PUSHAD instruction handler:
def pushad_instruction_handler(emu, instruction, eip, op1, op2, op3):
#get and save ESP
global _esp_
_esp_ = emu.get_register("ESP") - 4
#set our memory handler
emu.set_memory_access_handler(memory_access_handler)
return True
Step 2, define our memory access handler:
def memory_access_handler(emu, address, value, size, type):
global _esp_
if address == _esp_ and type == "read":
#set JMP handler
emu.set_opcode_handler(0xE9, jmp_instruction_handler)
return True
Step 3, define our JMP instruction handler:
def jmp_instruction_handler(emu, instruction, address, op1, op2, op3):
#stop emulation
emu.emulating = False
#print OEP
raw_input("[*] OEP: 0x%08x" % address)
return True
Step 4, put all together:
_esp_ = None
def pushad_instruction_handler(emu, instruction, eip, op1, op2, op3):
#get and save ESP
global _esp_
_esp_ = emu.get_register("ESP") - 4
#set our memory handler
emu.set_memory_access_handler(memory_access_handler)
return True
def memory_access_handler(emu, address, value, size, type):
global _esp_
if address == _esp_ and type == "read":
#set JMP handler
emu.set_opcode_handler(0xE9, jmp_instruction_handler)
return True
def jmp_instruction_handler(emu, instruction, address, op1, op2, op3):
#stop emulation
emu.emulating = False
#print OEP
raw_input("[*] OEP: 0x%08x" % address)
return True
emu = PEPyEmu()
if not emu.load(EXE_TO_UNPACK):
print "[!] unable to load target exe: %s" % EXE_TO_UNPACK
else:
#library
emu.set_library_handler("LoadLibraryA", LoadLibrary)
emu.set_library_handler("GetProcAddress", GetProcAddress)
emu.set_library_handler("VirtualProtect", VirtualProtect)
#opcode
emu.set_opcode_handler(0x60, pushad_instruction_handler)
#misc
emu.execute(start=emu.entry_point, end=-1)
This program has been tested versus an UPX packed exe, so maybe that with a different packer it will not work fine. Full source code is available here.
I hope you enjoyed this little trip into PyEmu… see you next post 8)