From a7a1dcc66128801d1ef82e992a6cc4ff10fcce5d Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 11 Feb 2016 08:02:13 +0800 Subject: [PATCH 01/41] uc_hook_add(): add begin & end arguments for all hook types. also update Python binding after this change --- bindings/python/sample_x86.py | 6 ++-- bindings/python/shellcode.py | 2 +- bindings/python/unicorn/unicorn.py | 14 ++++------ include/unicorn/unicorn.h | 8 +++++- samples/mem_apis.c | 12 ++++---- samples/sample_arm.c | 8 +++--- samples/sample_arm64.c | 4 +-- samples/sample_m68k.c | 4 +-- samples/sample_mips.c | 8 +++--- samples/sample_sparc.c | 4 +-- samples/sample_x86.c | 44 +++++++++++++++--------------- samples/shellcode.c | 2 +- tests/unit/test_mem_high.c | 2 +- tests/unit/test_multihook.c | 4 +-- tests/unit/test_pc_change.c | 2 +- tests/unit/test_tb_x86.c | 8 +++--- tests/unit/test_x86.c | 28 +++++++++---------- uc.c | 26 ++++++++++-------- 18 files changed, 96 insertions(+), 90 deletions(-) diff --git a/bindings/python/sample_x86.py b/bindings/python/sample_x86.py index b470f4ce..32947a3c 100755 --- a/bindings/python/sample_x86.py +++ b/bindings/python/sample_x86.py @@ -291,8 +291,8 @@ def test_i386_inout(): mu.hook_add(UC_HOOK_CODE, hook_code) # handle IN & OUT instruction - mu.hook_add(UC_HOOK_INSN, hook_in, None, UC_X86_INS_IN) - mu.hook_add(UC_HOOK_INSN, hook_out, None, UC_X86_INS_OUT) + mu.hook_add(UC_HOOK_INSN, hook_in, None, 1, 0, UC_X86_INS_IN) + mu.hook_add(UC_HOOK_INSN, hook_out, None, 1, 0, UC_X86_INS_OUT) # emulate machine code in infinite time mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_INOUT)) @@ -417,7 +417,7 @@ def test_x86_64_syscall(): print('ERROR: was not expecting rax=%d in syscall' % rax) # hook interrupts for syscall - mu.hook_add(UC_HOOK_INSN, hook_syscall, None, UC_X86_INS_SYSCALL) + mu.hook_add(UC_HOOK_INSN, hook_syscall, None, 1, 0, UC_X86_INS_SYSCALL) # syscall handler is expecting rax=0x100 mu.reg_write(UC_X86_REG_RAX, 0x100) diff --git a/bindings/python/shellcode.py b/bindings/python/shellcode.py index a4a473b0..898ada7b 100755 --- a/bindings/python/shellcode.py +++ b/bindings/python/shellcode.py @@ -97,7 +97,7 @@ def test_i386(mode, code): mu.hook_add(UC_HOOK_INTR, hook_intr) # handle SYSCALL - mu.hook_add(UC_HOOK_INSN, hook_syscall, None, UC_X86_INS_SYSCALL) + mu.hook_add(UC_HOOK_INSN, hook_syscall, None, 1, 0, UC_X86_INS_SYSCALL) # emulate machine code in infinite time mu.emu_start(ADDRESS, ADDRESS + len(code)) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 476ac552..3d784368 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -315,7 +315,7 @@ class Uc(object): # add a hook - def hook_add(self, htype, callback, user_data=None, arg1=1, arg2=0): + def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0): _h2 = uc_hook_h() # save callback & user_data @@ -332,30 +332,28 @@ class Uc(object): if arg1 in (x86_const.UC_X86_INS_SYSCALL, x86_const.UC_X86_INS_SYSENTER): # SYSCALL/SYSENTER instruction cb = ctypes.cast(UC_HOOK_INSN_SYSCALL_CB(self._hook_insn_syscall_cb), UC_HOOK_INSN_SYSCALL_CB) status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ - cb, ctypes.cast(self._callback_count, ctypes.c_void_p), insn) + cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end), insn) elif htype == UC_HOOK_INTR: cb = ctypes.cast(UC_HOOK_INTR_CB(self._hook_intr_cb), UC_HOOK_INTR_CB) status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ - cb, ctypes.cast(self._callback_count, ctypes.c_void_p)) + cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end)) else: - begin = ctypes.c_uint64(arg1) - end = ctypes.c_uint64(arg2) if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE): # set callback with wrapper, so it can be called # with this object as param cb = ctypes.cast(UC_HOOK_CODE_CB(self._hookcode_cb), UC_HOOK_CODE_CB) status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, cb, \ - ctypes.cast(self._callback_count, ctypes.c_void_p), begin, end) + ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end)) elif htype & UC_HOOK_MEM_READ_UNMAPPED or htype & UC_HOOK_MEM_WRITE_UNMAPPED or \ htype & UC_HOOK_MEM_FETCH_UNMAPPED or htype & UC_HOOK_MEM_READ_PROT or \ htype & UC_HOOK_MEM_WRITE_PROT or htype & UC_HOOK_MEM_FETCH_PROT: cb = ctypes.cast(UC_HOOK_MEM_INVALID_CB(self._hook_mem_invalid_cb), UC_HOOK_MEM_INVALID_CB) status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ - cb, ctypes.cast(self._callback_count, ctypes.c_void_p)) + cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end)) else: cb = ctypes.cast(UC_HOOK_MEM_ACCESS_CB(self._hook_mem_access_cb), UC_HOOK_MEM_ACCESS_CB) status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ - cb, ctypes.cast(self._callback_count, ctypes.c_void_p)) + cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end)) # save the ctype function so gc will leave it alone. self._ctype_cbs[self._callback_count] = cb diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 2a556841..bf26b741 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -458,13 +458,19 @@ uc_err uc_emu_stop(uc_engine *uc); @callback: callback to be run when instruction is hit @user_data: user-defined data. This will be passed to callback function in its last argument @user_data + @begin: start address of the area where the callback is effect (inclusive) + @begin: end address of the area where the callback is effect (inclusive) + NOTE 1: the callback is called only if related address is in range [@begin, @end] + NOTE 2: if @begin > @end, callback is called whenever this hook type is triggered @...: variable arguments (depending on @type) + NOTE: if @type = UC_HOOK_INSN, this is the instruction ID (ex: UC_X86_INS_OUT) @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum for detailed error). */ UNICORN_EXPORT -uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...); +uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, + void *user_data, uint64_t begin, uint64_t end, ...); /* Unregister (remove) a hook callback. diff --git a/samples/mem_apis.c b/samples/mem_apis.c index 008f077d..dc1c2481 100644 --- a/samples/mem_apis.c +++ b/samples/mem_apis.c @@ -168,9 +168,9 @@ static void do_nx_demo(bool cause_fault) } // intercept code and invalid memory events - if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK || + if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK || uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, - hook_mem_invalid, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) { printf("not ok - Failed to install hooks\n"); return; } @@ -248,10 +248,10 @@ static void do_perms_demo(bool change_perms) } // intercept code and invalid memory events - if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK || + if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK || uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, - hook_mem_invalid, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) { printf("not ok - Failed to install hooks\n"); return; } @@ -326,10 +326,10 @@ static void do_unmap_demo(bool do_unmap) } // intercept code and invalid memory events - if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK || + if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK || uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, - hook_mem_invalid, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) { printf("not ok - Failed to install hooks\n"); return; } diff --git a/samples/sample_arm.c b/samples/sample_arm.c index 8a5067db..2c69ce6a 100644 --- a/samples/sample_arm.c +++ b/samples/sample_arm.c @@ -77,10 +77,10 @@ static void test_arm(void) uc_reg_write(uc, UC_ARM_REG_R3, &r3); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. @@ -128,10 +128,10 @@ static void test_thumb(void) uc_reg_write(uc, UC_ARM_REG_SP, &sp); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. diff --git a/samples/sample_arm64.c b/samples/sample_arm64.c index 39d500aa..785708d0 100644 --- a/samples/sample_arm64.c +++ b/samples/sample_arm64.c @@ -75,10 +75,10 @@ static void test_arm64(void) uc_reg_write(uc, UC_ARM64_REG_X15, &x15); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. diff --git a/samples/sample_m68k.c b/samples/sample_m68k.c index efda5294..4bbf1cce 100644 --- a/samples/sample_m68k.c +++ b/samples/sample_m68k.c @@ -108,10 +108,10 @@ static void test_m68k(void) uc_reg_write(uc, UC_M68K_REG_SR, &sr); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instruction - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. diff --git a/samples/sample_mips.c b/samples/sample_mips.c index b27a02b1..994047c2 100644 --- a/samples/sample_mips.c +++ b/samples/sample_mips.c @@ -72,10 +72,10 @@ static void test_mips_eb(void) uc_reg_write(uc, UC_MIPS_REG_1, &r1); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. @@ -122,10 +122,10 @@ static void test_mips_el(void) uc_reg_write(uc, UC_MIPS_REG_1, &r1); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index e6276b14..649a6dec 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -76,10 +76,10 @@ static void test_sparc(void) uc_reg_write(uc, UC_SPARC_REG_G3, &g3); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instructions with customized callback - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. diff --git a/samples/sample_x86.c b/samples/sample_x86.c index c57043d2..264015f2 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -219,10 +219,10 @@ static void test_i386(void) uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instruction by having @begin > @end - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0); @@ -289,10 +289,10 @@ static void test_i386_map_ptr(void) uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instruction by having @begin > @end - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0); @@ -345,10 +345,10 @@ static void test_i386_jump(void) } // tracing 1 basic block with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, ADDRESS, ADDRESS); // tracing 1 instruction at ADDRESS - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_JUMP) - 1, 0, 0); @@ -447,10 +447,10 @@ static void test_i386_invalid_mem_read(void) uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instruction by having @begin > @end - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_READ) - 1, 0, 0); @@ -505,13 +505,13 @@ static void test_i386_invalid_mem_write(void) uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instruction by having @begin > @end - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // intercept invalid memory events - uc_hook_add(uc, &trace3, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace3, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_WRITE) - 1, 0, 0); @@ -576,10 +576,10 @@ static void test_i386_jump_invalid(void) uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instructions by having @begin > @end - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_JMP_INVALID) - 1, 0, 0); @@ -632,15 +632,15 @@ static void test_i386_inout(void) uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instructions - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // uc IN instruction - uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, UC_X86_INS_IN); + uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, 1, 0, UC_X86_INS_IN); // uc OUT instruction - uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, UC_X86_INS_OUT); + uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, 1, 0, UC_X86_INS_OUT); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INOUT) - 1, 0, 0); @@ -721,16 +721,16 @@ static void test_x86_64(void) uc_reg_write(uc, UC_X86_REG_R15, &r15); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instructions in the range [ADDRESS, ADDRESS+20] - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, (uint64_t)ADDRESS, (uint64_t)(ADDRESS+20)); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, ADDRESS, ADDRESS+20); // tracing all memory WRITE access (with @begin > @end) - uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, 1, 0); // tracing all memory READ access (with @begin > @end) - uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, 1, 0); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. @@ -804,7 +804,7 @@ static void test_x86_64_syscall(void) } // hook interrupts for syscall - uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, UC_X86_INS_SYSCALL); + uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, 1, 0, UC_X86_INS_SYSCALL); // initialize machine registers uc_reg_write(uc, UC_X86_REG_RAX, &rax); diff --git a/samples/shellcode.c b/samples/shellcode.c index a6fd5221..8ad0c69b 100644 --- a/samples/shellcode.c +++ b/samples/shellcode.c @@ -138,7 +138,7 @@ static void test_i386(void) uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code, NULL, 1, 0); // handle interrupt ourself - uc_hook_add(uc, &trace2, UC_HOOK_INTR, hook_intr, NULL); + uc_hook_add(uc, &trace2, UC_HOOK_INTR, hook_intr, NULL, 1, 0); printf("\n>>> Start tracing this Linux code\n"); diff --git a/tests/unit/test_mem_high.c b/tests/unit/test_mem_high.c index 5e2244e5..c8e58288 100644 --- a/tests/unit/test_mem_high.c +++ b/tests/unit/test_mem_high.c @@ -79,7 +79,7 @@ static void test_high_address_reads(void **state) uint8_t code[] = {0x48,0x8b,0x00,0x90,0x90,0x90,0x90}; // mov rax, [rax], nops uc_assert_success(uc_mem_map(uc, base_addr, 4096, UC_PROT_ALL)); uc_assert_success(uc_mem_write(uc, base_addr, code, 7)); - uc_assert_success(uc_hook_add(uc, &trace2, UC_HOOK_MEM_READ, hook_mem64, NULL, (uint64_t)1, (uint64_t)0)); + uc_assert_success(uc_hook_add(uc, &trace2, UC_HOOK_MEM_READ, hook_mem64, NULL, 1, 0)); uc_assert_success(uc_emu_start(uc, base_addr, base_addr + 3, 0, 0)); if(number_of_memory_reads != 1) { fail_msg("wrong number of memory reads for instruction %i", number_of_memory_reads); diff --git a/tests/unit/test_multihook.c b/tests/unit/test_multihook.c index eb831865..c131481d 100644 --- a/tests/unit/test_multihook.c +++ b/tests/unit/test_multihook.c @@ -96,8 +96,8 @@ static void test_basic_blocks(void **state) OK(uc_mem_write(uc, address, code, sizeof(code))); // trace all basic blocks - OK(uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, test_basic_blocks_hook, &bbtest, (uint64_t)1, (uint64_t)0)); - OK(uc_hook_add(uc, &trace2, UC_HOOK_BLOCK, test_basic_blocks_hook2, &bbtest, (uint64_t)1, (uint64_t)0)); + OK(uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, test_basic_blocks_hook, &bbtest, 1, 0)); + OK(uc_hook_add(uc, &trace2, UC_HOOK_BLOCK, test_basic_blocks_hook2, &bbtest, 1, 0)); OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0)); } diff --git a/tests/unit/test_pc_change.c b/tests/unit/test_pc_change.c index 7994e772..c2ec73a8 100644 --- a/tests/unit/test_pc_change.c +++ b/tests/unit/test_pc_change.c @@ -83,7 +83,7 @@ static void test_pc_change(void **state) printf("ECX = %u, EDX = %u\n", r_ecx, r_edx); // trace all instructions - OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, test_code_hook, NULL, (uint64_t)1, (uint64_t)0)); + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, test_code_hook, NULL, 1, 0)); OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0)); diff --git a/tests/unit/test_tb_x86.c b/tests/unit/test_tb_x86.c index bf691e8b..1d6ba7a0 100644 --- a/tests/unit/test_tb_x86.c +++ b/tests/unit/test_tb_x86.c @@ -273,16 +273,16 @@ static void test_tb_x86_64_32_imul_Gv_Ev_Ib(void **state) UC_HOOK_CODE, hook_code32, NULL, - (uint64_t)1, - (uint64_t)0)); + 1, + 0)); uc_assert_success(uc_hook_add(uc, &trace2, UC_HOOK_MEM_VALID, hook_mem32, NULL, - (uint64_t)1, - (uint64_t)0)); + 1, + 0)); uc_assert_success(uc_emu_start(uc, #ifdef RIP_NEXT_TO_THE_SELFMODIFY_OPCODE diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index 04441123..348cd5cd 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -85,7 +85,7 @@ static void test_basic_blocks(void **state) OK(uc_mem_write(uc, address, code, sizeof(code))); // trace all basic blocks - OK(uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, test_basic_blocks_hook, &bbtest, (uint64_t)1, (uint64_t)0)); + OK(uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, test_basic_blocks_hook, &bbtest, 1, 0)); OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0)); } @@ -144,11 +144,11 @@ static void test_i386(void **state) uc_assert_success(err); // tracing all basic blocks with customized callback - err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); uc_assert_success(err); // tracing all instruction by having @begin > @end - err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); uc_assert_success(err); // emulate machine code in infinite time @@ -194,11 +194,11 @@ static void test_i386_jump(void **state) uc_assert_success(err); // tracing 1 basic block with customized callback - err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)address, (uint64_t)address); + err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, address, address); uc_assert_success(err); // tracing 1 instruction at address - err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)address, (uint64_t)address); + err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, address, address); uc_assert_success(err); // emulate machine code in infinite time @@ -302,19 +302,19 @@ static void test_i386_inout(void **state) uc_assert_success(err); // tracing all basic blocks with customized callback - err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); uc_assert_success(err); // tracing all instructions - err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); uc_assert_success(err); // uc IN instruction - err = uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, UC_X86_INS_IN); + err = uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, 1, 0, UC_X86_INS_IN); uc_assert_success(err); // uc OUT instruction - err = uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, UC_X86_INS_OUT); + err = uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, 1, 0, UC_X86_INS_OUT); uc_assert_success(err); // emulate machine code in infinite time @@ -566,19 +566,19 @@ static void test_x86_64(void **state) uc_assert_success(uc_reg_write(uc, UC_X86_REG_R15, &r15)); // tracing all basic blocks with customized callback - err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); uc_assert_success(err); // tracing all instructions in the range [address, address+20] - err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, (uint64_t)address, (uint64_t)(address+20)); + err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, address, address+20); uc_assert_success(err); // tracing all memory WRITE access (with @begin > @end) - err = uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, (uint64_t)1, (uint64_t)0); + err = uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, 1, 0); uc_assert_success(err); // tracing all memory READ access (with @begin > @end) - err = uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, (uint64_t)1, (uint64_t)0); + err = uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, 1, 0); uc_assert_success(err); // emulate machine code in infinite time (last param = 0), or when @@ -662,7 +662,7 @@ static void test_x86_64_syscall(void **state) uc_assert_success(err); // hook interrupts for syscall - err = uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, UC_X86_INS_SYSCALL); + err = uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, 1, 0, UC_X86_INS_SYSCALL); uc_assert_success(err); // initialize machine registers diff --git a/uc.c b/uc.c index ab466601..169da7b6 100644 --- a/uc.c +++ b/uc.c @@ -551,7 +551,7 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time } // set up count hook to count instructions. if (count > 0 && uc->count_hook == 0) { - uc_err err = uc_hook_add(uc, &uc->count_hook, UC_HOOK_CODE, hook_count_cb, NULL); + uc_err err = uc_hook_add(uc, &uc->count_hook, UC_HOOK_CODE, hook_count_cb, NULL, 1, 0); if (err != UC_ERR_OK) { return err; } @@ -565,6 +565,7 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time if (timeout) enable_emu_timer(uc, timeout * 1000); // microseconds -> nanoseconds + uc->pause_all_vcpus(uc); // emulation is done uc->emulation_done = true; @@ -963,17 +964,19 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) } UNICORN_EXPORT -uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...) +uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, + void *user_data, uint64_t begin, uint64_t end, ...) { - va_list valist; int ret = UC_ERR_OK; - - va_start(valist, user_data); + int i = 0; struct hook *hook = calloc(1, sizeof(struct hook)); if (hook == NULL) { return UC_ERR_NOMEM; } + + hook->begin = begin; + hook->end = end; hook->type = type; hook->callback = callback; hook->user_data = user_data; @@ -982,22 +985,21 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *u // everybody but HOOK_INSN gets begin/end, so exit early here. if (type & UC_HOOK_INSN) { + va_list valist; + + va_start(valist, end); hook->insn = va_arg(valist, int); - hook->begin = 1; - hook->end = 0; + va_end(valist); + if (list_append(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) { free(hook); return UC_ERR_NOMEM; } + hook->refs++; return UC_ERR_OK; } - hook->begin = va_arg(valist, uint64_t); - hook->end = va_arg(valist, uint64_t); - va_end(valist); - - int i = 0; while ((type >> i) > 0) { if ((type >> i) & 1) { // TODO: invalid hook error? From 0822c0af85c6623a4c905a3673c233c0ccfbf98a Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 11 Feb 2016 08:05:15 +0800 Subject: [PATCH 02/41] bump API version to 1.0 --- bindings/dotnet/UnicornManaged/Const/Common.fs | 4 ++-- bindings/go/unicorn/unicorn_const.go | 4 ++-- bindings/java/unicorn/UnicornConst.java | 4 ++-- bindings/python/unicorn/unicorn_const.py | 4 ++-- include/unicorn/unicorn.h | 4 ++-- pkgconfig.mk | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bindings/dotnet/UnicornManaged/Const/Common.fs b/bindings/dotnet/UnicornManaged/Const/Common.fs index 6f106a3e..0f42d3d7 100644 --- a/bindings/dotnet/UnicornManaged/Const/Common.fs +++ b/bindings/dotnet/UnicornManaged/Const/Common.fs @@ -6,9 +6,9 @@ open System [] module Common = + let UC_API_MAJOR = 1 - let UC_API_MAJOR = 0 - let UC_API_MINOR = 9 + let UC_API_MINOR = 0 let UC_SECOND_SCALE = 1000000 let UC_MILISECOND_SCALE = 1000 let UC_ARCH_ARM = 1 diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 8d634be9..1faff075 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -1,9 +1,9 @@ package unicorn // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [unicorn_const.go] const ( + API_MAJOR = 1 - API_MAJOR = 0 - API_MINOR = 9 + API_MINOR = 0 SECOND_SCALE = 1000000 MILISECOND_SCALE = 1000 ARCH_ARM = 1 diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index 0fe4f193..64b52236 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -3,9 +3,9 @@ package unicorn; public interface UnicornConst { + public static final int UC_API_MAJOR = 1; - public static final int UC_API_MAJOR = 0; - public static final int UC_API_MINOR = 9; + public static final int UC_API_MINOR = 0; public static final int UC_SECOND_SCALE = 1000000; public static final int UC_MILISECOND_SCALE = 1000; public static final int UC_ARCH_ARM = 1; diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index 4e942ef5..bdb8ed01 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -1,7 +1,7 @@ # For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [unicorn_const.py] +UC_API_MAJOR = 1 -UC_API_MAJOR = 0 -UC_API_MINOR = 9 +UC_API_MINOR = 0 UC_SECOND_SCALE = 1000000 UC_MILISECOND_SCALE = 1000 UC_ARCH_ARM = 1 diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index bf26b741..3762cecd 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -57,8 +57,8 @@ typedef size_t uc_hook; #endif // Unicorn API version -#define UC_API_MAJOR 0 -#define UC_API_MINOR 9 +#define UC_API_MAJOR 1 +#define UC_API_MINOR 0 /* Macro to create combined version which can be compared to diff --git a/pkgconfig.mk b/pkgconfig.mk index 125322eb..e4374b15 100644 --- a/pkgconfig.mk +++ b/pkgconfig.mk @@ -2,8 +2,8 @@ # To be used to generate unicorn.pc for pkg-config # version major & minor -PKG_MAJOR = 0 -PKG_MINOR = 9 +PKG_MAJOR = 1 +PKG_MINOR = 0 # version bugfix level. Example: PKG_EXTRA = 1 PKG_EXTRA = From 80b0356a86ce0a6bd2fca8563f5c6aa8cd048f00 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 11 Feb 2016 09:27:30 +0800 Subject: [PATCH 03/41] fix a comment in uc_hook_add() for UC_HOOK_INSN --- uc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uc.c b/uc.c index 169da7b6..d7492bae 100644 --- a/uc.c +++ b/uc.c @@ -983,7 +983,7 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, hook->refs = 0; *hh = (uc_hook)hook; - // everybody but HOOK_INSN gets begin/end, so exit early here. + // UC_HOOK_INSN has an extra argument for instruction ID if (type & UC_HOOK_INSN) { va_list valist; From 8bf1257ac756b21067b975c30a55b6b33b4d7973 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 17 Feb 2016 23:24:10 +0800 Subject: [PATCH 04/41] update CREDITS.TXT --- CREDITS.TXT | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CREDITS.TXT b/CREDITS.TXT index 049e9b56..695b73d5 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -55,3 +55,6 @@ Loi Anh Tuan Shaun Wheelhouse: Homebrew package Kamil Rytarowski: Pkgsrc package Zak Escano: MSVC binding +Chris Eagle: Java binding +Ryan Hileman: Go binding +Antonio Parata: .NET binding From de5a887ed299caa62bf040da130ec628a145ce39 Mon Sep 17 00:00:00 2001 From: emdel Date: Wed, 17 Feb 2016 13:56:20 -0800 Subject: [PATCH 05/41] testcase to set ZF and modify eflags --- tests/regress/jumping.py | 167 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 tests/regress/jumping.py diff --git a/tests/regress/jumping.py b/tests/regress/jumping.py new file mode 100644 index 00000000..39172a5a --- /dev/null +++ b/tests/regress/jumping.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python +# Mariano Graziano + +from unicorn import * +from unicorn.x86_const import * + +import regress + +#echo -ne "\x48\x31\xc0\x48\xb8\x04\x00\x00\x00\x00\x00\x00\x00\x48\x3d\x05\x00\x00\x00\x74\x05\xe9\x0f\x00\x00\x00\x48\xba\xbe\xba\x00\x00\x00\x00\x00\x00\xe9\x0f\x00\x00\x00\x48\xba\xca\xc0\x00\x00\x00\x00\x00\x00\xe9\x00\x00\x00\x00\x90" | ndisasm - -b64 +#00000000 4831C0 xor rax,rax +#00000003 48B8040000000000 mov rax,0x4 +# -0000 +#0000000D 483D05000000 cmp rax,0x5 +#00000013 7405 jz 0x1a +#00000015 E90F000000 jmp qword 0x29 +#0000001A 48BABEBA00000000 mov rdx,0xbabe +# -0000 +#00000024 E90F000000 jmp qword 0x38 +#00000029 48BACAC000000000 mov rdx,0xc0ca +# -0000 +#00000033 E900000000 jmp qword 0x38 +#00000038 90 nop + + +mu = 0 +zf = 1 # (0:clear, 1:set) + + +class Init(regress.RegressTest): + def clear_zf(self): + eflags_cur = mu.reg_read(UC_X86_REG_EFLAGS) + eflags = eflags_cur & ~(1 << 6) + #eflags = 0x0 + print "[clear_zf] - eflags from %x to %x" % (eflags_cur, eflags) + if eflags != eflags_cur: + print "[clear_zf] - writing new eflags..." + mu.reg_write(UC_X86_REG_EFLAGS, eflags) + + def set_zf(self): + eflags_cur = mu.reg_read(UC_X86_REG_EFLAGS) + eflags = eflags_cur | (1 << 6) + #eflags = 0xFFFFFFFF + print "[set_zf] - eflags from %x to %x" % (eflags_cur, eflags) + if eflags != eflags_cur: + print "[set_zf] - writing new eflags..." + mu.reg_write(UC_X86_REG_EFLAGS, eflags) + + def handle_zf(self, zf): + print "[handle_zf] - eflags " , zf + if zf == 0: self.clear_zf() + else: self.set_zf() + + def multipath(self): + print "[multipath] - handling ZF (%s) - default" % zf + self.handle_zf(zf) + + # callback for tracing basic blocks + def hook_block(self, uc, address, size, user_data): + print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size)) + + # callback for tracing instructions + def hook_code(self, uc, address, size, user_data): + print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) + rax = mu.reg_read(UC_X86_REG_RAX) + rbx = mu.reg_read(UC_X86_REG_RBX) + rcx = mu.reg_read(UC_X86_REG_RCX) + rdx = mu.reg_read(UC_X86_REG_RDX) + rsi = mu.reg_read(UC_X86_REG_RSI) + rdi = mu.reg_read(UC_X86_REG_RDI) + r8 = mu.reg_read(UC_X86_REG_R8) + r9 = mu.reg_read(UC_X86_REG_R9) + r10 = mu.reg_read(UC_X86_REG_R10) + r11 = mu.reg_read(UC_X86_REG_R11) + r12 = mu.reg_read(UC_X86_REG_R12) + r13 = mu.reg_read(UC_X86_REG_R13) + r14 = mu.reg_read(UC_X86_REG_R14) + r15 = mu.reg_read(UC_X86_REG_R15) + eflags = mu.reg_read(UC_X86_REG_EFLAGS) + + print(">>> RAX = %x" %rax) + print(">>> RBX = %x" %rbx) + print(">>> RCX = %x" %rcx) + print(">>> RDX = %x" %rdx) + print(">>> RSI = %x" %rsi) + print(">>> RDI = %x" %rdi) + print(">>> R8 = %x" %r8) + print(">>> R9 = %x" %r9) + print(">>> R10 = %x" %r10) + print(">>> R11 = %x" %r11) + print(">>> R12 = %x" %r12) + print(">>> R13 = %x" %r13) + print(">>> R14 = %x" %r14) + print(">>> R15 = %x" %r15) + print(">>> ELAGS = %x" %eflags) + print "-"*11 + self.multipath() + print "-"*11 + + # callback for tracing memory access (READ or WRITE) + def hook_mem_access(self, uc, access, address, size, value, user_data): + if access == UC_MEM_WRITE: + print(">>> Memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" \ + %(address, size, value)) + else: # READ + print(">>> Memory is being READ at 0x%x, data size = %u" \ + %(address, size)) + + # callback for tracing invalid memory access (READ or WRITE) + def hook_mem_invalid(self, uc, access, address, size, value, user_data): + print("[ HOOK_MEM_INVALID - Address: %s ]" % hex(address)) + if access == UC_MEM_WRITE_UNMAPPED: + print(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" %(address, size, value)) + return True + else: + print(">>> Missing memory is being READ at 0x%x, data size = %u, data value = 0x%x" %(address, size, value)) + return True + + + def hook_mem_fetch_unmapped(self, uc, access, address, size, value, user_data): + print("[ HOOK_MEM_FETCH - Address: %s ]" % hex(address)) + print("[ mem_fetch_unmapped: faulting address at %s ]" % hex(address).strip("L")) + return True + + def runTest(self): + global mu + + JUMP = "\x48\x31\xc0\x48\xb8\x04\x00\x00\x00\x00\x00\x00\x00\x48\x3d\x05\x00\x00\x00\x74\x05\xe9\x0f\x00\x00\x00\x48\xba\xbe\xba\x00\x00\x00\x00\x00\x00\xe9\x0f\x00\x00\x00\x48\xba\xca\xc0\x00\x00\x00\x00\x00\x00\xe9\x00\x00\x00\x00\x90" + + ADDRESS = 0x1000000 + + print("Emulate x86_64 code") + # Initialize emulator in X86-64bit mode + mu = Uc(UC_ARCH_X86, UC_MODE_64) + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, JUMP) + + # setup stack + mu.reg_write(UC_X86_REG_RSP, ADDRESS + 0x200000) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, self.hook_block) + + # tracing all instructions in range [ADDRESS, ADDRESS+0x60] + mu.hook_add(UC_HOOK_CODE, self.hook_code, None, ADDRESS, ADDRESS+0x60) + + # tracing all memory READ & WRITE access + mu.hook_add(UC_HOOK_MEM_WRITE, self.hook_mem_access) + mu.hook_add(UC_HOOK_MEM_READ, self.hook_mem_access) + mu.hook_add(UC_HOOK_MEM_FETCH_UNMAPPED, self.hook_mem_fetch_unmapped) + mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, self.hook_mem_invalid) + + try: + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + len(JUMP)) + except UcError as e: + print("ERROR: %s" % e) + + # now print out some registers + print(">>> Emulation done. Below is the CPU context") + + +if __name__ == '__main__': + regress.main() From 6e5a3a6d5b5dd3e945545d2d7b1c413abe4c8f20 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 18 Feb 2016 21:58:48 +0800 Subject: [PATCH 06/41] regress: chmod +x jumping.py --- tests/regress/jumping.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tests/regress/jumping.py diff --git a/tests/regress/jumping.py b/tests/regress/jumping.py old mode 100644 new mode 100755 From 0383db9d279658a9bc1d992fbeff35db0cae887e Mon Sep 17 00:00:00 2001 From: emdel Date: Thu, 18 Feb 2016 06:21:04 -0800 Subject: [PATCH 07/41] Added assert --- tests/regress/jumping.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/regress/jumping.py b/tests/regress/jumping.py index 39172a5a..fdddc424 100755 --- a/tests/regress/jumping.py +++ b/tests/regress/jumping.py @@ -23,7 +23,7 @@ import regress mu = 0 -zf = 1 # (0:clear, 1:set) +zf = 0 # (0:clear, 1:set) class Init(regress.RegressTest): @@ -159,8 +159,8 @@ class Init(regress.RegressTest): except UcError as e: print("ERROR: %s" % e) - # now print out some registers - print(">>> Emulation done. Below is the CPU context") + rdx = mu.reg_read(UC_X86_REG_RDX) + self.assertEqual(rdx, 0xbabe, "RDX contains the wrong value. Eflags modification failed.") if __name__ == '__main__': From f010219a0febd7bad1521a658d2e3e8a072147cc Mon Sep 17 00:00:00 2001 From: emdel Date: Thu, 18 Feb 2016 06:29:59 -0800 Subject: [PATCH 08/41] zf set to 1 --- tests/regress/jumping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regress/jumping.py b/tests/regress/jumping.py index fdddc424..265ec075 100755 --- a/tests/regress/jumping.py +++ b/tests/regress/jumping.py @@ -23,7 +23,7 @@ import regress mu = 0 -zf = 0 # (0:clear, 1:set) +zf = 1 # (0:clear, 1:set) class Init(regress.RegressTest): From b7d55e2d67daf88e5c74257ec65f619099e70674 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 21 Feb 2016 21:21:15 +0800 Subject: [PATCH 09/41] update CREDITS.TXT --- CREDITS.TXT | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.TXT b/CREDITS.TXT index 695b73d5..e4319580 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -58,3 +58,4 @@ Zak Escano: MSVC binding Chris Eagle: Java binding Ryan Hileman: Go binding Antonio Parata: .NET binding +Jonathon Reinhart: C unit test From 2ab2b229ce1d6c158fa09fea474d69e6b647c69a Mon Sep 17 00:00:00 2001 From: Ramirez57 Date: Mon, 22 Feb 2016 00:03:14 -0500 Subject: [PATCH 10/41] test case: x86 guest paging Test case for x86 paging using virtual addresses mapped by Unicorn, as well as unmapped. Attempting to read/write from virtual address ranges unmapped by Unicorn wrongly causes protection faults, even when the virtual address points to read/write regions of Unicorn memory. --- tests/unit/Makefile | 4 +- tests/unit/test_x86_soft_paging.c | 210 ++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_x86_soft_paging.c diff --git a/tests/unit/Makefile b/tests/unit/Makefile index 67376fd2..d08671d1 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -5,7 +5,7 @@ CFLAGS += -lcmocka -lunicorn CFLAGS += -I ../../include ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high test_mem_map_ptr \ - test_tb_x86 test_multihook test_pc_change + test_tb_x86 test_multihook test_pc_change test_x86_soft_paging .PHONY: all all: ${ALL_TESTS} @@ -25,6 +25,7 @@ test: ${ALL_TESTS} ./test_tb_x86 ./test_multihook ./test_pc_change + ./test_x86_soft_paging test_sanity: test_sanity.c test_x86: test_x86.c @@ -34,6 +35,7 @@ test_mem_high: test_mem_high.c test_tb_x86: test_tb_x86.c test_multihook: test_multihook.c test_pc_change: test_pc_change.c +test_x86_soft_paging: test_x86_soft_paging.c ${ALL_TESTS}: ${CC} ${CFLAGS} -o $@ $^ diff --git a/tests/unit/test_x86_soft_paging.c b/tests/unit/test_x86_soft_paging.c new file mode 100644 index 00000000..b3a931fc --- /dev/null +++ b/tests/unit/test_x86_soft_paging.c @@ -0,0 +1,210 @@ +#include "unicorn_test.h" +#include + +/* + Two tests here for software paging + Low paging: Test paging using virtual addresses already mapped by Unicorn + High paging: Test paging using virtual addresses not mapped by Unicorn +*/ + +static void test_low_paging(void **state) { + uc_engine *uc; + uc_err err; + int r_eax; + + /* The following x86 code will map emulated physical memory + to virtual memory using pages and attempt + to read/write from virtual memory + + Specifically, the virtual memory address range + has been mapped by Unicorn (0x7FF000 - 0x7FFFFF) + + Memory area purposes: + 0x1000 = page directory + 0x2000 = page table (identity map first 4 MiB) + 0x3000 = page table (0x007FF000 -> 0x00004000) + 0x4000 = data area (0xBEEF) + */ + const uint8_t code[] = { + /* Zero memory for page directories and page tables */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB9, 0x00, 0x10, 0x00, 0x00, /* MOV ECX, 0x1000 */ + 0x31, 0xC0, /* XOR EAX, EAX */ + 0xF3, 0xAB, /* REP STOSD */ + + /* Load DWORD [0x4000] with 0xDEADBEEF to retrieve later */ + 0xBF, 0x00, 0x40, 0x00, 0x00, /* MOV EDI, 0x4000 */ + 0xB8, 0xEF, 0xBE, 0x00, 0x00, /* MOV EAX, 0xBEEF */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Identity map the first 4MiB of memory */ + 0xB9, 0x00, 0x04, 0x00, 0x00, /* MOV ECX, 0x400 */ + 0xBF, 0x00, 0x20, 0x00, 0x00, /* MOV EDI, 0x2000 */ + 0xB8, 0x03, 0x00, 0x00, 0x00, /* MOV EAX, 3 */ + /* aLoop: */ + 0xAB, /* STOSD */ + 0x05, 0x00, 0x10, 0x00, 0x00, /* ADD EAX, 0x1000 */ + 0xE2, 0xF8, /* LOOP aLoop */ + + /* Map physical address 0x4000 to virtual address 0x7FF000 */ + 0xBF, 0xFC, 0x3F, 0x00, 0x00, /* MOV EDI, 0x3FFC */ + 0xB8, 0x03, 0x40, 0x00, 0x00, /* MOV EAX, 0x4003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Add page tables into page directory */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB8, 0x03, 0x20, 0x00, 0x00, /* MOV EAX, 0x2003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + 0xBF, 0x04, 0x10, 0x00, 0x00, /* MOV EDI, 0x1004 */ + 0xB8, 0x03, 0x30, 0x00, 0x00, /* MOV EAX, 0x3003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Load the page directory register */ + 0xB8, 0x00, 0x10, 0x00, 0x00, /* MOV EAX, 0x1000 */ + 0x0F, 0x22, 0xD8, /* MOV CR3, EAX */ + + /* Enable paging */ + 0x0F, 0x20, 0xC0, /* MOV EAX, CR0 */ + 0x0D, 0x00, 0x00, 0x00, 0x80, /* OR EAX, 0x80000000 */ + 0x0F, 0x22, 0xC0, /* MOV CR0, EAX */ + + /* Clear EAX */ + 0x31, 0xC0, /* XOR EAX, EAX */ + + /* Load using virtual memory address; EAX = 0xBEEF */ + 0xBE, 0x00, 0xF0, 0x7F, 0x00, /* MOV ESI, 0x7FF000 */ + 0x8B, 0x06, /* MOV EAX, [ESI] */ + 0xF4, /* HLT */ + }; + + /* Initialise X86-32bit mode */ + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + /* Map 8MB of memory at base address 0 */ + err = uc_mem_map(uc, 0, (8 * 1024 * 1024), UC_PROT_ALL); + uc_assert_success(err); + + /* Write code into memory at address 0 */ + err = uc_mem_write(uc, 0, code, sizeof(code)); + uc_assert_success(err); + + /* Start emulation */ + err = uc_emu_start(uc, 0, sizeof(code), 0, 0); + uc_assert_success(err); + + /* The code should have loaded 0xBEEF into EAX */ + uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); + assert_int_equal(r_eax, 0xBEEF); + + uc_close(uc); +} + + +/****************************************************************************/ + + +static void test_high_paging(void **state) { + uc_engine *uc; + uc_err err; + int r_eax; + + /* The following x86 code will map emulated physical memory + to virtual memory using pages and attempt + to read/write from virtual memory + + Specifically, the virtual memory address range + has not been mapped by UC (0xFFFFF000 - 0xFFFFFFFF) + + Memory area purposes: + 0x1000 = page directory + 0x2000 = page table (identity map first 4 MiB) + 0x3000 = page table (0xFFFFF000 -> 0x00004000) + 0x4000 = data area (0xDEADBEEF) + */ + const uint8_t code[] = { + /* Zero memory for page directories and page tables */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB9, 0x00, 0x10, 0x00, 0x00, /* MOV ECX, 0x1000 */ + 0x31, 0xC0, /* XOR EAX, EAX */ + 0xF3, 0xAB, /* REP STOSD */ + + /* Load DWORD [0x4000] with 0xDEADBEEF to retrieve later */ + 0xBF, 0x00, 0x40, 0x00, 0x00, /* MOV EDI, 0x4000 */ + 0xB8, 0xEF, 0xBE, 0x00, 0x00, /* MOV EAX, 0xBEEF */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Identity map the first 4MiB of memory */ + 0xB9, 0x00, 0x04, 0x00, 0x00, /* MOV ECX, 0x400 */ + 0xBF, 0x00, 0x20, 0x00, 0x00, /* MOV EDI, 0x2000 */ + 0xB8, 0x03, 0x00, 0x00, 0x00, /* MOV EAX, 3 */ + /* aLoop: */ + 0xAB, /* STOSD */ + 0x05, 0x00, 0x10, 0x00, 0x00, /* ADD EAX, 0x1000 */ + 0xE2, 0xF8, /* LOOP aLoop */ + + /* Map physical address 0x4000 to virtual address 0xFFFFF000 */ + 0xBF, 0xFC, 0x3F, 0x00, 0x00, /* MOV EDI, 0x3FFC */ + 0xB8, 0x03, 0x40, 0x00, 0x00, /* MOV EAX, 0x4003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Add page tables into page directory */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB8, 0x03, 0x20, 0x00, 0x00, /* MOV EAX, 0x2003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + 0xBF, 0xFC, 0x1F, 0x00, 0x00, /* MOV EDI, 0x1FFC */ + 0xB8, 0x03, 0x30, 0x00, 0x00, /* MOV EAX, 0x3003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Load the page directory register */ + 0xB8, 0x00, 0x10, 0x00, 0x00, /* MOV EAX, 0x1000 */ + 0x0F, 0x22, 0xD8, /* MOV CR3, EAX */ + + /* Enable paging */ + 0x0F, 0x20, 0xC0, /* MOV EAX, CR0 */ + 0x0D, 0x00, 0x00, 0x00, 0x80, /* OR EAX, 0x80000000 */ + 0x0F, 0x22, 0xC0, /* MOV CR0, EAX */ + + /* Clear EAX */ + 0x31, 0xC0, /* XOR EAX, EAX */ + + /* Load using virtual memory address; EAX = 0xBEEF */ + 0xBE, 0x00, 0xF0, 0xFF, 0xFF, /* MOV ESI, 0xFFFFF000 */ + 0x8B, 0x06, /* MOV EAX, [ESI] */ + 0xF4, /* HLT */ + }; + + /* Initialise X86-32bit mode */ + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + /* Map 4MB of memory at base address 0 */ + err = uc_mem_map(uc, 0, (4 * 1024 * 1024), UC_PROT_ALL); + uc_assert_success(err); + + /* Write code into memory at address 0 */ + err = uc_mem_write(uc, 0, code, sizeof(code)); + uc_assert_success(err); + + /* Start emulation */ + err = uc_emu_start(uc, 0, sizeof(code), 0, 0); + uc_assert_success(err); + + /* The code should have loaded 0xBEEF into EAX */ + uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); + assert_int_equal(r_eax, 0xBEEF); + + uc_close(uc); +} + + +/****************************************************************************/ + + +int main(void) { + const struct CMUnitTests tests[] = { + cmocka_unit_test(test_low_paging), + cmocka_unit_test(test_high_paging), + }; + return cmocka_run_group_tests(tests, NULL, NULL); +} From 2f28f3f210432bdfdd944015699367ab6edfbd0b Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 22 Feb 2016 14:01:00 +0800 Subject: [PATCH 11/41] unit: make test_x86_soft_paging.c compilable. also update .gitignore for its binary --- .gitignore | 1 + tests/unit/test_x86_soft_paging.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8d291285..ae776b30 100644 --- a/.gitignore +++ b/.gitignore @@ -138,6 +138,7 @@ test_tb_x86 test_multihook test_pc_change mem_fuzz +test_x86_soft_paging ################# diff --git a/tests/unit/test_x86_soft_paging.c b/tests/unit/test_x86_soft_paging.c index b3a931fc..1b3aaeef 100644 --- a/tests/unit/test_x86_soft_paging.c +++ b/tests/unit/test_x86_soft_paging.c @@ -202,7 +202,7 @@ static void test_high_paging(void **state) { int main(void) { - const struct CMUnitTests tests[] = { + const struct CMUnitTest tests[] = { cmocka_unit_test(test_low_paging), cmocka_unit_test(test_high_paging), }; From aabcb95f0120151b47b549eaa50899b6abc3d9ce Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 22 Feb 2016 14:02:28 +0800 Subject: [PATCH 12/41] unit: remove ^M from test_x86_soft_paging.c --- tests/unit/test_x86_soft_paging.c | 420 +++++++++++++++--------------- 1 file changed, 210 insertions(+), 210 deletions(-) diff --git a/tests/unit/test_x86_soft_paging.c b/tests/unit/test_x86_soft_paging.c index 1b3aaeef..ffba0155 100644 --- a/tests/unit/test_x86_soft_paging.c +++ b/tests/unit/test_x86_soft_paging.c @@ -1,210 +1,210 @@ -#include "unicorn_test.h" -#include - -/* - Two tests here for software paging - Low paging: Test paging using virtual addresses already mapped by Unicorn - High paging: Test paging using virtual addresses not mapped by Unicorn -*/ - -static void test_low_paging(void **state) { - uc_engine *uc; - uc_err err; - int r_eax; - - /* The following x86 code will map emulated physical memory - to virtual memory using pages and attempt - to read/write from virtual memory - - Specifically, the virtual memory address range - has been mapped by Unicorn (0x7FF000 - 0x7FFFFF) - - Memory area purposes: - 0x1000 = page directory - 0x2000 = page table (identity map first 4 MiB) - 0x3000 = page table (0x007FF000 -> 0x00004000) - 0x4000 = data area (0xBEEF) - */ - const uint8_t code[] = { - /* Zero memory for page directories and page tables */ - 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ - 0xB9, 0x00, 0x10, 0x00, 0x00, /* MOV ECX, 0x1000 */ - 0x31, 0xC0, /* XOR EAX, EAX */ - 0xF3, 0xAB, /* REP STOSD */ - - /* Load DWORD [0x4000] with 0xDEADBEEF to retrieve later */ - 0xBF, 0x00, 0x40, 0x00, 0x00, /* MOV EDI, 0x4000 */ - 0xB8, 0xEF, 0xBE, 0x00, 0x00, /* MOV EAX, 0xBEEF */ - 0x89, 0x07, /* MOV [EDI], EAX */ - - /* Identity map the first 4MiB of memory */ - 0xB9, 0x00, 0x04, 0x00, 0x00, /* MOV ECX, 0x400 */ - 0xBF, 0x00, 0x20, 0x00, 0x00, /* MOV EDI, 0x2000 */ - 0xB8, 0x03, 0x00, 0x00, 0x00, /* MOV EAX, 3 */ - /* aLoop: */ - 0xAB, /* STOSD */ - 0x05, 0x00, 0x10, 0x00, 0x00, /* ADD EAX, 0x1000 */ - 0xE2, 0xF8, /* LOOP aLoop */ - - /* Map physical address 0x4000 to virtual address 0x7FF000 */ - 0xBF, 0xFC, 0x3F, 0x00, 0x00, /* MOV EDI, 0x3FFC */ - 0xB8, 0x03, 0x40, 0x00, 0x00, /* MOV EAX, 0x4003 */ - 0x89, 0x07, /* MOV [EDI], EAX */ - - /* Add page tables into page directory */ - 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ - 0xB8, 0x03, 0x20, 0x00, 0x00, /* MOV EAX, 0x2003 */ - 0x89, 0x07, /* MOV [EDI], EAX */ - 0xBF, 0x04, 0x10, 0x00, 0x00, /* MOV EDI, 0x1004 */ - 0xB8, 0x03, 0x30, 0x00, 0x00, /* MOV EAX, 0x3003 */ - 0x89, 0x07, /* MOV [EDI], EAX */ - - /* Load the page directory register */ - 0xB8, 0x00, 0x10, 0x00, 0x00, /* MOV EAX, 0x1000 */ - 0x0F, 0x22, 0xD8, /* MOV CR3, EAX */ - - /* Enable paging */ - 0x0F, 0x20, 0xC0, /* MOV EAX, CR0 */ - 0x0D, 0x00, 0x00, 0x00, 0x80, /* OR EAX, 0x80000000 */ - 0x0F, 0x22, 0xC0, /* MOV CR0, EAX */ - - /* Clear EAX */ - 0x31, 0xC0, /* XOR EAX, EAX */ - - /* Load using virtual memory address; EAX = 0xBEEF */ - 0xBE, 0x00, 0xF0, 0x7F, 0x00, /* MOV ESI, 0x7FF000 */ - 0x8B, 0x06, /* MOV EAX, [ESI] */ - 0xF4, /* HLT */ - }; - - /* Initialise X86-32bit mode */ - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - uc_assert_success(err); - - /* Map 8MB of memory at base address 0 */ - err = uc_mem_map(uc, 0, (8 * 1024 * 1024), UC_PROT_ALL); - uc_assert_success(err); - - /* Write code into memory at address 0 */ - err = uc_mem_write(uc, 0, code, sizeof(code)); - uc_assert_success(err); - - /* Start emulation */ - err = uc_emu_start(uc, 0, sizeof(code), 0, 0); - uc_assert_success(err); - - /* The code should have loaded 0xBEEF into EAX */ - uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); - assert_int_equal(r_eax, 0xBEEF); - - uc_close(uc); -} - - -/****************************************************************************/ - - -static void test_high_paging(void **state) { - uc_engine *uc; - uc_err err; - int r_eax; - - /* The following x86 code will map emulated physical memory - to virtual memory using pages and attempt - to read/write from virtual memory - - Specifically, the virtual memory address range - has not been mapped by UC (0xFFFFF000 - 0xFFFFFFFF) - - Memory area purposes: - 0x1000 = page directory - 0x2000 = page table (identity map first 4 MiB) - 0x3000 = page table (0xFFFFF000 -> 0x00004000) - 0x4000 = data area (0xDEADBEEF) - */ - const uint8_t code[] = { - /* Zero memory for page directories and page tables */ - 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ - 0xB9, 0x00, 0x10, 0x00, 0x00, /* MOV ECX, 0x1000 */ - 0x31, 0xC0, /* XOR EAX, EAX */ - 0xF3, 0xAB, /* REP STOSD */ - - /* Load DWORD [0x4000] with 0xDEADBEEF to retrieve later */ - 0xBF, 0x00, 0x40, 0x00, 0x00, /* MOV EDI, 0x4000 */ - 0xB8, 0xEF, 0xBE, 0x00, 0x00, /* MOV EAX, 0xBEEF */ - 0x89, 0x07, /* MOV [EDI], EAX */ - - /* Identity map the first 4MiB of memory */ - 0xB9, 0x00, 0x04, 0x00, 0x00, /* MOV ECX, 0x400 */ - 0xBF, 0x00, 0x20, 0x00, 0x00, /* MOV EDI, 0x2000 */ - 0xB8, 0x03, 0x00, 0x00, 0x00, /* MOV EAX, 3 */ - /* aLoop: */ - 0xAB, /* STOSD */ - 0x05, 0x00, 0x10, 0x00, 0x00, /* ADD EAX, 0x1000 */ - 0xE2, 0xF8, /* LOOP aLoop */ - - /* Map physical address 0x4000 to virtual address 0xFFFFF000 */ - 0xBF, 0xFC, 0x3F, 0x00, 0x00, /* MOV EDI, 0x3FFC */ - 0xB8, 0x03, 0x40, 0x00, 0x00, /* MOV EAX, 0x4003 */ - 0x89, 0x07, /* MOV [EDI], EAX */ - - /* Add page tables into page directory */ - 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ - 0xB8, 0x03, 0x20, 0x00, 0x00, /* MOV EAX, 0x2003 */ - 0x89, 0x07, /* MOV [EDI], EAX */ - 0xBF, 0xFC, 0x1F, 0x00, 0x00, /* MOV EDI, 0x1FFC */ - 0xB8, 0x03, 0x30, 0x00, 0x00, /* MOV EAX, 0x3003 */ - 0x89, 0x07, /* MOV [EDI], EAX */ - - /* Load the page directory register */ - 0xB8, 0x00, 0x10, 0x00, 0x00, /* MOV EAX, 0x1000 */ - 0x0F, 0x22, 0xD8, /* MOV CR3, EAX */ - - /* Enable paging */ - 0x0F, 0x20, 0xC0, /* MOV EAX, CR0 */ - 0x0D, 0x00, 0x00, 0x00, 0x80, /* OR EAX, 0x80000000 */ - 0x0F, 0x22, 0xC0, /* MOV CR0, EAX */ - - /* Clear EAX */ - 0x31, 0xC0, /* XOR EAX, EAX */ - - /* Load using virtual memory address; EAX = 0xBEEF */ - 0xBE, 0x00, 0xF0, 0xFF, 0xFF, /* MOV ESI, 0xFFFFF000 */ - 0x8B, 0x06, /* MOV EAX, [ESI] */ - 0xF4, /* HLT */ - }; - - /* Initialise X86-32bit mode */ - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - uc_assert_success(err); - - /* Map 4MB of memory at base address 0 */ - err = uc_mem_map(uc, 0, (4 * 1024 * 1024), UC_PROT_ALL); - uc_assert_success(err); - - /* Write code into memory at address 0 */ - err = uc_mem_write(uc, 0, code, sizeof(code)); - uc_assert_success(err); - - /* Start emulation */ - err = uc_emu_start(uc, 0, sizeof(code), 0, 0); - uc_assert_success(err); - - /* The code should have loaded 0xBEEF into EAX */ - uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); - assert_int_equal(r_eax, 0xBEEF); - - uc_close(uc); -} - - -/****************************************************************************/ - - -int main(void) { - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_low_paging), - cmocka_unit_test(test_high_paging), - }; - return cmocka_run_group_tests(tests, NULL, NULL); -} +#include "unicorn_test.h" +#include + +/* + Two tests here for software paging + Low paging: Test paging using virtual addresses already mapped by Unicorn + High paging: Test paging using virtual addresses not mapped by Unicorn +*/ + +static void test_low_paging(void **state) { + uc_engine *uc; + uc_err err; + int r_eax; + + /* The following x86 code will map emulated physical memory + to virtual memory using pages and attempt + to read/write from virtual memory + + Specifically, the virtual memory address range + has been mapped by Unicorn (0x7FF000 - 0x7FFFFF) + + Memory area purposes: + 0x1000 = page directory + 0x2000 = page table (identity map first 4 MiB) + 0x3000 = page table (0x007FF000 -> 0x00004000) + 0x4000 = data area (0xBEEF) + */ + const uint8_t code[] = { + /* Zero memory for page directories and page tables */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB9, 0x00, 0x10, 0x00, 0x00, /* MOV ECX, 0x1000 */ + 0x31, 0xC0, /* XOR EAX, EAX */ + 0xF3, 0xAB, /* REP STOSD */ + + /* Load DWORD [0x4000] with 0xDEADBEEF to retrieve later */ + 0xBF, 0x00, 0x40, 0x00, 0x00, /* MOV EDI, 0x4000 */ + 0xB8, 0xEF, 0xBE, 0x00, 0x00, /* MOV EAX, 0xBEEF */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Identity map the first 4MiB of memory */ + 0xB9, 0x00, 0x04, 0x00, 0x00, /* MOV ECX, 0x400 */ + 0xBF, 0x00, 0x20, 0x00, 0x00, /* MOV EDI, 0x2000 */ + 0xB8, 0x03, 0x00, 0x00, 0x00, /* MOV EAX, 3 */ + /* aLoop: */ + 0xAB, /* STOSD */ + 0x05, 0x00, 0x10, 0x00, 0x00, /* ADD EAX, 0x1000 */ + 0xE2, 0xF8, /* LOOP aLoop */ + + /* Map physical address 0x4000 to virtual address 0x7FF000 */ + 0xBF, 0xFC, 0x3F, 0x00, 0x00, /* MOV EDI, 0x3FFC */ + 0xB8, 0x03, 0x40, 0x00, 0x00, /* MOV EAX, 0x4003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Add page tables into page directory */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB8, 0x03, 0x20, 0x00, 0x00, /* MOV EAX, 0x2003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + 0xBF, 0x04, 0x10, 0x00, 0x00, /* MOV EDI, 0x1004 */ + 0xB8, 0x03, 0x30, 0x00, 0x00, /* MOV EAX, 0x3003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Load the page directory register */ + 0xB8, 0x00, 0x10, 0x00, 0x00, /* MOV EAX, 0x1000 */ + 0x0F, 0x22, 0xD8, /* MOV CR3, EAX */ + + /* Enable paging */ + 0x0F, 0x20, 0xC0, /* MOV EAX, CR0 */ + 0x0D, 0x00, 0x00, 0x00, 0x80, /* OR EAX, 0x80000000 */ + 0x0F, 0x22, 0xC0, /* MOV CR0, EAX */ + + /* Clear EAX */ + 0x31, 0xC0, /* XOR EAX, EAX */ + + /* Load using virtual memory address; EAX = 0xBEEF */ + 0xBE, 0x00, 0xF0, 0x7F, 0x00, /* MOV ESI, 0x7FF000 */ + 0x8B, 0x06, /* MOV EAX, [ESI] */ + 0xF4, /* HLT */ + }; + + /* Initialise X86-32bit mode */ + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + /* Map 8MB of memory at base address 0 */ + err = uc_mem_map(uc, 0, (8 * 1024 * 1024), UC_PROT_ALL); + uc_assert_success(err); + + /* Write code into memory at address 0 */ + err = uc_mem_write(uc, 0, code, sizeof(code)); + uc_assert_success(err); + + /* Start emulation */ + err = uc_emu_start(uc, 0, sizeof(code), 0, 0); + uc_assert_success(err); + + /* The code should have loaded 0xBEEF into EAX */ + uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); + assert_int_equal(r_eax, 0xBEEF); + + uc_close(uc); +} + + +/****************************************************************************/ + + +static void test_high_paging(void **state) { + uc_engine *uc; + uc_err err; + int r_eax; + + /* The following x86 code will map emulated physical memory + to virtual memory using pages and attempt + to read/write from virtual memory + + Specifically, the virtual memory address range + has not been mapped by UC (0xFFFFF000 - 0xFFFFFFFF) + + Memory area purposes: + 0x1000 = page directory + 0x2000 = page table (identity map first 4 MiB) + 0x3000 = page table (0xFFFFF000 -> 0x00004000) + 0x4000 = data area (0xDEADBEEF) + */ + const uint8_t code[] = { + /* Zero memory for page directories and page tables */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB9, 0x00, 0x10, 0x00, 0x00, /* MOV ECX, 0x1000 */ + 0x31, 0xC0, /* XOR EAX, EAX */ + 0xF3, 0xAB, /* REP STOSD */ + + /* Load DWORD [0x4000] with 0xDEADBEEF to retrieve later */ + 0xBF, 0x00, 0x40, 0x00, 0x00, /* MOV EDI, 0x4000 */ + 0xB8, 0xEF, 0xBE, 0x00, 0x00, /* MOV EAX, 0xBEEF */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Identity map the first 4MiB of memory */ + 0xB9, 0x00, 0x04, 0x00, 0x00, /* MOV ECX, 0x400 */ + 0xBF, 0x00, 0x20, 0x00, 0x00, /* MOV EDI, 0x2000 */ + 0xB8, 0x03, 0x00, 0x00, 0x00, /* MOV EAX, 3 */ + /* aLoop: */ + 0xAB, /* STOSD */ + 0x05, 0x00, 0x10, 0x00, 0x00, /* ADD EAX, 0x1000 */ + 0xE2, 0xF8, /* LOOP aLoop */ + + /* Map physical address 0x4000 to virtual address 0xFFFFF000 */ + 0xBF, 0xFC, 0x3F, 0x00, 0x00, /* MOV EDI, 0x3FFC */ + 0xB8, 0x03, 0x40, 0x00, 0x00, /* MOV EAX, 0x4003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Add page tables into page directory */ + 0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */ + 0xB8, 0x03, 0x20, 0x00, 0x00, /* MOV EAX, 0x2003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + 0xBF, 0xFC, 0x1F, 0x00, 0x00, /* MOV EDI, 0x1FFC */ + 0xB8, 0x03, 0x30, 0x00, 0x00, /* MOV EAX, 0x3003 */ + 0x89, 0x07, /* MOV [EDI], EAX */ + + /* Load the page directory register */ + 0xB8, 0x00, 0x10, 0x00, 0x00, /* MOV EAX, 0x1000 */ + 0x0F, 0x22, 0xD8, /* MOV CR3, EAX */ + + /* Enable paging */ + 0x0F, 0x20, 0xC0, /* MOV EAX, CR0 */ + 0x0D, 0x00, 0x00, 0x00, 0x80, /* OR EAX, 0x80000000 */ + 0x0F, 0x22, 0xC0, /* MOV CR0, EAX */ + + /* Clear EAX */ + 0x31, 0xC0, /* XOR EAX, EAX */ + + /* Load using virtual memory address; EAX = 0xBEEF */ + 0xBE, 0x00, 0xF0, 0xFF, 0xFF, /* MOV ESI, 0xFFFFF000 */ + 0x8B, 0x06, /* MOV EAX, [ESI] */ + 0xF4, /* HLT */ + }; + + /* Initialise X86-32bit mode */ + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + /* Map 4MB of memory at base address 0 */ + err = uc_mem_map(uc, 0, (4 * 1024 * 1024), UC_PROT_ALL); + uc_assert_success(err); + + /* Write code into memory at address 0 */ + err = uc_mem_write(uc, 0, code, sizeof(code)); + uc_assert_success(err); + + /* Start emulation */ + err = uc_emu_start(uc, 0, sizeof(code), 0, 0); + uc_assert_success(err); + + /* The code should have loaded 0xBEEF into EAX */ + uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); + assert_int_equal(r_eax, 0xBEEF); + + uc_close(uc); +} + + +/****************************************************************************/ + + +int main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_low_paging), + cmocka_unit_test(test_high_paging), + }; + return cmocka_run_group_tests(tests, NULL, NULL); +} From 693719e732042469e4f5b745698b765d8af317b3 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 10:50:51 -0800 Subject: [PATCH 13/41] Go: update hook interface --- bindings/go/unicorn/hook.c | 12 ++++++++---- bindings/go/unicorn/hook.go | 27 +++++++++------------------ bindings/go/unicorn/hook.h | 4 ++-- bindings/go/unicorn/unicorn.go | 2 +- 4 files changed, 20 insertions(+), 25 deletions(-) diff --git a/bindings/go/unicorn/hook.c b/bindings/go/unicorn/hook.c index 4ed41b51..a2b7dc93 100644 --- a/bindings/go/unicorn/hook.c +++ b/bindings/go/unicorn/hook.c @@ -1,12 +1,16 @@ #include #include "_cgo_export.h" -uc_err uc_hook_add_i1(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, int arg1) { - return uc_hook_add(handle, h2, type, callback, (void *)user, arg1); +uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, + void *user_data, uint64_t begin, uint64_t end, ...); + + +uc_err uc_hook_add_wrap(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end) { + return uc_hook_add(handle, h2, type, callback, (void *)user, begin, end); } -uc_err uc_hook_add_u2(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t arg1, uint64_t arg2) { - return uc_hook_add(handle, h2, type, callback, (void *)user, arg1, arg2); +uc_err uc_hook_add_insn(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end, int insn) { + return uc_hook_add(handle, h2, type, callback, (void *)user, begin, end, insn); } void hookCode_cgo(uc_engine *handle, uint64_t addr, uint32_t size, uintptr_t user) { diff --git a/bindings/go/unicorn/hook.go b/bindings/go/unicorn/hook.go index d5dfc874..6591c46c 100644 --- a/bindings/go/unicorn/hook.go +++ b/bindings/go/unicorn/hook.go @@ -63,23 +63,21 @@ func hookX86Syscall(handle unsafe.Pointer, user unsafe.Pointer) { hook.Callback.(func(Unicorn))(hook.Uc) } -func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) { +func (u *uc) HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) (Hook, error) { var callback unsafe.Pointer - var iarg1 C.int - var uarg1, uarg2 C.uint64_t - rangeMode := false + var insn C.int + var insnMode bool switch htype { case HOOK_BLOCK, HOOK_CODE: - rangeMode = true callback = C.hookCode_cgo case HOOK_MEM_READ, HOOK_MEM_WRITE, HOOK_MEM_READ | HOOK_MEM_WRITE: - rangeMode = true callback = C.hookMemAccess_cgo case HOOK_INTR: callback = C.hookInterrupt_cgo case HOOK_INSN: - iarg1 = C.int(extra[0]) - switch iarg1 { + insn = C.int(extra[0]) + insnMode = true + switch insn { case X86_INS_IN: callback = C.hookX86In_cgo case X86_INS_OUT: @@ -93,7 +91,6 @@ func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) { // special case for mask if htype&(HOOK_MEM_READ_UNMAPPED|HOOK_MEM_WRITE_UNMAPPED|HOOK_MEM_FETCH_UNMAPPED| HOOK_MEM_READ_PROT|HOOK_MEM_WRITE_PROT|HOOK_MEM_FETCH_PROT) != 0 { - rangeMode = true callback = C.hookMemInvalid_cgo } else { return 0, errors.New("Unknown hook type.") @@ -102,16 +99,10 @@ func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) { var h2 C.uc_hook data := &HookData{u, cb} uptr := uintptr(unsafe.Pointer(data)) - if rangeMode { - if len(extra) == 2 { - uarg1 = C.uint64_t(extra[0]) - uarg2 = C.uint64_t(extra[1]) - } else { - uarg1, uarg2 = 1, 0 - } - C.uc_hook_add_u2(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), uarg1, uarg2) + if insnMode { + C.uc_hook_add_wrap(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end)) } else { - C.uc_hook_add_i1(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), iarg1) + C.uc_hook_add_insn(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end), insn) } hookDataMap[uptr] = data hookToUintptr[Hook(h2)] = uptr diff --git a/bindings/go/unicorn/hook.h b/bindings/go/unicorn/hook.h index 6c209516..35813a0a 100644 --- a/bindings/go/unicorn/hook.h +++ b/bindings/go/unicorn/hook.h @@ -1,5 +1,5 @@ -uc_err uc_hook_add_i1(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, int arg1); -uc_err uc_hook_add_u2(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t arg1, uint64_t arg2); +uc_err uc_hook_add_wrap(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end); +uc_err uc_hook_add_insn(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end, int insn); void hookCode_cgo(uc_engine *handle, uint64_t addr, uint32_t size, uintptr_t user); bool hookMemInvalid_cgo(uc_engine *handle, uc_mem_type type, uint64_t addr, int size, int64_t value, uintptr_t user); void hookMemAccess_cgo(uc_engine *handle, uc_mem_type type, uint64_t addr, int size, int64_t value, uintptr_t user); diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 4f6f1f99..1f3e9094 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -39,7 +39,7 @@ type Unicorn interface { Start(begin, until uint64) error StartWithOptions(begin, until uint64, options *UcOptions) error Stop() error - HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) + HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) (Hook, error) HookDel(hook Hook) error Close() error } From 475c8de3dec65f1d90928e2665d767ee91880bfd Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 10:55:40 -0800 Subject: [PATCH 14/41] Go: update test hooks --- bindings/go/unicorn/hook.go | 4 ++-- bindings/go/unicorn/x86_test.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bindings/go/unicorn/hook.go b/bindings/go/unicorn/hook.go index 6591c46c..0a1a7d6f 100644 --- a/bindings/go/unicorn/hook.go +++ b/bindings/go/unicorn/hook.go @@ -100,9 +100,9 @@ func (u *uc) HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) data := &HookData{u, cb} uptr := uintptr(unsafe.Pointer(data)) if insnMode { - C.uc_hook_add_wrap(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end)) - } else { C.uc_hook_add_insn(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end), insn) + } else { + C.uc_hook_add_wrap(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end)) } hookDataMap[uptr] = data hookToUintptr[Hook(h2)] = uptr diff --git a/bindings/go/unicorn/x86_test.go b/bindings/go/unicorn/x86_test.go index 67400552..aca1d3be 100644 --- a/bindings/go/unicorn/x86_test.go +++ b/bindings/go/unicorn/x86_test.go @@ -96,7 +96,7 @@ func TestX86InOut(t *testing.T) { default: return 0 } - }, X86_INS_IN) + }, 1, 0, X86_INS_IN) mu.HookAdd(HOOK_INSN, func(_ Unicorn, port, size, value uint32) { outCalled = true var err error @@ -111,7 +111,7 @@ func TestX86InOut(t *testing.T) { if err != nil { t.Fatal(err) } - }, X86_INS_OUT) + }, 1, 0, X86_INS_OUT) if err := mu.Start(ADDRESS, ADDRESS+uint64(len(code))); err != nil { t.Fatal(err) } @@ -132,7 +132,7 @@ func TestX86Syscall(t *testing.T) { mu.HookAdd(HOOK_INSN, func(_ Unicorn) { rax, _ := mu.RegRead(X86_REG_RAX) mu.RegWrite(X86_REG_RAX, rax+1) - }, X86_INS_SYSCALL) + }, 1, 0, X86_INS_SYSCALL) mu.RegWrite(X86_REG_RAX, 0x100) err = mu.Start(ADDRESS, ADDRESS+uint64(len(code))) if err != nil { From 74f783a27419d22da3c4e653aba48466a703929a Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 10:51:10 -0800 Subject: [PATCH 15/41] Go: add x86 RegWriteMmr method --- bindings/go/unicorn/unicorn.go | 1 + bindings/go/unicorn/x86.go | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 bindings/go/unicorn/x86.go diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 1f3e9094..2076fb88 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -36,6 +36,7 @@ type Unicorn interface { MemWrite(addr uint64, data []byte) error RegRead(reg int) (uint64, error) RegWrite(reg int, value uint64) error + RegWriteMmr(reg int, value *X86Mmr) error Start(begin, until uint64) error StartWithOptions(begin, until uint64, options *UcOptions) error Stop() error diff --git a/bindings/go/unicorn/x86.go b/bindings/go/unicorn/x86.go new file mode 100644 index 00000000..490f7dfa --- /dev/null +++ b/bindings/go/unicorn/x86.go @@ -0,0 +1,26 @@ +package unicorn + +import ( + "unsafe" +) + +// #include +// #include +import "C" + +type X86Mmr struct { + Selector uint16 + Base uint64 + Limit uint32 + Flags uint32 +} + +func (u *uc) RegWriteMmr(reg int, value *X86Mmr) error { + var val C.uc_x86_mmr + val.selector = C.uint16_t(value.Selector) + val.base = C.uint64_t(value.Base) + val.limit = C.uint32_t(value.Limit) + val.flags = C.uint32_t(value.Flags) + ucerr := C.uc_reg_write(u.handle, C.int(reg), unsafe.Pointer(&val)) + return errReturn(ucerr) +} From 9f1603c15753016b8636b4be3ae1b40169c0119d Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 11:10:15 -0800 Subject: [PATCH 16/41] Go: add MemRegions --- bindings/go/unicorn/unicorn.go | 25 +++++++++++++++++++++++++ bindings/go/unicorn/unicorn_test.go | 22 ++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 2076fb88..1500627a 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -25,12 +25,18 @@ func errReturn(err C.uc_err) error { return nil } +type MemRegion struct { + Begin, End uint64 + Prot int +} + type Unicorn interface { MemMap(addr, size uint64) error MemMapProt(addr, size uint64, prot int) error MemMapPtr(addr, size uint64, prot int, ptr unsafe.Pointer) error MemProtect(addr, size uint64, prot int) error MemUnmap(addr, size uint64) error + MemRegions() ([]*MemRegion, error) MemRead(addr, size uint64) ([]byte, error) MemReadInto(dst []byte, addr uint64) error MemWrite(addr uint64, data []byte) error @@ -104,6 +110,25 @@ func (u *uc) RegRead(reg int) (uint64, error) { return uint64(val), errReturn(ucerr) } +func (u *uc) MemRegions() ([]*MemRegion, error) { + var regions *C.struct_uc_mem_region + var count C.uint32_t + ucerr := C.uc_mem_regions(u.handle, ®ions, &count) + if ucerr != C.UC_ERR_OK { + return nil, errReturn(ucerr) + } + ret := make([]*MemRegion, count) + tmp := (*[1 << 30]C.struct_uc_mem_region)(unsafe.Pointer(regions))[:count] + for i, v := range tmp { + ret[i] = &MemRegion{ + Begin: uint64(v.begin), + End: uint64(v.end), + Prot: int(v.perms), + } + } + return ret, nil +} + func (u *uc) MemWrite(addr uint64, data []byte) error { if len(data) == 0 { return nil diff --git a/bindings/go/unicorn/unicorn_test.go b/bindings/go/unicorn/unicorn_test.go index caf13126..58e78431 100644 --- a/bindings/go/unicorn/unicorn_test.go +++ b/bindings/go/unicorn/unicorn_test.go @@ -37,3 +37,25 @@ func TestDoubleClose(t *testing.T) { t.Fatal(err) } } + +func TestMemRegions(t *testing.T) { + mu, err := NewUnicorn(ARCH_X86, MODE_32) + if err != nil { + t.Fatal(err) + } + err = mu.MemMap(0x1000, 0x1000) + if err != nil { + t.Fatal(err) + } + regions, err := mu.MemRegions() + if err != nil { + t.Fatal(err) + } + if len(regions) != 1 { + t.Fatalf("returned wrong number of regions: %d != 1", len(regions)) + } + r := regions[0] + if r.Begin != 0x1000 || r.End != 0x1fff || r.Prot != 7 { + t.Fatalf("incorrect region: %#v", r) + } +} From 43eb9ec351c5998be0504fa39e82a8f7882a7a94 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 11:15:06 -0800 Subject: [PATCH 17/41] Go: add uc_query api --- bindings/go/unicorn/unicorn.go | 7 +++++++ bindings/go/unicorn/unicorn_test.go | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 1500627a..ecaa6336 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -48,6 +48,7 @@ type Unicorn interface { Stop() error HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) (Hook, error) HookDel(hook Hook) error + Query(queryType int) (uint64, error) Close() error } @@ -167,3 +168,9 @@ func (u *uc) MemProtect(addr, size uint64, prot int) error { func (u *uc) MemUnmap(addr, size uint64) error { return errReturn(C.uc_mem_unmap(u.handle, C.uint64_t(addr), C.size_t(size))) } + +func (u *uc) Query(queryType int) (uint64, error) { + var ret C.size_t + ucerr := C.uc_query(u.handle, C.uc_query_type(queryType), &ret) + return uint64(ret), errReturn(ucerr) +} diff --git a/bindings/go/unicorn/unicorn_test.go b/bindings/go/unicorn/unicorn_test.go index 58e78431..6627528f 100644 --- a/bindings/go/unicorn/unicorn_test.go +++ b/bindings/go/unicorn/unicorn_test.go @@ -59,3 +59,17 @@ func TestMemRegions(t *testing.T) { t.Fatalf("incorrect region: %#v", r) } } + +func TestQuery(t *testing.T) { + mu, err := NewUnicorn(ARCH_ARM, MODE_THUMB) + if err != nil { + t.Fatal(err) + } + mode, err := mu.Query(QUERY_MODE) + if err != nil { + t.Fatal(err) + } + if mode != MODE_THUMB { + t.Fatal("query returned invalid mode: %d != %d", mode, MODE_THUMB) + } +} From 4f1c88e70c23c34e54e96cbdcdd9da08ebcdefbf Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sun, 28 Feb 2016 12:00:58 -0800 Subject: [PATCH 18/41] Go: add RegReadMmr and test --- bindings/go/unicorn/unicorn.go | 1 + bindings/go/unicorn/x86.go | 12 ++++++++++++ bindings/go/unicorn/x86_test.go | 15 +++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index ecaa6336..2b0e456c 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -42,6 +42,7 @@ type Unicorn interface { MemWrite(addr uint64, data []byte) error RegRead(reg int) (uint64, error) RegWrite(reg int, value uint64) error + RegReadMmr(reg int) (*X86Mmr, error) RegWriteMmr(reg int, value *X86Mmr) error Start(begin, until uint64) error StartWithOptions(begin, until uint64, options *UcOptions) error diff --git a/bindings/go/unicorn/x86.go b/bindings/go/unicorn/x86.go index 490f7dfa..9097de2a 100644 --- a/bindings/go/unicorn/x86.go +++ b/bindings/go/unicorn/x86.go @@ -24,3 +24,15 @@ func (u *uc) RegWriteMmr(reg int, value *X86Mmr) error { ucerr := C.uc_reg_write(u.handle, C.int(reg), unsafe.Pointer(&val)) return errReturn(ucerr) } + +func (u *uc) RegReadMmr(reg int) (*X86Mmr, error) { + var val C.uc_x86_mmr + ucerr := C.uc_reg_read(u.handle, C.int(reg), unsafe.Pointer(&val)) + ret := &X86Mmr{ + Selector: uint16(val.selector), + Base: uint64(val.base), + Limit: uint32(val.limit), + Flags: uint32(val.flags), + } + return ret, errReturn(ucerr) +} diff --git a/bindings/go/unicorn/x86_test.go b/bindings/go/unicorn/x86_test.go index aca1d3be..c74a0611 100644 --- a/bindings/go/unicorn/x86_test.go +++ b/bindings/go/unicorn/x86_test.go @@ -143,3 +143,18 @@ func TestX86Syscall(t *testing.T) { t.Fatal("Incorrect syscall return value.") } } + +func TestX86Mmr(t *testing.T) { + mu, err := MakeUc(MODE_64, "") + if err != nil { + t.Fatal(err) + } + err = mu.RegWriteMmr(X86_REG_GDTR, &X86Mmr{Selector: 0, Base: 0x1000, Limit: 0x1fff, Flags: 0}) + if err != nil { + t.Fatal(err) + } + mmr, err := mu.RegReadMmr(X86_REG_GDTR) + if mmr.Selector != 0 || mmr.Base != 0x1000 || mmr.Limit != 0x1fff || mmr.Flags != 0 { + t.Fatalf("mmr read failed: %#v", mmr) + } +} From 5fa6705d7af599275193d5eeaad5abf20fcc1fee Mon Sep 17 00:00:00 2001 From: Jonas Zaddach Date: Mon, 29 Feb 2016 22:57:41 +0100 Subject: [PATCH 19/41] Fixed restoring of eflags after helper call --- qemu/target-i386/translate.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index d68cb516..76bab2d6 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -4721,6 +4721,17 @@ static void sync_eflags(DisasContext *s, TCGContext *tcg_ctx) tcg_gen_st_tl(tcg_ctx, *cpu_T[0], cpu_env, offsetof(CPUX86State, eflags)); } +static void restore_eflags(DisasContext *s, TCGContext *tcg_ctx) +{ + TCGv **cpu_T = (TCGv **)tcg_ctx->cpu_T; + TCGv_ptr cpu_env = tcg_ctx->cpu_env; + + tcg_gen_ld_tl(tcg_ctx, *cpu_T[0], cpu_env, offsetof(CPUX86State, eflags)); + gen_helper_write_eflags(tcg_ctx, cpu_env, *cpu_T[0], + tcg_const_i32(tcg_ctx, (TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff)); + set_cc_op(s, CC_OP_EFLAGS); +} + /* convert one instruction. s->is_jmp is set if the translation must be stopped. Return the next pc value */ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, @@ -4773,6 +4784,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, changed_cc_op = true; } gen_uc_tracecode(tcg_ctx, 0xf1f1f1f1, UC_HOOK_CODE_IDX, env->uc, pc_start); + restore_eflags(s, tcg_ctx); // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } From 9eb1c57c34cf8ba5c3f59a77087ebf170f46ae25 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 1 Mar 2016 13:49:27 +0800 Subject: [PATCH 20/41] add Travis support for automated tests --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..b80f07f3 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: c +sudo: false +before_install: + - export LD_LIBRARY_PATH=`pwd`/samples/:$LD_LIBRARY_PATH +script: + - ./make.sh +compiler: + - clang + - gcc From d6fee1fd6a3427d50f8a28ca66df104c9c3783bd Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 1 Mar 2016 13:54:32 +0800 Subject: [PATCH 21/41] add Travis build status to README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 942e1b8e..0d8e7558 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ Unicorn Engine ============== +[![Build Status](https://travis-ci.org/unicorn-engine/unicorn.svg?branch=master)](https://travis-ci.org/unicorn-engine/unicorn) + Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framework based on [QEMU](http://qemu.org). From 1cd3c3093b0fc152daed76bfd0068a34c922e09c Mon Sep 17 00:00:00 2001 From: Hiroyuki UEKAWA Date: Wed, 2 Mar 2016 09:23:48 +0900 Subject: [PATCH 22/41] fix WRITE_BYTE_H --- qemu/target-arm/unicorn_aarch64.c | 2 +- qemu/target-arm/unicorn_arm.c | 2 +- qemu/target-i386/unicorn.c | 2 +- qemu/target-m68k/unicorn.c | 2 +- qemu/target-mips/unicorn.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index 1ce9d6eb..fbdfaff7 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -62,7 +62,7 @@ int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) #define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) +#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 95ea812d..da51cac4 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -69,7 +69,7 @@ int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) #define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) +#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index c8436b9b..92b79d32 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -578,7 +578,7 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) #define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) +#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) diff --git a/qemu/target-m68k/unicorn.c b/qemu/target-m68k/unicorn.c index 0055d4a1..bbf5898f 100644 --- a/qemu/target-m68k/unicorn.c +++ b/qemu/target-m68k/unicorn.c @@ -54,7 +54,7 @@ int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) #define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) +#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) diff --git a/qemu/target-mips/unicorn.c b/qemu/target-mips/unicorn.c index 6af98dce..6085a259 100644 --- a/qemu/target-mips/unicorn.c +++ b/qemu/target-mips/unicorn.c @@ -67,7 +67,7 @@ int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) #define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) +#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) From c5888e5670e7608b9e49436962b294fb81fddbe2 Mon Sep 17 00:00:00 2001 From: Hiroyuki UEKAWA Date: Wed, 2 Mar 2016 12:43:02 +0900 Subject: [PATCH 23/41] move macros in `qemu/target-*/unicorn*.c` to `uc_priv.h` --- include/uc_priv.h | 11 +++++++++++ qemu/target-arm/unicorn_aarch64.c | 17 +---------------- qemu/target-arm/unicorn_arm.c | 16 +--------------- qemu/target-i386/unicorn.c | 16 ++-------------- qemu/target-m68k/unicorn.c | 14 +------------- qemu/target-mips/unicorn.c | 15 +-------------- qemu/target-sparc/unicorn.c | 8 +------- qemu/target-sparc/unicorn64.c | 8 +------- 8 files changed, 19 insertions(+), 86 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 0ef5a3dd..e36a8c84 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -22,6 +22,17 @@ #define ARR_SIZE(a) (sizeof(a)/sizeof(a[0])) +#define READ_QWORD(x) ((uint64)x) +#define READ_DWORD(x) (x & 0xffffffff) +#define READ_WORD(x) (x & 0xffff) +#define READ_BYTE_H(x) ((x & 0xffff) >> 8) +#define READ_BYTE_L(x) (x & 0xff) +#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) +#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) +#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) +#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) + + QTAILQ_HEAD(CPUTailQ, CPUState); typedef struct ModuleEntry { diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index fbdfaff7..c1d53a68 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -3,21 +3,11 @@ #include "hw/boards.h" #include "hw/arm/arm.h" - #include "sysemu/cpus.h" - #include "unicorn.h" - #include "cpu.h" - #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static void arm64_set_pc(struct uc_struct *uc, uint64_t address) @@ -60,11 +50,6 @@ int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value) return 0; } -#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) -#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index da51cac4..9fc2a44c 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -3,20 +3,11 @@ #include "hw/boards.h" #include "hw/arm/arm.h" - #include "sysemu/cpus.h" - #include "unicorn.h" - #include "cpu.h" #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static void arm_set_pc(struct uc_struct *uc, uint64_t address) @@ -67,11 +58,6 @@ int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value) return 0; } -#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) -#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 92b79d32..7ec2d140 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -2,20 +2,14 @@ /* By Nguyen Anh Quynh , 2015 */ #include "hw/boards.h" -#include "sysemu/cpus.h" #include "hw/i386/pc.h" +#include "sysemu/cpus.h" #include "unicorn.h" #include "cpu.h" #include "tcg.h" - #include "unicorn_common.h" #include /* needed for uc_x86_mmr */ - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static void x86_set_pc(struct uc_struct *uc, uint64_t address) @@ -575,12 +569,6 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) return 0; } - -#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) -#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-m68k/unicorn.c b/qemu/target-m68k/unicorn.c index bbf5898f..0edf04c2 100644 --- a/qemu/target-m68k/unicorn.c +++ b/qemu/target-m68k/unicorn.c @@ -6,14 +6,8 @@ #include "sysemu/cpus.h" #include "unicorn.h" #include "cpu.h" - #include "unicorn_common.h" - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static void m68k_set_pc(struct uc_struct *uc, uint64_t address) @@ -51,12 +45,6 @@ int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value) return 0; } - -#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) -#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-mips/unicorn.c b/qemu/target-mips/unicorn.c index 6085a259..7740d0d9 100644 --- a/qemu/target-mips/unicorn.c +++ b/qemu/target-mips/unicorn.c @@ -6,15 +6,8 @@ #include "sysemu/cpus.h" #include "unicorn.h" #include "cpu.h" - #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static uint64_t mips_mem_redirect(uint64_t address) @@ -64,12 +57,6 @@ int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value) return 0; } - -#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) -#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index e612457b..3775776a 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -7,13 +7,7 @@ #include "unicorn.h" #include "cpu.h" #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static bool sparc_stop_interrupt(int intno) diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index e9257b75..ef99b5ab 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -7,13 +7,7 @@ #include "unicorn.h" #include "cpu.h" #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static bool sparc_stop_interrupt(int intno) From feb7b8e1ae56f4290da6c5372c2d6b3d93c8ea3f Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Mar 2016 23:14:25 +0800 Subject: [PATCH 24/41] travis: support OSX & Linux --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index b80f07f3..4d077ff9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,3 +7,6 @@ script: compiler: - clang - gcc +os: + - linux + - osx From cf08670a1c1d16b53637c6bcf0c805a5e29cf180 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Mar 2016 23:25:29 +0800 Subject: [PATCH 25/41] Travis: install dependencies for OSX --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4d077ff9..9a3ebd3f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,9 @@ language: c sudo: false before_install: - export LD_LIBRARY_PATH=`pwd`/samples/:$LD_LIBRARY_PATH + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew pkg-config glib; fi + script: - ./make.sh compiler: From 3ebb5d3a2e145aa9355e4c1e0349f8a181236281 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Mar 2016 23:33:07 +0800 Subject: [PATCH 26/41] travis: fix brew install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9a3ebd3f..ffc13784 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ sudo: false before_install: - export LD_LIBRARY_PATH=`pwd`/samples/:$LD_LIBRARY_PATH - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew pkg-config glib; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install pkg-config glib; fi script: - ./make.sh From 1ddebc7304dd4d0a91ad410eedc7e41bae8d46fa Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Mar 2016 23:41:03 +0800 Subject: [PATCH 27/41] travis: do not need to install pkg-config --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ffc13784..39c18b8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ sudo: false before_install: - export LD_LIBRARY_PATH=`pwd`/samples/:$LD_LIBRARY_PATH - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install pkg-config glib; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install glib; fi script: - ./make.sh From 1087ba9dea62ef0e6c2b2e7e147b1dab9b46c2d2 Mon Sep 17 00:00:00 2001 From: Nicolas PLANEL Date: Fri, 4 Mar 2016 15:26:06 +1100 Subject: [PATCH 28/41] [query] add UC_QUERY_PAGE_SIZE uc_query helper Return the current page size used by the current arch. Useful to call uc_mem_map() with memory/size aligned. Signed-off-by: Nicolas PLANEL --- include/unicorn/unicorn.h | 1 + tests/unit/test_mem_map.c | 10 ++++++++++ uc.c | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 35e745ca..23a17a4f 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -262,6 +262,7 @@ typedef struct uc_mem_region { typedef enum uc_query_type { // Dynamically query current hardware mode. UC_QUERY_MODE = 1, + UC_QUERY_PAGE_SIZE, } uc_query_type; /* diff --git a/tests/unit/test_mem_map.c b/tests/unit/test_mem_map.c index 303a370b..9c2b9892 100644 --- a/tests/unit/test_mem_map.c +++ b/tests/unit/test_mem_map.c @@ -158,6 +158,15 @@ static void test_strange_map(void **state) uc_mem_unmap(uc, 0x0,0x1000); } +static void test_query_page_size(void **state) +{ + uc_engine *uc = *state; + + size_t page_size; + uc_assert_success(uc_query(uc, UC_QUERY_PAGE_SIZE, &page_size)); + assert_int_equal(4096, page_size); +} + void write(uc_engine* uc, uint64_t addr, uint64_t len){ uint8_t* buff = alloca(len); memset(buff,0,len); @@ -220,6 +229,7 @@ int main(void) { test(test_unmap_double_map), test(test_overlap_unmap_double_map), test(test_strange_map), + test(test_query_page_size), }; #undef test return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/uc.c b/uc.c index 298d21e0..ce9f121d 100644 --- a/uc.c +++ b/uc.c @@ -1094,6 +1094,11 @@ uint32_t uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count) UNICORN_EXPORT uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result) { + if (type == UC_QUERY_PAGE_SIZE) { + *result = uc->target_page_size; + return UC_ERR_OK; + } + switch(uc->arch) { case UC_ARCH_ARM: return uc->query(uc, type, result); From 2031f7cbdd64cb5a2bc5e980574710ed1ff2d5b9 Mon Sep 17 00:00:00 2001 From: Nicolas PLANEL Date: Fri, 4 Mar 2016 15:29:32 +1100 Subject: [PATCH 29/41] [query] update bindings UC_QUERY_PAGE_SIZE Signed-off-by: Nicolas PLANEL --- bindings/dotnet/UnicornManaged/Const/Common.fs | 1 + bindings/go/unicorn/unicorn_const.go | 1 + bindings/java/unicorn/UnicornConst.java | 1 + bindings/python/unicorn/unicorn_const.py | 1 + 4 files changed, 4 insertions(+) diff --git a/bindings/dotnet/UnicornManaged/Const/Common.fs b/bindings/dotnet/UnicornManaged/Const/Common.fs index 0f42d3d7..ef9004e6 100644 --- a/bindings/dotnet/UnicornManaged/Const/Common.fs +++ b/bindings/dotnet/UnicornManaged/Const/Common.fs @@ -93,6 +93,7 @@ module Common = let UC_HOOK_MEM_INVALID = 1008 let UC_HOOK_MEM_VALID = 7168 let UC_QUERY_MODE = 1 + let UC_QUERY_PAGE_SIZE = 2 let UC_PROT_NONE = 0 let UC_PROT_READ = 1 diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 1faff075..01b62fca 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -88,6 +88,7 @@ const ( HOOK_MEM_INVALID = 1008 HOOK_MEM_VALID = 7168 QUERY_MODE = 1 + QUERY_PAGE_SIZE = 2 PROT_NONE = 0 PROT_READ = 1 diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index 64b52236..033267ae 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -90,6 +90,7 @@ public interface UnicornConst { public static final int UC_HOOK_MEM_INVALID = 1008; public static final int UC_HOOK_MEM_VALID = 7168; public static final int UC_QUERY_MODE = 1; + public static final int UC_QUERY_PAGE_SIZE = 2; public static final int UC_PROT_NONE = 0; public static final int UC_PROT_READ = 1; diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index bdb8ed01..89ccd919 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -86,6 +86,7 @@ UC_HOOK_MEM_FETCH_INVALID = 576 UC_HOOK_MEM_INVALID = 1008 UC_HOOK_MEM_VALID = 7168 UC_QUERY_MODE = 1 +UC_QUERY_PAGE_SIZE = 2 UC_PROT_NONE = 0 UC_PROT_READ = 1 From bf7dc4293b7711a89938996c325439255bc89061 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 6 Mar 2016 17:27:50 +0800 Subject: [PATCH 30/41] python: README -> README.md in setup.py --- bindings/python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 66ea8ab0..8c44f470 100755 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -63,7 +63,7 @@ def copy_sources(): src.extend(glob.glob("../../Makefile")) src.extend(glob.glob("../../LICENSE*")) - src.extend(glob.glob("../../README")) + src.extend(glob.glob("../../README.md")) src.extend(glob.glob("../../*.TXT")) src.extend(glob.glob("../../RELEASE_NOTES")) src.extend(glob.glob("../../make.sh")) From 0950f2e18b54acc20062bbd69e21a0f7e31204ce Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 6 Mar 2016 17:28:32 +0800 Subject: [PATCH 31/41] python: 0.9 -> 1.0 in setup.py --- bindings/python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 8c44f470..6b98bae5 100755 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -24,7 +24,7 @@ PKG_NAME = 'unicorn' if os.path.exists(PATH_LIB64) and os.path.exists(PATH_LIB32): PKG_NAME = 'unicorn-windows' -VERSION = '0.9' +VERSION = '1.0' SYSTEM = sys.platform # virtualenv breaks import, but get_python_lib() will work. From eb5a7624526cece15e43353e73b67e5f334abefe Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 6 Mar 2016 21:21:39 +0800 Subject: [PATCH 32/41] python: add __version__ --- bindings/python/unicorn/__init__.py | 2 +- bindings/python/unicorn/unicorn.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bindings/python/unicorn/__init__.py b/bindings/python/unicorn/__init__.py index 3f63904c..9d2b717c 100644 --- a/bindings/python/unicorn/__init__.py +++ b/bindings/python/unicorn/__init__.py @@ -1,4 +1,4 @@ # Unicorn Python bindings, by Nguyen Anh Quynnh from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const from .unicorn_const import * -from .unicorn import Uc, uc_version, uc_arch_supported, version_bind, debug, UcError +from .unicorn import Uc, uc_version, uc_arch_supported, version_bind, debug, UcError, __version__ diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 3d784368..989d985f 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -81,6 +81,8 @@ if _found == False: raise ImportError("ERROR: fail to load the dynamic library.") +__version__ = "%s.%s" %(UC_API_MAJOR, UC_API_MINOR) + # setup all the function prototype def _setup_prototype(lib, fname, restype, *argtypes): getattr(lib, fname).restype = restype From 338fb0e81b18b4909d969207ca4131ddb3ebc9ba Mon Sep 17 00:00:00 2001 From: Spl3en Date: Mon, 7 Mar 2016 17:52:08 +0100 Subject: [PATCH 33/41] Fix a typo in uc_hook_add documentation. --- include/unicorn/unicorn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 23a17a4f..65d6aa53 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -459,7 +459,7 @@ uc_err uc_emu_stop(uc_engine *uc); @user_data: user-defined data. This will be passed to callback function in its last argument @user_data @begin: start address of the area where the callback is effect (inclusive) - @begin: end address of the area where the callback is effect (inclusive) + @end: end address of the area where the callback is effect (inclusive) NOTE 1: the callback is called only if related address is in range [@begin, @end] NOTE 2: if @begin > @end, callback is called whenever this hook type is triggered @...: variable arguments (depending on @type) From 9d9056c4747c404f6c460e8c779cda407aff1df7 Mon Sep 17 00:00:00 2001 From: Hoang-Vu Dang Date: Mon, 7 Mar 2016 12:22:20 -0600 Subject: [PATCH 34/41] Add a license for regression tests --- tests/regress/LICENSE | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/regress/LICENSE diff --git a/tests/regress/LICENSE b/tests/regress/LICENSE new file mode 100644 index 00000000..dceeb48a --- /dev/null +++ b/tests/regress/LICENSE @@ -0,0 +1,30 @@ +This is the software license for Unicorn regression tests. The regression tests +are written by several Unicorn contributors (See CREDITS.TXT) and maintained by +Hoang-Vu Dang + +Copyright (c) 2015, Unicorn contributers +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the developer(s) nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. From 9c91a6ec28744d5140fd44d6de6af9ab7d190b93 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 8 Mar 2016 08:55:55 +0800 Subject: [PATCH 35/41] fix a typo in tests/regress/LICENSE --- tests/regress/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regress/LICENSE b/tests/regress/LICENSE index dceeb48a..dd85900f 100644 --- a/tests/regress/LICENSE +++ b/tests/regress/LICENSE @@ -2,7 +2,7 @@ This is the software license for Unicorn regression tests. The regression tests are written by several Unicorn contributors (See CREDITS.TXT) and maintained by Hoang-Vu Dang -Copyright (c) 2015, Unicorn contributers +Copyright (c) 2015, Unicorn contributors All rights reserved. Redistribution and use in source and binary forms, with or without From 86e2127af16dd332221d17bf73401ca4800485d5 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 8 Mar 2016 12:52:13 +0800 Subject: [PATCH 36/41] add Appveyor CI --- appveyor.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..c854f49e --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,27 @@ +version: 1.0-{build} + +platform: + - x64 + +environment: + global: + MSYS2_BASEVER: 20150512 + MSYS2_ARCH: x86_64 + matrix: + - HOST_ARCH_ARG: --host=x86_64-w64-mingw32 + ADD_PATH: /mingw64/bin + - HOST_ARCH_ARG: --host=i686-w64-mingw32 + ADD_PATH: /mingw32/bin + - HOST_ARCH_ARG: --enable-msvc + ADD_PATH: /mingw64/bin + +install: + - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" + - appveyor DownloadFile "http://kent.dl.sourceforge.net/project/msys2/Base/%MSYS2_ARCH%/msys2-base-%MSYS2_ARCH%-%MSYS2_BASEVER%.tar.xz" -FileName "msys2.tar.xz" + - 7z x msys2.tar.xz + - 7z x msys2.tar > NUL + - msys64\usr\bin\bash -lc "" + - msys64\usr\bin\bash -lc "for i in {1..3}; do pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain && break || sleep 15; done" + +build_script: + - ./make.sh cross-win64 From 861d5e1ad83501b83d4c61bc42041a34fb0bf76c Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 8 Mar 2016 13:06:16 +0800 Subject: [PATCH 37/41] fix appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index c854f49e..db1e0861 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,4 +24,4 @@ install: - msys64\usr\bin\bash -lc "for i in {1..3}; do pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain && break || sleep 15; done" build_script: - - ./make.sh cross-win64 + - make.sh cross-win64 From 276775f5cca809f54c90849a6356a350e6431d81 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 8 Mar 2016 13:41:24 +0800 Subject: [PATCH 38/41] more fix for Appveyor CI --- README.md | 1 + appveyor.yml | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 0d8e7558..f57b1df6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ Unicorn Engine ============== [![Build Status](https://travis-ci.org/unicorn-engine/unicorn.svg?branch=master)](https://travis-ci.org/unicorn-engine/unicorn) +[![Build status](https://ci.appveyor.com/api/projects/status/kojr7bald748ba2x/branch/master?svg=true)](https://ci.appveyor.com/project/aquynh/unicorn/branch/master) Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framework based on [QEMU](http://qemu.org). diff --git a/appveyor.yml b/appveyor.yml index db1e0861..8d1c61e7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,8 +12,6 @@ environment: ADD_PATH: /mingw64/bin - HOST_ARCH_ARG: --host=i686-w64-mingw32 ADD_PATH: /mingw32/bin - - HOST_ARCH_ARG: --enable-msvc - ADD_PATH: /mingw64/bin install: - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" From 26261be2445c7c91917b981736913b76487d5084 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 9 Mar 2016 09:35:00 +0800 Subject: [PATCH 39/41] improve Appveyor config --- appveyor.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 8d1c61e7..790d37c8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,6 @@ platform: environment: global: - MSYS2_BASEVER: 20150512 MSYS2_ARCH: x86_64 matrix: - HOST_ARCH_ARG: --host=x86_64-w64-mingw32 @@ -15,11 +14,7 @@ environment: install: - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" - - appveyor DownloadFile "http://kent.dl.sourceforge.net/project/msys2/Base/%MSYS2_ARCH%/msys2-base-%MSYS2_ARCH%-%MSYS2_BASEVER%.tar.xz" -FileName "msys2.tar.xz" - - 7z x msys2.tar.xz - - 7z x msys2.tar > NUL - - msys64\usr\bin\bash -lc "" - - msys64\usr\bin\bash -lc "for i in {1..3}; do pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain && break || sleep 15; done" + - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain" build_script: - make.sh cross-win64 From dca32a875e14e35403c62c82c7c15f46c5ef450c Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 9 Mar 2016 09:54:09 +0800 Subject: [PATCH 40/41] appveyor: try without pacman installs --- appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 790d37c8..ffa5aa42 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,7 +14,6 @@ environment: install: - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" - - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain" build_script: - make.sh cross-win64 From 2cfe6fb9c0b74fa5e129b20819afbe7e05f4ce8f Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 9 Mar 2016 11:53:59 +0800 Subject: [PATCH 41/41] appveyor: no need to initialize MSVC env for Msys2 --- appveyor.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index ffa5aa42..cbc1c215 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,8 +12,5 @@ environment: - HOST_ARCH_ARG: --host=i686-w64-mingw32 ADD_PATH: /mingw32/bin -install: - - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" - build_script: - make.sh cross-win64