diff --git a/.gitignore b/.gitignore index 3fdb76f7..6831c5b6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ *.o *.a *.dSYM +*.so +*.so.* qemu/config-all-devices.mak diff --git a/COMPILE.TXT b/COMPILE.TXT index c14facd8..69edf581 100644 --- a/COMPILE.TXT +++ b/COMPILE.TXT @@ -98,11 +98,15 @@ Unicorn requires few dependent packages as follows. $ ./make.sh + - Unicorn requires Python 2.x to compile. If Python 2.x is not the default + Python interpreter, ensure that the appropriate option is set: + + $ UNICORN_QEMU_FLAGS="--python=/path/to/python2" ./make.sh + - To cross-compile Unicorn on 64-bit OS to target 32-bit binary, run: $ ./make.sh nix32 - After compiling, install Unicorn with: $ sudo ./make.sh install diff --git a/Makefile b/Makefile index 4ce64736..3a97a6a1 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,8 @@ LIBRARY = $(BLDIR)/$(LIBNAME).$(EXT) else ifeq ($(IS_CYGWIN),1) LIBRARY = $(BLDIR)/$(LIBNAME).$(EXT) else # *nix -LIBRARY = $(BLDIR)/lib$(LIBNAME).$(EXT) +LIBRARY = $(BLDIR)/lib$(LIBNAME).$(VERSION_EXT) +LIBRARY_SYMLINK = $(BLDIR)/lib$(LIBNAME).$(EXT) endif endif @@ -229,6 +230,9 @@ ifeq ($(V),0) else $(CC) $(CFLAGS) $($(LIBNAME)_LDFLAGS) -shared $^ -o $(LIBRARY) $(GLIB) -lm endif +ifneq (,$(LIBRARY_SYMLINK)) + @ln -sf $(LIBRARY) $(LIBRARY_SYMLINK) +endif endif $(ARCHIVE): $(UC_TARGET_OBJ) uc.o hook.o @@ -262,8 +266,7 @@ ifeq ($(UNICORN_SHARED),yes) $(INSTALL_LIB) $(LIBRARY) $(LIBDIR) ifneq ($(VERSION_EXT),) cd $(LIBDIR) && \ - mv lib$(LIBNAME).$(EXT) lib$(LIBNAME).$(VERSION_EXT) && \ - ln -s lib$(LIBNAME).$(VERSION_EXT) lib$(LIBNAME).$(EXT) + ln -sf lib$(LIBNAME).$(VERSION_EXT) lib$(LIBNAME).$(EXT) endif endif ifeq ($(UNICORN_STATIC),yes) diff --git a/bindings/go/unicorn/hook.go b/bindings/go/unicorn/hook.go index 3176df9f..13aba755 100644 --- a/bindings/go/unicorn/hook.go +++ b/bindings/go/unicorn/hook.go @@ -19,43 +19,43 @@ type HookData struct { type Hook uint64 //export hookCode -func hookCode(handle *C.uc_engine, addr uint64, size uint32, user unsafe.Pointer) { +func hookCode(handle unsafe.Pointer, addr uint64, size uint32, user unsafe.Pointer) { hook := (*HookData)(user) hook.Callback.(func(Unicorn, uint64, uint32))(hook.Uc, uint64(addr), uint32(size)) } //export hookMemInvalid -func hookMemInvalid(handle *C.uc_engine, typ C.uc_mem_type, addr uint64, size int, value int64, user unsafe.Pointer) bool { +func hookMemInvalid(handle unsafe.Pointer, typ C.uc_mem_type, addr uint64, size int, value int64, user unsafe.Pointer) bool { hook := (*HookData)(user) return hook.Callback.(func(Unicorn, int, uint64, int, int64) bool)(hook.Uc, int(typ), addr, size, value) } //export hookMemAccess -func hookMemAccess(handle *C.uc_engine, typ C.uc_mem_type, addr uint64, size int, value int64, user unsafe.Pointer) { +func hookMemAccess(handle unsafe.Pointer, typ C.uc_mem_type, addr uint64, size int, value int64, user unsafe.Pointer) { hook := (*HookData)(user) hook.Callback.(func(Unicorn, int, uint64, int, int64))(hook.Uc, int(typ), addr, size, value) } //export hookInterrupt -func hookInterrupt(handle *C.uc_engine, intno uint32, user unsafe.Pointer) { +func hookInterrupt(handle unsafe.Pointer, intno uint32, user unsafe.Pointer) { hook := (*HookData)(user) hook.Callback.(func(Unicorn, uint32))(hook.Uc, intno) } //export hookX86In -func hookX86In(handle *C.uc_engine, port, size uint32, user unsafe.Pointer) uint32 { +func hookX86In(handle unsafe.Pointer, port, size uint32, user unsafe.Pointer) uint32 { hook := (*HookData)(user) return hook.Callback.(func(Unicorn, uint32, uint32) uint32)(hook.Uc, port, size) } //export hookX86Out -func hookX86Out(handle *C.uc_engine, port, size, value uint32, user unsafe.Pointer) { +func hookX86Out(handle unsafe.Pointer, port, size, value uint32, user unsafe.Pointer) { hook := (*HookData)(user) hook.Callback.(func(Unicorn, uint32, uint32, uint32))(hook.Uc, port, size, value) } //export hookX86Syscall -func hookX86Syscall(handle *C.uc_engine, user unsafe.Pointer) { +func hookX86Syscall(handle unsafe.Pointer, user unsafe.Pointer) { hook := (*HookData)(user) hook.Callback.(func(Unicorn))(hook.Uc) } diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 37e744b3..acac9638 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -260,22 +260,22 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip); break; case UC_X86_REG_CS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_CS].base; + *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_CS].base; break; case UC_X86_REG_DS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].base; + *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].base; break; case UC_X86_REG_SS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].base; + *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].base; break; case UC_X86_REG_ES: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].base; + *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].base; break; case UC_X86_REG_FS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].base; + *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].base; break; case UC_X86_REG_GS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].base; + *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].base; break; } break; @@ -412,22 +412,22 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip); break; case UC_X86_REG_CS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_CS].base; + *(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_CS].base; break; case UC_X86_REG_DS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].base; + *(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].base; break; case UC_X86_REG_SS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].base; + *(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].base; break; case UC_X86_REG_ES: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].base; + *(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].base; break; case UC_X86_REG_FS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].base; + *(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].base; break; case UC_X86_REG_GS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].base; + *(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].base; break; case UC_X86_REG_R8: *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[8]); @@ -660,22 +660,22 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) WRITE_WORD(X86_CPU(uc, mycpu)->env.eip, *(uint16_t *)value); break; case UC_X86_REG_CS: - X86_CPU(uc, mycpu)->env.segs[R_CS].base = *(uint16_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_CS].base = *(uint32_t *)value; break; case UC_X86_REG_DS: - X86_CPU(uc, mycpu)->env.segs[R_DS].base = *(uint16_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_DS].base = *(uint32_t *)value; break; case UC_X86_REG_SS: - X86_CPU(uc, mycpu)->env.segs[R_SS].base = *(uint16_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_SS].base = *(uint32_t *)value; break; case UC_X86_REG_ES: - X86_CPU(uc, mycpu)->env.segs[R_ES].base = *(uint16_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_ES].base = *(uint32_t *)value; break; case UC_X86_REG_FS: - X86_CPU(uc, mycpu)->env.segs[R_FS].base = *(uint16_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_FS].base = *(uint32_t *)value; break; case UC_X86_REG_GS: - X86_CPU(uc, mycpu)->env.segs[R_GS].base = *(uint16_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_GS].base = *(uint32_t *)value; break; } break; @@ -812,22 +812,22 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) WRITE_WORD(X86_CPU(uc, mycpu)->env.eip, *(uint16_t *)value); break; case UC_X86_REG_CS: - X86_CPU(uc, mycpu)->env.segs[R_CS].base = *(uint16_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_CS].base = *(uint64_t *)value; break; case UC_X86_REG_DS: - X86_CPU(uc, mycpu)->env.segs[R_DS].base = *(uint16_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_DS].base = *(uint64_t *)value; break; case UC_X86_REG_SS: - X86_CPU(uc, mycpu)->env.segs[R_SS].base = *(uint16_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_SS].base = *(uint64_t *)value; break; case UC_X86_REG_ES: - X86_CPU(uc, mycpu)->env.segs[R_ES].base = *(uint16_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_ES].base = *(uint64_t *)value; break; case UC_X86_REG_FS: - X86_CPU(uc, mycpu)->env.segs[R_FS].base = *(uint16_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_FS].base = *(uint64_t *)value; break; case UC_X86_REG_GS: - X86_CPU(uc, mycpu)->env.segs[R_GS].base = *(uint16_t *)value; + X86_CPU(uc, mycpu)->env.segs[R_GS].base = *(uint64_t *)value; break; case UC_X86_REG_R8: X86_CPU(uc, mycpu)->env.regs[8] = *(uint64_t *)value; diff --git a/tests/regress/Makefile b/tests/regress/Makefile index e03c27e9..49010ebc 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -8,6 +8,7 @@ TESTS += ro_mem_test nr_mem_test TESTS += timeout_segfault TESTS += rep_movsb TESTS += mem_unmap +TESTS += mem_double_unmap TESTS += mem_protect TESTS += mem_exec diff --git a/tests/regress/callback-pc.py b/tests/regress/callback-pc.py index 3edc67e6..77f4e5ab 100755 --- a/tests/regress/callback-pc.py +++ b/tests/regress/callback-pc.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # reg_write() can't modify PC from within trace callbacks -# Pull Request #4 +# issue #210 from __future__ import print_function from unicorn import * @@ -30,11 +30,7 @@ def hook_block(uc, address, size, user_data): class CallBackPCTest(regress.RegressTest): - def runTest(self): - self.instruction_trace_test() - - # set up emulation - def instruction_trace_test(self): + def test_instruction_trace(self): try: # initialize emulator in ARM's Thumb mode mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB) @@ -51,14 +47,44 @@ class CallBackPCTest(regress.RegressTest): # tracing all instructions with customized callback mu.hook_add(UC_HOOK_CODE, hook_code, user_data=mu) - # tracing all basic blocks with customized callback - mu.hook_add(UC_HOOK_BLOCK, hook_block, user_data=mu) + # emulate one instruction + mu.emu_start(BASE_ADDRESS, BASE_ADDRESS + len(THUMB_CODE), count=1) - # emulate machine code in infinite time - mu.emu_start(BASE_ADDRESS, BASE_ADDRESS + len(THUMB_CODE)) + # the instruction trace callback set PC to 0xffffffff, so at this + # point, the PC value should be 0xffffffff. + pc = mu.reg_read(UC_ARM_REG_PC) + self.assertEqual(pc, 0xffffffff, "PC not set to 0xffffffff by instruction trace callback") except UcError as e: - assertFalse(0, "ERROR: %s" % e) + self.assertFalse(0, "ERROR: %s" % e) + + def test_block_trace(self): + try: + # initialize emulator in ARM's Thumb mode + mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB) + + # map some memory + mu.mem_map(BASE_ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(BASE_ADDRESS, THUMB_CODE) + + # setup stack + mu.reg_write(UC_ARM_REG_SP, BASE_ADDRESS + 2 * 1024 * 1024) + + # trace blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, hook_block, user_data=mu) + + # emulate one instruction + mu.emu_start(BASE_ADDRESS, BASE_ADDRESS + len(THUMB_CODE), count=1) + + # the block callback set PC to 0xffffffff, so at this point, the PC + # value should be 0xffffffff. + pc = mu.reg_read(UC_ARM_REG_PC) + self.assertEqual(pc, 0xffffffff, "PC not set to 0xffffffff by block callback") + + except UcError as e: + self.assertFalse(0, "ERROR: %s" % e) if __name__ == '__main__': regress.main() diff --git a/tests/regress/mem_double_unmap.c b/tests/regress/mem_double_unmap.c new file mode 100644 index 00000000..3373a5cc --- /dev/null +++ b/tests/regress/mem_double_unmap.c @@ -0,0 +1,51 @@ +#define __STDC_FORMAT_MACROS +#include +#include +#include +#include +#include +#include + +#include + +int main(int argc, char **argv, char **envp) +{ + uc_engine *uc; + uc_hook trace1, trace2; + uc_err err; + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + if (err) { + printf("not ok - Failed on uc_open() with error returned: %u\n", err); + return -1; + } + + uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL); + if (err) { + printf("not ok - Failed on uc_mem_map() with error returned: %u\n", err); + return -1; + } + + uc_mem_map(uc, 0x4000, 0x1000, UC_PROT_ALL); + if (err) { + printf("not ok - Failed on uc_mem_map() with error returned: %u\n", err); + return -1; + } + + err = uc_mem_unmap(uc, 0x4000, 0x1000); + if (err) { + printf("not ok - Failed on uc_mem_unmap() with error returned: %u\n", err); + return -1; + } + + err = uc_mem_unmap(uc, 0x4000, 0x1000); + if (!err) { + printf("not ok - second unmap succeeded\n"); + return -1; + } + + printf("Tests OK\n"); + uc_close(uc); + return 0; +} diff --git a/uc.c b/uc.c index bb45fa5e..02c157bc 100644 --- a/uc.c +++ b/uc.c @@ -88,7 +88,7 @@ const char *uc_strerror(uc_err code) case UC_ERR_FETCH_PROT: return "Fetch from non-executable memory (UC_ERR_FETCH_PROT)"; case UC_ERR_ARG: - return "Invalid argumet (UC_ERR_ARG)"; + return "Invalid argument (UC_ERR_ARG)"; case UC_ERR_READ_UNALIGNED: return "Read from unaligned memory (UC_ERR_READ_UNALIGNED)"; case UC_ERR_WRITE_UNALIGNED: @@ -814,7 +814,7 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) // try with the cache index first i = uc->mapped_block_cache_index; - if (address >= uc->mapped_blocks[i]->addr && address < uc->mapped_blocks[i]->end) + if (i < uc->mapped_block_count && address >= uc->mapped_blocks[i]->addr && address < uc->mapped_blocks[i]->end) return uc->mapped_blocks[i]; for(i = 0; i < uc->mapped_block_count; i++) {