#!/usr/bin/python from __future__ import print_function import binascii import regress from unicorn import * from unicorn.x86_const import * CODE = binascii.unhexlify(b"".join([ b"8B 74 01 28", # mov esi, dword ptr [ecx + eax + 0x28] mapped: 0x1000 b"03 F0", # add esi, eax 0x1004 b"8D 45 FC", # lea eax, dword ptr [ebp - 4] 0x1006 b"50", # push eax 0x1009 b"6A 40", # push 0x40 0x100A b"6A 10", # push 0x10 0x100C b"56", # push esi 0x100E b"FF 15 20 20 00 10" # call some address 0x100F ]).replace(" ", "")) def showpc(mu): pc = mu.reg_read(UC_X86_REG_EIP) print("pc: 0x%x" % (pc)) class HookCodeStopEmuTest(regress.RegressTest): def test_hook_code_stop_emu(self): mu = Uc(UC_ARCH_X86, UC_MODE_32) # base of CODE mu.mem_map(0x1000, 0x1000) mu.mem_write(0x1000, CODE) mu.reg_write(UC_X86_REG_EIP, 0x1000) # base of STACK mu.mem_map(0x4000, 0x4000) mu.mem_write(0x4000, "\x00" * 0x4000) mu.reg_write(UC_X86_REG_ESP, 0x6000) mu.reg_write(UC_X86_REG_EBP, 0x6000) mu.reg_write(UC_X86_REG_ECX, 0x0) mu.reg_write(UC_X86_REG_EAX, 0x0) def _hook(_, access, address, length, value, context): pc = mu.reg_read(UC_X86_REG_EIP) print("mem unmapped: pc: %x access: %x address: %x length: %x value: %x" % ( pc, access, address, length, value)) mu.emu_stop() return True mu.hook_add(UC_HOOK_MEM_UNMAPPED, _hook) # we only expect the following instruction to execute, # and it will fail, because it accesses unmapped memory. # mov esi, dword ptr [ecx + eax + 0x28] mapped: 0x1000 mu.emu_start(0x1000, 0x100F) showpc(mu) # now, we want to reuse the emulator, and keep executing # from the next instruction mu.reg_write(UC_X86_REG_EIP, 0x1004) self.assertEqual(0x1004, mu.reg_read(UC_X86_REG_EIP)) # we expect the following instructions to execute # add esi, eax 0x1004 # lea eax, dword ptr [ebp - 4] 0x1006 # push eax 0x1009 # push 0x40 0x100A # push 0x10 0x100C # push esi 0x100E # # currently, a UC_ERR_READ_UNMAPPED exception is raised here mu.emu_start(0x1004, 0x100F) showpc(mu) if __name__ == '__main__': regress.main()