diff --git a/bindings/python/sample_x86.py b/bindings/python/sample_x86.py index 7010327f..e213a774 100755 --- a/bindings/python/sample_x86.py +++ b/bindings/python/sample_x86.py @@ -308,6 +308,56 @@ def test_i386_inout(): print("ERROR: %s" % e) +def test_i386_reg_save(): + print("Save/restore registers in opaque blob") + address = 0 + code = '\x40' # inc eax + try: + # Initialize emulator + mu = Uc(UC_ARCH_X86, UC_MODE_32) + + # map 8KB memory for this emulation + mu.mem_map(address, 8 * 1024, UC_PROT_ALL) + + # write machine code to be emulated to memory + mu.mem_write(address, code) + + print(">>> set eax to 1") + mu.reg_write(UC_X86_REG_EAX, 1) + + print(">>> execute 'inc eax'") + mu.emu_start(address, address+1) + + print(">>> save the register state") + saved_regs = mu.save_regs() + + print(">>> execute 'inc eax'") + mu.emu_start(address, address+1) + + print(">>> assert eax == 3") + assert mu.reg_read(UC_X86_REG_EAX) == 3 + + print(">>> restore the register state") + mu.restore_regs(saved_regs) + + print(">>> assert eax == 2") + assert mu.reg_read(UC_X86_REG_EAX) == 2 + + print(">>> execute 'inc eax'") + mu.emu_start(address, address+1) + + print(">>> assert eax == 3") + assert mu.reg_read(UC_X86_REG_EAX) == 3 + + print(">>> restore the register state") + mu.restore_regs(saved_regs) + + print(">>> assert eax == 2") + assert mu.reg_read(UC_X86_REG_EAX) == 2 + + except UcError as e: + print("ERROR: %s" % e) + def test_x86_64(): print("Emulate x86_64 code") try: @@ -479,6 +529,8 @@ if __name__ == '__main__': print("=" * 20) test_i386_inout() print("=" * 20) + test_i386_reg_save() + print("=" * 20) test_x86_64() print("=" * 20) test_x86_64_syscall() diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index a1083f70..cf541e9c 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -127,6 +127,9 @@ _setup_prototype(_uc, "uc_mem_map_ptr", ucerr, uc_engine, ctypes.c_uint64, ctype _setup_prototype(_uc, "uc_mem_unmap", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t) _setup_prototype(_uc, "uc_mem_protect", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32) _setup_prototype(_uc, "uc_query", ucerr, uc_engine, ctypes.c_uint32, ctypes.POINTER(ctypes.c_size_t)) +_setup_prototype(_uc, "uc_save_regstate", ctypes.c_voidp, uc_engine, ctypes.c_voidp) +_setup_prototype(_uc, "uc_restore_regstate", None, uc_engine, ctypes.c_voidp) +_setup_prototype(_uc, "free", None, ctypes.c_voidp) # uc_hook_add is special due to variable number of arguments _uc.uc_hook_add = _uc.uc_hook_add @@ -449,6 +452,27 @@ class Uc(object): raise UcError(status) h = 0 + def save_regs(self, store=None): + if store is None: + ptr = ctypes.cast(0, ctypes.c_voidp) + return _ActivePointer(_uc.uc_save_regstate(self._uch, ptr)) + elif type(store) is _ActivePointer: + _uc.uc_save_regstate(self._uch, store.pointer) + return store + else: + raise TypeError("Bad register store %s" % repr(store)) + + def restore_regs(self, store): + if type(store) is not _ActivePointer: + raise TYpeError("Bad register store %s" % repr(store)) + _uc.uc_restore_regstate(self._uch, store.pointer) + +class _ActivePointer(object): + def __init__(self, pointer): + self.pointer = pointer + + def __del__(self): + _uc.free(self.pointer) # print out debugging info def debug():