From 39c7f0fb1d246a35c41583d87dcc2127fb8addc8 Mon Sep 17 00:00:00 2001 From: Michal Malik Date: Tue, 22 Dec 2015 11:29:55 +0100 Subject: [PATCH 1/2] Add regress test for issue #334 https://github.com/unicorn-engine/unicorn/issues/334 The code is a bit different than in the issue, but it should demonstrate the main problem just fine. --- tests/regress/hook_code_add_del.py | 48 ++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tests/regress/hook_code_add_del.py diff --git a/tests/regress/hook_code_add_del.py b/tests/regress/hook_code_add_del.py new file mode 100644 index 00000000..8c589e87 --- /dev/null +++ b/tests/regress/hook_code_add_del.py @@ -0,0 +1,48 @@ +#!/usr/bin/python + +'''https://github.com/unicorn-engine/unicorn/issues/334''' + +from __future__ import print_function +import regress + +from unicorn import * +from unicorn.x86_const import * + +ADDRESS = 0x8048000 +STACK_ADDRESS = 0xffff000 +STACK_SIZE = 4096 +''' +31 DB xor ebx, ebx +53 push ebx +43 inc ebx +53 push ebx +6A 02 push 2 +6A 66 push 66h +58 pop eax +89 E1 mov ecx, esp +CD 80 int 80h +''' +CODE = "\x31\xDB\x53\x43\x53\x6A\x02\x6A\x66\x58\x89\xE1\xCD\x80" +EP = ADDRESS + 0x54 + +def hook_code(mu, address, size, user_data): + print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) + +class HookCodeAddDelTest(regress.RegressTest): + def runTest(self): + emu = Uc(UC_ARCH_X86, UC_MODE_32) + emu.mem_map(ADDRESS, 0x1000) + emu.mem_write(EP, CODE) + + emu.mem_map(STACK_ADDRESS, STACK_SIZE) + emu.reg_write(UC_X86_REG_ESP, STACK_ADDRESS + STACK_SIZE) + + # UC_HOOK_CODE hook will work even after deletion + emu.hook_add(UC_HOOK_CODE, hook_code, None) + emu.hook_del(UC_HOOK_CODE) + + emu.emu_start(EP, EP + len(CODE), count = 3) + print("EIP: 0x%x" % emu.reg_read(UC_X86_REG_EIP)) + +if __name__ == '__main__': + regress.main() From 784b8066e204d05564446278c3fb73f4ae426871 Mon Sep 17 00:00:00 2001 From: farmdve Date: Tue, 22 Dec 2015 12:33:36 +0200 Subject: [PATCH 2/2] Add test for pre-instruction hook being called more times. --- .gitignore | 1 + tests/regress/Makefile | 1 + tests/regress/hook_extrainvoke.c | 94 ++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 tests/regress/hook_extrainvoke.c diff --git a/.gitignore b/.gitignore index e8723101..3952c8e5 100644 --- a/.gitignore +++ b/.gitignore @@ -128,6 +128,7 @@ mips_branch_likely_issue test_mem_map_ptr test_mem_high rw_hookstack +hook_extrainvoke ################# diff --git a/tests/regress/Makefile b/tests/regress/Makefile index e5bde71f..8bb1d844 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -34,6 +34,7 @@ TESTS += rw_hookstack TESTS += threaded_emu_start TESTS += emu_stop_in_hook_overrun TESTS += mips_branch_likely_issue +TESTS += hook_extrainvoke all: $(TESTS) diff --git a/tests/regress/hook_extrainvoke.c b/tests/regress/hook_extrainvoke.c new file mode 100644 index 00000000..5f74e4d7 --- /dev/null +++ b/tests/regress/hook_extrainvoke.c @@ -0,0 +1,94 @@ +#include +#include +#include + +#include + +#define X86_CODE32 "\xf3\xab" // rep stosd dword ptr es:[edi], eax -> Fill (E)CX doublewords at ES:[(E)DI] with EAX +#define ADDRESS 0x1000000 +#define ECX_OPS 2 +static long unsigned int hook_called = 0; + +void hook_ins(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + hook_called++; + printf("hook called\n"); +} + +static void VM_exec() +{ + uc_engine *uc; + uc_err err; + uc_hook trace; + unsigned int r_eax, eflags, r_esp, r_edi, r_ecx; + + r_eax = 0xbaadbabe; + r_esp = ADDRESS+0x20; + r_edi = ADDRESS+0x300; //some safe distance from main code. + eflags = 0x00000206; + r_ecx = ECX_OPS; + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + if(err) + { + printf("Failed on uc_open() with error returned: %s\n", uc_strerror(err)); + return; + } + + err = uc_mem_map(uc, ADDRESS, (2 * 1024 * 1024), UC_PROT_ALL); + if(err != UC_ERR_OK) + { + printf("Failed to map memory %s\n", uc_strerror(err)); + return; + } + + // write machine code to be emulated to memory + err = uc_mem_write(uc, ADDRESS, X86_CODE32, sizeof(X86_CODE32) - 1); + if(err != UC_ERR_OK) + { + printf("Failed to write emulation code to memory, quit!: %s(len %lu)\n", uc_strerror(err), (unsigned long)sizeof(X86_CODE32) - 1); + return; + } + + // initialize machine registers + uc_reg_write(uc, UC_X86_REG_EAX, &r_eax); + uc_reg_write(uc, UC_X86_REG_EDI, &r_edi); + uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_write(uc, UC_X86_REG_ESP, &r_esp); //make stack pointer point to already mapped memory so we don't need to hook. + uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); + + uc_hook_add(uc, &trace, UC_HOOK_CODE, (void *)hook_ins, NULL, (uint64_t)1, (uint64_t)0); + + // emulate machine code in infinite time + err = uc_emu_start(uc, ADDRESS, ADDRESS + (sizeof(X86_CODE32) - 1), 0, 0); + if(err) + { + printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); + + uc_close(uc); + return; + } + + uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); + uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_read(uc, UC_X86_REG_EDI, &r_edi); + uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags); + + uc_close(uc); + + printf("\n>>> Emulation done. Below is the CPU context\n"); + printf(">>> EAX = 0x%08X\n", r_eax); + printf(">>> ECX = 0x%08X\n", r_ecx); + printf(">>> EDI = 0x%08X\n", r_edi); + printf(">>> EFLAGS = 0x%08X\n", eflags); + + printf("\nHook called %lu times. Test %s\n", hook_called, (hook_called == ECX_OPS ? "PASSED!!" : "FAILED!!!")); + +} + +int main(int argc, char *argv[]) +{ + VM_exec(); + return 0; +}