From 4ea3a3ebbf3d633952309d7a939c05b710b77aa2 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 08:00:00 -0400 Subject: [PATCH 01/64] change uch to uc_struct (header files) --- include/uc_priv.h | 6 ++-- include/unicorn/unicorn.h | 70 ++++++++++++++++++++------------------- include/unicorn/x86.h | 2 +- 3 files changed, 40 insertions(+), 38 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 2703627c..2d075267 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -24,10 +24,10 @@ typedef struct ModuleEntry { typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList; // return 0 on success, -1 on failure -typedef int (*reg_read_t)(uch handle, unsigned int regid, void *value); -typedef int (*reg_write_t)(uch handle, unsigned int regid, const void *value); +typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int regid, void *value); +typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int regid, const void *value); -typedef void (*reg_reset_t)(uch handle); +typedef void (*reg_reset_t)(struct uc_struct *uc); typedef bool (*uc_write_mem_t)(AddressSpace *as, hwaddr addr, const uint8_t *buf, int len); diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 66de81eb..9fd38435 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -19,6 +19,8 @@ extern "C" { #include "platform.h" +struct uc_struct; + // Handle to use with all APIs typedef size_t uch; @@ -123,24 +125,24 @@ typedef enum uc_err { // @address: address where the code is being executed // @size: size of machine instruction(s) being executed, or 0 when size is unknown // @user_data: user data passed to tracing APIs. -typedef void (*uc_cb_hookcode_t)(uch handle, uint64_t address, uint32_t size, void *user_data); +typedef void (*uc_cb_hookcode_t)(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data); // Callback function for tracing interrupts (for uc_hook_intr()) // @intno: interrupt number // @user_data: user data passed to tracing APIs. -typedef void (*uc_cb_hookintr_t)(uch handle, uint32_t intno, void *user_data); +typedef void (*uc_cb_hookintr_t)(struct uc_struct *uc, uint32_t intno, void *user_data); // Callback function for tracing IN instruction of X86 // @port: port number // @size: data size (1/2/4) to be read from this port // @user_data: user data passed to tracing APIs. -typedef uint32_t (*uc_cb_insn_in_t)(uch handle, uint32_t port, int size, void *user_data); +typedef uint32_t (*uc_cb_insn_in_t)(struct uc_struct *uc, uint32_t port, int size, void *user_data); // x86's handler for OUT // @port: port number // @size: data size (1/2/4) to be written to this port // @value: data value to be written to this port -typedef void (*uc_cb_insn_out_t)(uch handle, uint32_t port, int size, uint32_t value, void *user_data); +typedef void (*uc_cb_insn_out_t)(struct uc_struct *uc, uint32_t port, int size, uint32_t value, void *user_data); // All type of memory accesses for UC_HOOK_MEM_* typedef enum uc_mem_type { @@ -167,7 +169,7 @@ typedef enum uc_hook_t { // @size: size of data being read or written // @value: value of data being written to memory, or irrelevant if type = READ. // @user_data: user data passed to tracing APIs -typedef void (*uc_cb_hookmem_t)(uch handle, uc_mem_type type, +typedef void (*uc_cb_hookmem_t)(struct uc_struct *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data); // Callback function for handling memory events (for UC_HOOK_MEM_INVALID) @@ -177,7 +179,7 @@ typedef void (*uc_cb_hookmem_t)(uch handle, uc_mem_type type, // @value: value of data being written to memory, or irrelevant if type = READ. // @user_data: user data passed to tracing APIs // @return: return true to continue, or false to stop program (due to invalid memory). -typedef bool (*uc_cb_eventmem_t)(uch handle, uc_mem_type type, +typedef bool (*uc_cb_eventmem_t)(struct uc_struct *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data); @@ -214,43 +216,43 @@ bool uc_arch_supported(uc_arch arch); /* - Initialize UC handle: this must be done before any usage of UC. + Create new instance of unicorn engine. @arch: architecture type (UC_ARCH_*) @mode: hardware mode. This is combined of UC_MODE_* - @handle: pointer to handle, which will be updated at return time + @uc: pointer to struct uc_struct, which will be updated at return time @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum for detailed error). */ UNICORN_EXPORT -uc_err uc_open(uc_arch arch, uc_mode mode, uch *handle); +uc_err uc_open(uc_arch arch, uc_mode mode, struct uc_struct **uc); /* - Close UC handle: MUST do to release the handle when it is not used anymore. + Close UC instance: MUST do to release the handle when it is not used anymore. NOTE: this must be called only when there is no longer usage of Unicorn. The reason is the this API releases some cached memory, thus access to any Unicorn API after uc_close() might crash your application. - After this, @handle is invalid, and nolonger usable. + After this, @uc is invalid, and nolonger usable. - @handle: pointer to a handle returned by uc_open() + @uc: pointer to a handle returned by uc_open() @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum for detailed error). */ UNICORN_EXPORT -uc_err uc_close(uch *handle); +uc_err uc_close(struct uc_struct *uc); /* Report the last error number when some API function fail. Like glibc's errno, uc_errno might not retain its old value once accessed. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @return: error code of uc_err enum type (UC_ERR_*, see above) */ UNICORN_EXPORT -uc_err uc_errno(uch handle); +uc_err uc_errno(struct uc_struct *uc); /* Return a string describing given error code. @@ -266,7 +268,7 @@ const char *uc_strerror(uc_err code); /* Write to register. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @regid: register ID that is to be modified. @value: pointer to the value that will set to register @regid @@ -274,12 +276,12 @@ const char *uc_strerror(uc_err code); for detailed error). */ UNICORN_EXPORT -uc_err uc_reg_write(uch handle, int regid, const void *value); +uc_err uc_reg_write(struct uc_struct *uc, int regid, const void *value); /* Read register value. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @regid: register ID that is to be retrieved. @value: pointer to a variable storing the register value. @@ -287,12 +289,12 @@ uc_err uc_reg_write(uch handle, int regid, const void *value); for detailed error). */ UNICORN_EXPORT -uc_err uc_reg_read(uch handle, int regid, void *value); +uc_err uc_reg_read(struct uc_struct *uc, int regid, void *value); /* Write to a range of bytes in memory. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @address: starting memory address of bytes to set. @bytes: pointer to a variable containing data to be written to memory. @size: size of memory to write to. @@ -303,12 +305,12 @@ uc_err uc_reg_read(uch handle, int regid, void *value); for detailed error). */ UNICORN_EXPORT -uc_err uc_mem_write(uch handle, uint64_t address, const uint8_t *bytes, size_t size); +uc_err uc_mem_write(struct uc_struct *uc, uint64_t address, const uint8_t *bytes, size_t size); /* Read a range of bytes in memory. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @address: starting memory address of bytes to get. @bytes: pointer to a variable containing data copied from memory. @size: size of memory to read. @@ -319,12 +321,12 @@ uc_err uc_mem_write(uch handle, uint64_t address, const uint8_t *bytes, size_t s for detailed error). */ UNICORN_EXPORT -uc_err uc_mem_read(uch handle, uint64_t address, uint8_t *bytes, size_t size); +uc_err uc_mem_read(struct uc_struct *uc, uint64_t address, uint8_t *bytes, size_t size); /* Emulate machine code in a specific duration of time. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @begin: address where emulation starts @until: address where emulation stops (i.e when this address is hit) @timeout: duration to emulate the code (in microseconds). When this value is 0, @@ -336,26 +338,26 @@ uc_err uc_mem_read(uch handle, uint64_t address, uint8_t *bytes, size_t size); for detailed error). */ UNICORN_EXPORT -uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout, size_t count); +uc_err uc_emu_start(struct uc_struct *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count); /* Stop emulation (which was started by uc_emu_start() API. This is typically called from callback functions registered via tracing APIs. NOTE: for now, this will stop the execution only after the current block. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum for detailed error). */ UNICORN_EXPORT -uc_err uc_emu_stop(uch handle); +uc_err uc_emu_stop(struct uc_struct *uc); /* Register callback for a hook event. The callback will be run when the hook event is hit. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @h2: hook handle returned from this registration. To be used in uc_hook_del() API @type: hook type @callback: callback to be run when instruction is hit @@ -367,28 +369,28 @@ uc_err uc_emu_stop(uch handle); for detailed error). */ UNICORN_EXPORT -uc_err uc_hook_add(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, ...); +uc_err uc_hook_add(struct uc_struct *uc, uch *h2, uc_hook_t type, void *callback, void *user_data, ...); /* Unregister (remove) a hook callback. This API removes the hook callback registered by uc_hook_add(). NOTE: this should be called only when you no longer want to trace. - After this, @hhandle is invalid, and nolonger usable. + After this, @h2 is invalid, and nolonger usable. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @h2: handle returned by uc_hook_add() @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_del(uch handle, uch *h2); +uc_err uc_hook_del(struct uc_struct *uc, uch *h2); /* Map memory in for emulation. This API adds a memory region that can be used by emulation. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @address: starting address of the new memory region to be mapped in. This address must be aligned to 4KB, or this will return with UC_ERR_MAP error. @size: size of the new memory region to be mapped in. @@ -398,7 +400,7 @@ uc_err uc_hook_del(uch handle, uch *h2); for detailed error). */ UNICORN_EXPORT -uc_err uc_mem_map(uch handle, uint64_t address, size_t size); +uc_err uc_mem_map(struct uc_struct *uc, uint64_t address, size_t size); #ifdef __cplusplus } diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index 4ee6945e..b279de58 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -10,7 +10,7 @@ extern "C" { // Callback function for tracing SYSCALL/SYSENTER (for uc_hook_intr()) // @user_data: user data passed to tracing APIs. -typedef void (*uc_cb_insn_syscall_t)(uch handle, void *user_data); +typedef void (*uc_cb_insn_syscall_t)(struct uc_struct *uc, void *user_data); //> X86 registers typedef enum uc_x86_reg { From 5f89f9884ebbde38d5067bd4d529b9a88679c589 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 06:39:51 -0400 Subject: [PATCH 02/64] change uch to uc_struct (uc.c) --- uc.c | 150 ++++++++++++++--------------------------------------------- 1 file changed, 36 insertions(+), 114 deletions(-) diff --git a/uc.c b/uc.c index 5a798f57..2a808ce8 100644 --- a/uc.c +++ b/uc.c @@ -49,15 +49,8 @@ unsigned int uc_version(unsigned int *major, unsigned int *minor) UNICORN_EXPORT -uc_err uc_errno(uch handle) +uc_err uc_errno(struct uc_struct *uc) { - struct uc_struct *uc; - - if (!handle) - return UC_ERR_UCH; - - uc = (struct uc_struct *)(uintptr_t)handle; - return uc->errnum; } @@ -131,7 +124,7 @@ bool uc_arch_supported(uc_arch arch) UNICORN_EXPORT -uc_err uc_open(uc_arch arch, uc_mode mode, uch *handle) +uc_err uc_open(uc_arch arch, uc_mode mode, struct uc_struct **result) { struct uc_struct *uc; @@ -180,7 +173,6 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uch *handle) // verify mode if (mode != UC_MODE_ARM && mode != UC_MODE_THUMB) { - *handle = 0; free(uc); return UC_ERR_MODE; } @@ -230,38 +222,29 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uch *handle) } if (uc->init_arch == NULL) { - *handle = 0; return UC_ERR_ARCH; } machine_initialize(uc); - *handle = (uintptr_t)uc; + *result = uc; if (uc->reg_reset) - uc->reg_reset(*handle); + uc->reg_reset(uc); uc->hook_size = HOOK_SIZE; uc->hook_callbacks = calloc(1, sizeof(uc->hook_callbacks[0]) * HOOK_SIZE); return UC_ERR_OK; } else { - *handle = 0; return UC_ERR_ARCH; } } UNICORN_EXPORT -uc_err uc_close(uch *handle) +uc_err uc_close(struct uc_struct *uc) { - struct uc_struct *uc; - - // invalid handle ? - if (*handle == 0) - return UC_ERR_UCH; - - uc = (struct uc_struct *)(*handle); if (uc->release) uc->release(uc->tcg_ctx); @@ -293,26 +276,15 @@ uc_err uc_close(uch *handle) memset(uc, 0, sizeof(*uc)); free(uc); - // invalidate this handle by ZERO out its value. - // this is to make sure it is unusable after uc_close() - *handle = 0; - return UC_ERR_OK; } UNICORN_EXPORT -uc_err uc_reg_read(uch handle, int regid, void *value) +uc_err uc_reg_read(struct uc_struct *uc, int regid, void *value) { - struct uc_struct *uc; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - - uc = (struct uc_struct *)handle; if (uc->reg_read) - uc->reg_read(handle, regid, value); + uc->reg_read(uc, regid, value); else return -1; // FIXME: need a proper uc_err @@ -321,17 +293,10 @@ uc_err uc_reg_read(uch handle, int regid, void *value) UNICORN_EXPORT -uc_err uc_reg_write(uch handle, int regid, const void *value) +uc_err uc_reg_write(struct uc_struct *uc, int regid, const void *value) { - struct uc_struct *uc; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - - uc = (struct uc_struct *)handle; if (uc->reg_write) - uc->reg_write(handle, regid, value); + uc->reg_write(uc, regid, value); else return -1; // FIXME: need a proper uc_err @@ -340,14 +305,8 @@ uc_err uc_reg_write(uch handle, int regid, const void *value) UNICORN_EXPORT -uc_err uc_mem_read(uch handle, uint64_t address, uint8_t *bytes, size_t size) +uc_err uc_mem_read(struct uc_struct *uc, uint64_t address, uint8_t *bytes, size_t size) { - struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - if (uc->read_mem(&uc->as, address, bytes, size) == false) return UC_ERR_MEM_READ; @@ -356,14 +315,8 @@ uc_err uc_mem_read(uch handle, uint64_t address, uint8_t *bytes, size_t size) UNICORN_EXPORT -uc_err uc_mem_write(uch handle, uint64_t address, const uint8_t *bytes, size_t size) +uc_err uc_mem_write(struct uc_struct *uc, uint64_t address, const uint8_t *bytes, size_t size) { - struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - if (uc->write_mem(&uc->as, address, bytes, size) == false) return UC_ERR_MEM_WRITE; @@ -392,24 +345,16 @@ static void *_timeout_fn(void *arg) return NULL; } -static void enable_emu_timer(uch handle, uint64_t timeout) +static void enable_emu_timer(struct uc_struct *uc, uint64_t timeout) { - struct uc_struct *uc = (struct uc_struct *)handle; - uc->timeout = timeout; qemu_thread_create(&uc->timer, "timeout", _timeout_fn, uc, QEMU_THREAD_JOINABLE); } UNICORN_EXPORT -uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) +uc_err uc_emu_start(struct uc_struct* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) { - struct uc_struct* uc = (struct uc_struct *)handle; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - // reset the counter uc->emu_counter = 0; uc->stop_request = false; @@ -421,7 +366,7 @@ uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout break; case UC_ARCH_M68K: - uc_reg_write(handle, UC_M68K_REG_PC, &begin); + uc_reg_write(uc, UC_M68K_REG_PC, &begin); break; case UC_ARCH_X86: @@ -429,13 +374,13 @@ uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout default: break; case UC_MODE_16: - uc_reg_write(handle, UC_X86_REG_IP, &begin); + uc_reg_write(uc, UC_X86_REG_IP, &begin); break; case UC_MODE_32: - uc_reg_write(handle, UC_X86_REG_EIP, &begin); + uc_reg_write(uc, UC_X86_REG_EIP, &begin); break; case UC_MODE_64: - uc_reg_write(handle, UC_X86_REG_RIP, &begin); + uc_reg_write(uc, UC_X86_REG_RIP, &begin); break; } break; @@ -446,23 +391,23 @@ uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout break; case UC_MODE_THUMB: case UC_MODE_ARM: - uc_reg_write(handle, UC_ARM_REG_R15, &begin); + uc_reg_write(uc, UC_ARM_REG_R15, &begin); break; } break; case UC_ARCH_ARM64: - uc_reg_write(handle, UC_ARM64_REG_PC, &begin); + uc_reg_write(uc, UC_ARM64_REG_PC, &begin); break; case UC_ARCH_MIPS: // TODO: MIPS32/MIPS64/BIGENDIAN etc - uc_reg_write(handle, UC_MIPS_REG_PC, &begin); + uc_reg_write(uc, UC_MIPS_REG_PC, &begin); break; case UC_ARCH_SPARC: // TODO: Sparc/Sparc64 - uc_reg_write(handle, UC_SPARC_REG_PC, &begin); + uc_reg_write(uc, UC_SPARC_REG_PC, &begin); break; } @@ -475,7 +420,7 @@ uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout uc->vm_start(uc); if (timeout) - enable_emu_timer(handle, timeout * 1000); // microseconds -> nanoseconds + enable_emu_timer(uc, timeout * 1000); // microseconds -> nanoseconds uc->pause_all_vcpus(uc); // emulation is done uc->emulation_done = true; @@ -485,14 +430,8 @@ uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout UNICORN_EXPORT -uc_err uc_emu_stop(uch handle) +uc_err uc_emu_stop(struct uc_struct *uc) { - struct uc_struct* uc = (struct uc_struct *)handle; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - uc->stop_request = true; // exit the current TB cpu_exit(uc->current_cpu); @@ -501,12 +440,12 @@ uc_err uc_emu_stop(uch handle) } -static int _hook_code(uch handle, int type, uint64_t begin, uint64_t end, +static int _hook_code(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, void *callback, void *user_data, uch *h2) { int i; - i = hook_add(handle, type, begin, end, callback, user_data); + i = hook_add(uc, type, begin, end, callback, user_data); if (i == 0) return UC_ERR_OOM; // FIXME @@ -516,13 +455,13 @@ static int _hook_code(uch handle, int type, uint64_t begin, uint64_t end, } -static uc_err _hook_mem_access(uch handle, uc_mem_type type, +static uc_err _hook_mem_access(struct uc_struct *uc, uc_mem_type type, uint64_t begin, uint64_t end, void *callback, void *user_data, uch *h2) { int i; - i = hook_add(handle, type, begin, end, callback, user_data); + i = hook_add(uc, type, begin, end, callback, user_data); if (i == 0) return UC_ERR_OOM; // FIXME @@ -532,14 +471,8 @@ static uc_err _hook_mem_access(uch handle, uc_mem_type type, } UNICORN_EXPORT -uc_err uc_mem_map(uch handle, uint64_t address, size_t size) +uc_err uc_mem_map(struct uc_struct *uc, uint64_t address, size_t size) { - struct uc_struct* uc = (struct uc_struct *)handle; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - if (size == 0) // invalid memory mapping return UC_ERR_MAP; @@ -663,18 +596,13 @@ static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callb } UNICORN_EXPORT -uc_err uc_hook_add(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, ...) +uc_err uc_hook_add(struct uc_struct *uc, uch *h2, uc_hook_t type, void *callback, void *user_data, ...) { - struct uc_struct* uc = (struct uc_struct *)handle; va_list valist; int ret = UC_ERR_OK; int id; uint64_t begin, end; - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - va_start(valist, user_data); switch(type) { @@ -691,12 +619,12 @@ uc_err uc_hook_add(uch handle, uch *h2, uc_hook_t type, void *callback, void *us case UC_HOOK_CODE: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_code(handle, UC_HOOK_CODE, begin, end, callback, user_data, h2); + ret = _hook_code(uc, UC_HOOK_CODE, begin, end, callback, user_data, h2); break; case UC_HOOK_BLOCK: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_code(handle, UC_HOOK_BLOCK, begin, end, callback, user_data, h2); + ret = _hook_code(uc, UC_HOOK_BLOCK, begin, end, callback, user_data, h2); break; case UC_HOOK_MEM_INVALID: ret = _hook_mem_invalid(uc, callback, user_data, h2); @@ -704,16 +632,16 @@ uc_err uc_hook_add(uch handle, uch *h2, uc_hook_t type, void *callback, void *us case UC_HOOK_MEM_READ: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_mem_access(handle, UC_MEM_READ, begin, end, callback, user_data, h2); + ret = _hook_mem_access(uc, UC_MEM_READ, begin, end, callback, user_data, h2); break; case UC_HOOK_MEM_WRITE: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_mem_access(handle, UC_MEM_WRITE, begin, end, callback, user_data, h2); + ret = _hook_mem_access(uc, UC_MEM_WRITE, begin, end, callback, user_data, h2); case UC_HOOK_MEM_READ_WRITE: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_mem_access(handle, UC_MEM_READ_WRITE, begin, end, callback, user_data, h2); + ret = _hook_mem_access(uc, UC_MEM_READ_WRITE, begin, end, callback, user_data, h2); break; } @@ -723,18 +651,12 @@ uc_err uc_hook_add(uch handle, uch *h2, uc_hook_t type, void *callback, void *us } UNICORN_EXPORT -uc_err uc_hook_del(uch handle, uch *h2) +uc_err uc_hook_del(struct uc_struct *uc, uch *h2) { - //struct uc_struct* uc = (struct uc_struct *)handle; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - if (*h2 == 0) // invalid handle return UC_ERR_HANDLE; - return hook_del(handle, h2); + return hook_del(uc, h2); } From b9f7850efb00e0115958b5cd9061e4e03e7a5679 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 06:11:39 -0400 Subject: [PATCH 03/64] change uch to uc_struct (hook) --- hook.c | 31 +++++++------------------------ include/hook.h | 6 +++--- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/hook.c b/hook.c index 6a26d70d..468d79b7 100644 --- a/hook.c +++ b/hook.c @@ -38,13 +38,9 @@ size_t hook_find_new(struct uc_struct *uc) } // return -1 on failure, index to hook_callbacks[] on success. -size_t hook_add(uch handle, int type, uint64_t begin, uint64_t end, void *callback, void *user_data) +size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, void *callback, void *user_data) { int i; - struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle; - - if (handle == 0) - return -1; // find the first free slot. skip slot 0, so index > 0 i = hook_find_new(uc); @@ -95,13 +91,8 @@ size_t hook_add(uch handle, int type, uint64_t begin, uint64_t end, void *callba } // return 0 on success, -1 on failure -uc_err hook_del(uch handle, uch *h2) +uc_err hook_del(struct uc_struct *uc, uch *h2) { - struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle; - - if (handle == 0) - return UC_ERR_UCH; - if (*h2 == uc->hook_block_idx) { uc->hook_block_idx = 0; } @@ -205,26 +196,19 @@ static struct hook_struct *_hook_find(struct uc_struct *uc, int type, uint64_t a } -static void hook_count_cb(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_count_cb(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { - struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle; - // count this instruction uc->emu_counter++; if (uc->emu_counter > uc->emu_count) - uc_emu_stop(handle); + uc_emu_stop(uc); else if (uc->hook_count_callback) - uc->hook_count_callback(handle, address, size, user_data); + uc->hook_count_callback(uc, address, size, user_data); } -struct hook_struct *hook_find(uch handle, int type, uint64_t address) +struct hook_struct *hook_find(struct uc_struct *uc, int type, uint64_t address) { - struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle; - - if (handle == 0) - return NULL; - // stop executing callbacks if we already got stop request if (uc->stop_request) return NULL; @@ -269,6 +253,5 @@ void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t add uc->set_pc(uc, address); } - ((uc_cb_hookcode_t)callback)((uch)handle, address, size, user_data); + ((uc_cb_hookcode_t)callback)(uc, address, size, user_data); } - diff --git a/include/hook.h b/include/hook.h index 5441071f..72e255a7 100644 --- a/include/hook.h +++ b/include/hook.h @@ -5,13 +5,13 @@ #define UC_HOOK_H // return -1 on failure, index to traces[] on success. -size_t hook_add(uch handle, int type, uint64_t begin, uint64_t end, void *callback, void *user_data); +size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, void *callback, void *user_data); // return 0 on success, -1 on failure -uc_err hook_del(uch handle, uch *traceh); +uc_err hook_del(struct uc_struct *uc, uch *traceh); // return NULL on failure -struct hook_struct *hook_find(uch handle, int type, uint64_t address); +struct hook_struct *hook_find(struct uc_struct *uc, int type, uint64_t address); // return index of an free hook entry in hook_callbacks[] array. // this realloc memory if needed. From 6c4726c88eb0d784b4f751bd38e1467b8756985d Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 06:19:28 -0400 Subject: [PATCH 04/64] change uch to uc_struct (ioport.c) --- qemu/ioport.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/qemu/ioport.c b/qemu/ioport.c index f4e56510..338a296a 100644 --- a/qemu/ioport.c +++ b/qemu/ioport.c @@ -69,7 +69,7 @@ void cpu_outb(struct uc_struct *uc, pio_addr_t addr, uint8_t val) // Unicorn: call interrupt callback if registered if (uc->hook_out_idx) ((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)( - (uch)uc, addr, 1, val, + uc, addr, 1, val, uc->hook_callbacks[uc->hook_out_idx].user_data); } @@ -79,7 +79,7 @@ void cpu_outw(struct uc_struct *uc, pio_addr_t addr, uint16_t val) // Unicorn: call interrupt callback if registered if (uc->hook_out_idx) ((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)( - (uch)uc, addr, 2, val, + uc, addr, 2, val, uc->hook_callbacks[uc->hook_out_idx].user_data); } @@ -88,7 +88,7 @@ void cpu_outl(struct uc_struct *uc, pio_addr_t addr, uint32_t val) //LOG_IOPORT("outl: %04"FMT_pioaddr" %08"PRIx32"\n", addr, val); if (uc->hook_out_idx) ((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)( - (uch)uc, addr, 4, val, + uc, addr, 4, val, uc->hook_callbacks[uc->hook_out_idx].user_data); } @@ -97,7 +97,7 @@ uint8_t cpu_inb(struct uc_struct *uc, pio_addr_t addr) //LOG_IOPORT("inb : %04"FMT_pioaddr" %02"PRIx8"\n", addr, val); if (uc->hook_in_idx) return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)( - (uch)uc, addr, 1, + uc, addr, 1, uc->hook_callbacks[uc->hook_in_idx].user_data); return 0; @@ -108,7 +108,7 @@ uint16_t cpu_inw(struct uc_struct *uc, pio_addr_t addr) //LOG_IOPORT("inw : %04"FMT_pioaddr" %04"PRIx16"\n", addr, val); if (uc->hook_in_idx) return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)( - (uch)uc, addr, 2, + uc, addr, 2, uc->hook_callbacks[uc->hook_in_idx].user_data); return 0; @@ -119,7 +119,7 @@ uint32_t cpu_inl(struct uc_struct *uc, pio_addr_t addr) //LOG_IOPORT("inl : %04"FMT_pioaddr" %08"PRIx32"\n", addr, val); if (uc->hook_in_idx) return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)( - (uch)uc, addr, 4, + uc, addr, 4, uc->hook_callbacks[uc->hook_in_idx].user_data); return 0; From 622d5cd5f9669ab98cb58200938254f6422b1967 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 06:30:58 -0400 Subject: [PATCH 05/64] change uch to uc_struct (target-arm) --- qemu/target-arm/translate-a64.c | 4 ++-- qemu/target-arm/translate.c | 6 +++--- qemu/target-arm/unicorn.h | 12 ++++++------ qemu/target-arm/unicorn_aarch64.c | 21 ++++++--------------- qemu/target-arm/unicorn_arm.c | 14 +++++--------- 5 files changed, 22 insertions(+), 35 deletions(-) diff --git a/qemu/target-arm/translate-a64.c b/qemu/target-arm/translate-a64.c index 2e159f21..deeebabe 100644 --- a/qemu/target-arm/translate-a64.c +++ b/qemu/target-arm/translate-a64.c @@ -10984,7 +10984,7 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s) // Unicorn: trace this instruction on request if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)s->uc, UC_HOOK_CODE, s->pc - 4); + struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc - 4); if (trace) gen_uc_tracecode(tcg_ctx, 4, trace->callback, env->uc, s->pc - 4, trace->user_data); // if requested to emulate only some instructions, check if @@ -11106,7 +11106,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, // Unicorn: trace this block on request if (env->uc->hook_block) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_BLOCK, pc_start); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); if (trace) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; diff --git a/qemu/target-arm/translate.c b/qemu/target-arm/translate.c index 9a1b7914..e3aa07f7 100644 --- a/qemu/target-arm/translate.c +++ b/qemu/target-arm/translate.c @@ -7688,7 +7688,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq // Unicorn: trace this instruction on request if (s->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)s->uc, UC_HOOK_CODE, s->pc - 4); + struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc - 4); if (trace) gen_uc_tracecode(tcg_ctx, 4, trace->callback, s->uc, s->pc - 4, trace->user_data); // if requested to emulate only some instructions, check if @@ -10411,7 +10411,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) // qq // Unicorn: trace this instruction on request if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)s->uc, UC_HOOK_CODE, s->pc); + struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc); if (trace) gen_uc_tracecode(tcg_ctx, 2, trace->callback, env->uc, s->pc, trace->user_data); // if requested to emulate only some instructions, check to see @@ -11229,7 +11229,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, // Unicorn: trace this block on request if (env->uc->hook_block) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_BLOCK, pc_start); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); if (trace) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; diff --git a/qemu/target-arm/unicorn.h b/qemu/target-arm/unicorn.h index 0c355a71..797ef979 100644 --- a/qemu/target-arm/unicorn.h +++ b/qemu/target-arm/unicorn.h @@ -5,13 +5,13 @@ #define UC_QEMU_TARGET_ARM_H // functions to read & write registers -int arm_reg_read(uch handle, unsigned int regid, void *value); -int arm_reg_write(uch handle, unsigned int regid, const void *value); -int arm64_reg_read(uch handle, unsigned int regid, void *value); -int arm64_reg_write(uch handle, unsigned int regid, const void *value); +int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value); +int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); +int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value); +int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); -void arm_reg_reset(uch handle); -void arm64_reg_reset(uch handle); +void arm_reg_reset(struct uc_struct *uc); +void arm64_reg_reset(struct uc_struct *uc); __attribute__ ((visibility ("default"))) void arm_uc_init(struct uc_struct* uc); diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index b9474155..a8a674b0 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -25,23 +25,17 @@ static void arm64_set_pc(struct uc_struct *uc, uint64_t address) ((CPUARMState *)uc->current_cpu->env_ptr)->pc = address; } -void arm64_reg_reset(uch handle) +void arm64_reg_reset(struct uc_struct *uc) { - struct uc_struct *uc = (struct uc_struct *) handle; - CPUArchState *env; - - env = first_cpu->env_ptr; + CPUArchState *env = first_cpu->env_ptr; memset(env->xregs, 0, sizeof(env->xregs)); env->pc = 0; } -int arm64_reg_read(uch handle, unsigned int regid, void *value) +int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { - CPUState *mycpu; - struct uc_struct *uc = (struct uc_struct *) handle; - - mycpu = first_cpu; + CPUState *mycpu = first_cpu; if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0]; @@ -68,12 +62,9 @@ int arm64_reg_read(uch handle, unsigned int regid, void *value) #define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) -int arm64_reg_write(uch handle, unsigned int regid, const void *value) +int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { - CPUState *mycpu; - struct uc_struct *uc = (struct uc_struct *) handle; - - mycpu = first_cpu; + CPUState *mycpu = first_cpu; if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0] = *(int64_t *)value; diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 9737906c..dcb2a65f 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -25,9 +25,9 @@ static void arm_set_pc(struct uc_struct *uc, uint64_t address) ((CPUARMState *)uc->current_cpu->env_ptr)->regs[15] = address; } -void arm_reg_reset(uch handle) +void arm_reg_reset(struct uc_struct *uc) { - struct uc_struct *uc = (struct uc_struct *) handle; + (void)uc; CPUArchState *env; env = first_cpu->env_ptr; @@ -36,10 +36,9 @@ void arm_reg_reset(uch handle) env->pc = 0; } -int arm_reg_read(uch handle, unsigned int regid, void *value) +int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { CPUState *mycpu; - struct uc_struct *uc = (struct uc_struct *) handle; mycpu = first_cpu; @@ -78,12 +77,9 @@ int arm_reg_read(uch handle, unsigned int regid, void *value) #define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) -int arm_reg_write(uch handle, unsigned int regid, const void *value) +int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { - CPUState *mycpu; - struct uc_struct *uc = (struct uc_struct *) handle; - - mycpu = first_cpu; + CPUState *mycpu = first_cpu; switch(uc->mode) { default: From 15a774ac904ca8f834c2f2c2dbd0510ce53ca662 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 06:34:47 -0400 Subject: [PATCH 06/64] change uch to uc_struct (target-mips) --- qemu/target-mips/translate.c | 8 ++++---- qemu/target-mips/unicorn.c | 17 +++++++---------- qemu/target-mips/unicorn.h | 6 +++--- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index 4dbad582..6ffd0d79 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -11344,7 +11344,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) // Unicorn: trace this instruction on request if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_CODE, ctx->pc); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); if (trace) gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); // if requested to emulate only some instructions, check if @@ -13944,7 +13944,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) // Unicorn: trace this instruction on request if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_CODE, ctx->pc); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); if (trace) gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); // if requested to emulate only some instructions, check if @@ -18523,7 +18523,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) // Unicorn: trace this instruction on request if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_CODE, ctx->pc); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); if (trace) gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); // if requested to emulate only some instructions, check if @@ -19208,7 +19208,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, // Unicorn: trace this block on request if (env->uc->hook_block) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_BLOCK, pc_start); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); if (trace) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; diff --git a/qemu/target-mips/unicorn.c b/qemu/target-mips/unicorn.c index a66efdaf..33f1d6c0 100644 --- a/qemu/target-mips/unicorn.c +++ b/qemu/target-mips/unicorn.c @@ -22,19 +22,17 @@ static void mips_set_pc(struct uc_struct *uc, uint64_t address) ((CPUMIPSState *)uc->current_cpu->env_ptr)->active_tc.PC = address; } -void mips_reg_reset(uch handle) +void mips_reg_reset(struct uc_struct *uc) { - struct uc_struct *uc = (struct uc_struct *) handle; - CPUArchState *env; - - env = first_cpu->env_ptr; + (void)uc; + CPUArchState *env = first_cpu->env_ptr; memset(env->active_tc.gpr, 0, sizeof(env->active_tc.gpr)); - env->active_tc.PC = 0; } + env->active_tc.PC = 0; +} -int mips_reg_read(uch handle, unsigned int regid, void *value) +int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { - struct uc_struct *uc = (struct uc_struct *) handle; CPUState *mycpu = first_cpu; if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) @@ -57,9 +55,8 @@ int mips_reg_read(uch handle, unsigned int regid, void *value) #define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) -int mips_reg_write(uch handle, unsigned int regid, const void *value) +int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { - struct uc_struct *uc = (struct uc_struct *) handle; CPUState *mycpu = first_cpu; if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) diff --git a/qemu/target-mips/unicorn.h b/qemu/target-mips/unicorn.h index 29d36a7d..874b82f1 100644 --- a/qemu/target-mips/unicorn.h +++ b/qemu/target-mips/unicorn.h @@ -5,10 +5,10 @@ #define UC_QEMU_TARGET_MIPS_H // functions to read & write registers -int mips_reg_read(uch handle, unsigned int regid, void *value); -int mips_reg_write(uch handle, unsigned int regid, const void *value); +int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value); +int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); -void mips_reg_reset(uch handle); +void mips_reg_reset(struct uc_struct *uc); void mips_uc_init(struct uc_struct* uc); void mipsel_uc_init(struct uc_struct* uc); From e7a8eb89761949fce230e4c9bc85c81e541b165d Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 06:59:01 -0400 Subject: [PATCH 07/64] change uch to uc_struct (target-sparc) --- qemu/target-sparc/translate.c | 4 ++-- qemu/target-sparc/unicorn.c | 12 ++++-------- qemu/target-sparc/unicorn.h | 6 +++--- qemu/target-sparc/unicorn64.c | 12 ++++-------- 4 files changed, 13 insertions(+), 21 deletions(-) diff --git a/qemu/target-sparc/translate.c b/qemu/target-sparc/translate.c index 60c7ba20..f0ad799f 100644 --- a/qemu/target-sparc/translate.c +++ b/qemu/target-sparc/translate.c @@ -2632,7 +2632,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) // Unicorn: trace this instruction on request if (dc->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)dc->uc, UC_HOOK_CODE, dc->pc); + struct hook_struct *trace = hook_find(dc->uc, UC_HOOK_CODE, dc->pc); if (trace) gen_uc_tracecode(tcg_ctx, 4, trace->callback, dc->uc, dc->pc, trace->user_data); // if requested to emulate only some instructions, check if @@ -5406,7 +5406,7 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu, // Unicorn: trace this block on request if (env->uc->hook_block) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_BLOCK, pc_start); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); if (trace) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index 31c79cd7..2ca74743 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -32,12 +32,10 @@ static void sparc_set_pc(struct uc_struct *uc, uint64_t address) ((CPUSPARCState *)uc->current_cpu->env_ptr)->npc = address + 4; } -void sparc_reg_reset(uch handle) +void sparc_reg_reset(struct uc_struct *uc) { - struct uc_struct *uc = (struct uc_struct *) handle; - CPUArchState *env; + CPUArchState *env = first_cpu->env_ptr; - env = first_cpu->env_ptr; memset(env->gregs, 0, sizeof(env->gregs)); memset(env->fpr, 0, sizeof(env->fpr)); memset(env->regbase, 0, sizeof(env->regbase)); @@ -46,9 +44,8 @@ void sparc_reg_reset(uch handle) env->npc = 0; } -int sparc_reg_read(uch handle, unsigned int regid, void *value) +int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { - struct uc_struct *uc = (struct uc_struct *) handle; CPUState *mycpu = first_cpu; if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) @@ -71,9 +68,8 @@ int sparc_reg_read(uch handle, unsigned int regid, void *value) #define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) -int sparc_reg_write(uch handle, unsigned int regid, const void *value) +int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { - struct uc_struct *uc = (struct uc_struct *) handle; CPUState *mycpu = first_cpu; if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) diff --git a/qemu/target-sparc/unicorn.h b/qemu/target-sparc/unicorn.h index 492a7ffb..89771827 100644 --- a/qemu/target-sparc/unicorn.h +++ b/qemu/target-sparc/unicorn.h @@ -5,10 +5,10 @@ #define UC_QEMU_TARGET_SPARC_H // functions to read & write registers -int sparc_reg_read(uch handle, unsigned int regid, void *value); -int sparc_reg_write(uch handle, unsigned int regid, const void *value); +int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value); +int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); -void sparc_reg_reset(uch handle); +void sparc_reg_reset(struct uc_struct *uc); void sparc_uc_init(struct uc_struct* uc); void sparc64_uc_init(struct uc_struct* uc); diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index f9baef0c..20a3928e 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -15,12 +15,10 @@ #define READ_BYTE_L(x) (x & 0xff) -void sparc_reg_reset(uch handle) +void sparc_reg_reset(struct uc_struct *uc) { - struct uc_struct *uc = (struct uc_struct *) handle; - CPUArchState *env; + CPUArchState *env = first_cpu->env_ptr; - env = first_cpu->env_ptr; memset(env->gregs, 0, sizeof(env->gregs)); memset(env->fpr, 0, sizeof(env->fpr)); memset(env->regbase, 0, sizeof(env->regbase)); @@ -29,9 +27,8 @@ void sparc_reg_reset(uch handle) env->npc = 0; } -int sparc_reg_read(uch handle, unsigned int regid, void *value) +int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { - struct uc_struct *uc = (struct uc_struct *) handle; CPUState *mycpu = first_cpu; if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) @@ -54,9 +51,8 @@ int sparc_reg_read(uch handle, unsigned int regid, void *value) #define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) -int sparc_reg_write(uch handle, unsigned int regid, const void *value) +int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { - struct uc_struct *uc = (struct uc_struct *) handle; CPUState *mycpu = first_cpu; if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) From b57662e43d03e17a2514941c9280fecc812fd728 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 07:06:12 -0400 Subject: [PATCH 08/64] change uch to uc_struct (target-i386) --- qemu/target-i386/seg_helper.c | 2 +- qemu/target-i386/translate.c | 4 ++-- qemu/target-i386/unicorn.c | 21 ++++++--------------- qemu/target-i386/unicorn.h | 6 +++--- 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/qemu/target-i386/seg_helper.c b/qemu/target-i386/seg_helper.c index 0bae3caa..2111ac7c 100644 --- a/qemu/target-i386/seg_helper.c +++ b/qemu/target-i386/seg_helper.c @@ -949,7 +949,7 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) struct uc_struct *uc = env->uc; if (uc->hook_syscall_idx) { ((uc_cb_insn_syscall_t)uc->hook_callbacks[uc->hook_syscall_idx].callback)( - (uch)uc, uc->hook_callbacks[uc->hook_syscall_idx].user_data); + uc, uc->hook_callbacks[uc->hook_syscall_idx].user_data); env->eip += next_eip_addend; } diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index 7ce37ef8..776f73c6 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -4756,7 +4756,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, // Unicorn: trace this instruction on request if (env->uc->hook_insn) { - trace = hook_find((uch)env->uc, UC_HOOK_CODE, pc_start); + trace = hook_find(env->uc, UC_HOOK_CODE, pc_start); if (trace) { if (s->last_cc_op != s->cc_op) { sync_eflags(s, tcg_ctx); @@ -8353,7 +8353,7 @@ static inline void gen_intermediate_code_internal(uint8_t *gen_opc_cc_op, // Only hook this block if it is not broken from previous translation due to // full translation cache if (env->uc->hook_block && !env->uc->block_full) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_BLOCK, pc_start); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); if (trace) { env->uc->block_addr = pc_start; gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data); diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index c6350213..9db3fb6d 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -48,12 +48,9 @@ void x86_release(void *ctx) g_free(s->tb_ctx.tbs); } -void x86_reg_reset(uch handle) +void x86_reg_reset(struct uc_struct *uc) { - struct uc_struct *uc = (struct uc_struct *) handle; - CPUArchState *env; - - env = first_cpu->env_ptr; + CPUArchState *env = first_cpu->env_ptr; env->invalid_error = UC_ERR_OK; // no error memset(env->regs, 0, sizeof(env->regs)); @@ -138,12 +135,9 @@ void x86_reg_reset(uch handle) } } -int x86_reg_read(uch handle, unsigned int regid, void *value) +int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { - CPUState *mycpu; - struct uc_struct *uc = (struct uc_struct *) handle; - - mycpu = first_cpu; + CPUState *mycpu = first_cpu; switch(uc->mode) { default: @@ -540,12 +534,9 @@ int x86_reg_read(uch handle, unsigned int regid, void *value) #define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) -int x86_reg_write(uch handle, unsigned int regid, const void *value) +int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { - CPUState *mycpu; - struct uc_struct *uc = (struct uc_struct *) handle; - - mycpu = first_cpu; + CPUState *mycpu = first_cpu; switch(uc->mode) { default: diff --git a/qemu/target-i386/unicorn.h b/qemu/target-i386/unicorn.h index b710236b..a4dda81e 100644 --- a/qemu/target-i386/unicorn.h +++ b/qemu/target-i386/unicorn.h @@ -5,10 +5,10 @@ #define UC_QEMU_TARGET_I386_H // functions to read & write registers -int x86_reg_read(uch handle, unsigned int regid, void *value); -int x86_reg_write(uch handle, unsigned int regid, const void *value); +int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value); +int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); -void x86_reg_reset(uch handle); +void x86_reg_reset(struct uc_struct *uc); void x86_uc_init(struct uc_struct* uc); int x86_uc_machine_init(struct uc_struct *uc); From fcb099805fd414269f9c2d992fcb9bbc02b12663 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 07:08:24 -0400 Subject: [PATCH 09/64] change uch to uc_struct (qemu) --- qemu/cpu-exec.c | 2 +- qemu/softmmu_template.h | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/qemu/cpu-exec.c b/qemu/cpu-exec.c index 7d23caac..d491aacd 100644 --- a/qemu/cpu-exec.c +++ b/qemu/cpu-exec.c @@ -148,7 +148,7 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq // Unicorn: call interrupt callback if registered if (uc->hook_intr_idx) ((uc_cb_hookintr_t)uc->hook_callbacks[uc->hook_intr_idx].callback)( - (uch)uc, cpu->exception_index, + uc, cpu->exception_index, uc->hook_callbacks[uc->hook_intr_idx].user_data); cpu->exception_index = -1; #endif diff --git a/qemu/softmmu_template.h b/qemu/softmmu_template.h index 5ae4a73f..6c968676 100644 --- a/qemu/softmmu_template.h +++ b/qemu/softmmu_template.h @@ -180,9 +180,9 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on memory read if (env->uc->hook_mem_read && READ_ACCESS_TYPE == MMU_DATA_LOAD) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_MEM_READ, addr); + struct hook_struct *trace = hook_find(env->uc, UC_MEM_READ, addr); if (trace) { - ((uc_cb_hookmem_t)trace->callback)((uch)env->uc, UC_MEM_READ, + ((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_READ, (uint64_t)addr, (int)DATA_SIZE, (int64_t)0, trace->user_data); } } @@ -190,7 +190,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on invalid memory if (!memory_mapping(addr) && env->uc->hook_mem_idx) { if (!((uc_cb_eventmem_t)env->uc->hook_callbacks[env->uc->hook_mem_idx].callback)( - (uch)env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, + env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, env->uc->hook_callbacks[env->uc->hook_mem_idx].user_data)) { // save error & quit env->invalid_addr = addr; @@ -302,9 +302,9 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on memory read if (env->uc->hook_mem_read && READ_ACCESS_TYPE == MMU_DATA_LOAD) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_MEM_READ, addr); + struct hook_struct *trace = hook_find(env->uc, UC_MEM_READ, addr); if (trace) { - ((uc_cb_hookmem_t)trace->callback)((uch)env->uc, UC_MEM_READ, + ((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_READ, (uint64_t)addr, (int)DATA_SIZE, (int64_t)0, trace->user_data); } } @@ -312,7 +312,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on invalid memory if (!memory_mapping(addr) && env->uc->hook_mem_idx) { if (!((uc_cb_eventmem_t)env->uc->hook_callbacks[env->uc->hook_mem_idx].callback)( - (uch)env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, + env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, env->uc->hook_callbacks[env->uc->hook_mem_idx].user_data)) { // save error & quit env->invalid_addr = addr; @@ -462,9 +462,9 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on memory write if (env->uc->hook_mem_write) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_MEM_WRITE, addr); + struct hook_struct *trace = hook_find(env->uc, UC_MEM_WRITE, addr); if (trace) { - ((uc_cb_hookmem_t)trace->callback)((uch)env->uc, UC_MEM_WRITE, + ((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_WRITE, (uint64_t)addr, (int)DATA_SIZE, (int64_t)val, trace->user_data); } } @@ -472,7 +472,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on invalid memory if (!memory_mapping(addr) && env->uc->hook_mem_idx) { if (!((uc_cb_eventmem_t)env->uc->hook_callbacks[env->uc->hook_mem_idx].callback)( - (uch)env->uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, + env->uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, env->uc->hook_callbacks[env->uc->hook_mem_idx].user_data)) { // save error & quit env->invalid_addr = addr; @@ -576,9 +576,9 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on memory write if (env->uc->hook_mem_write) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_MEM_WRITE, addr); + struct hook_struct *trace = hook_find(env->uc, UC_MEM_WRITE, addr); if (trace) { - ((uc_cb_hookmem_t)trace->callback)((uch)env->uc, UC_MEM_WRITE, + ((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_WRITE, (uint64_t)addr, (int)DATA_SIZE, (int64_t)val, trace->user_data); } } @@ -586,7 +586,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on invalid memory if (!memory_mapping(addr) && env->uc->hook_mem_idx) { if (!((uc_cb_eventmem_t)env->uc->hook_callbacks[env->uc->hook_mem_idx].callback)( - (uch)env->uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, + env->uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, env->uc->hook_callbacks[env->uc->hook_mem_idx].user_data)) { // save error & quit env->invalid_addr = addr; From 8918deb1b2796d6f1a312905c89b904f72746218 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 07:11:49 -0400 Subject: [PATCH 10/64] change uch to uc_struct (target-m68k) --- qemu/target-m68k/translate.c | 4 ++-- qemu/target-m68k/unicorn.c | 12 ++++-------- qemu/target-m68k/unicorn.h | 6 +++--- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/qemu/target-m68k/translate.c b/qemu/target-m68k/translate.c index ce630d7d..0751445c 100644 --- a/qemu/target-m68k/translate.c +++ b/qemu/target-m68k/translate.c @@ -3044,7 +3044,7 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s) // Unicorn: trace this instruction on request if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_CODE, s->pc); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, s->pc); if (trace) gen_uc_tracecode(tcg_ctx, 2, trace->callback, env->uc, s->pc, trace->user_data); // if requested to emulate only some instructions, check if @@ -3102,7 +3102,7 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb, // Unicorn: trace this block on request if (env->uc->hook_block) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_BLOCK, pc_start); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); if (trace) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; diff --git a/qemu/target-m68k/unicorn.c b/qemu/target-m68k/unicorn.c index f085b53c..d8403c63 100644 --- a/qemu/target-m68k/unicorn.c +++ b/qemu/target-m68k/unicorn.c @@ -21,21 +21,18 @@ static void m68k_set_pc(struct uc_struct *uc, uint64_t address) ((CPUM68KState *)uc->current_cpu->env_ptr)->pc = address; } -void m68k_reg_reset(uch handle) +void m68k_reg_reset(struct uc_struct *uc) { - struct uc_struct *uc = (struct uc_struct *) handle; - CPUArchState *env; + CPUArchState *env = first_cpu->env_ptr; - env = first_cpu->env_ptr; memset(env->aregs, 0, sizeof(env->aregs)); memset(env->dregs, 0, sizeof(env->dregs)); env->pc = 0; } -int m68k_reg_read(uch handle, unsigned int regid, void *value) +int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { - struct uc_struct *uc = (struct uc_struct *)handle; CPUState *mycpu = first_cpu; if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) @@ -60,9 +57,8 @@ int m68k_reg_read(uch handle, unsigned int regid, void *value) #define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) -int m68k_reg_write(uch handle, unsigned int regid, const void *value) +int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { - struct uc_struct *uc = (struct uc_struct *) handle; CPUState *mycpu = first_cpu; if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) diff --git a/qemu/target-m68k/unicorn.h b/qemu/target-m68k/unicorn.h index 5fcca5f3..37ea828f 100644 --- a/qemu/target-m68k/unicorn.h +++ b/qemu/target-m68k/unicorn.h @@ -5,10 +5,10 @@ #define UC_QEMU_TARGET_M68K_H // functions to read & write registers -int m68k_reg_read(uch handle, unsigned int regid, void *value); -int m68k_reg_write(uch handle, unsigned int regid, const void *value); +int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value); +int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); -void m68k_reg_reset(uch handle); +void m68k_reg_reset(struct uc_struct *uc); void m68k_uc_init(struct uc_struct* uc); From 24caaa07debc8e1660d4efe84dce29164a353836 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 07:32:05 -0400 Subject: [PATCH 11/64] change uch to uc_hook_h for hook handles --- hook.c | 30 ++++++++++++++--------------- include/hook.h | 2 +- include/unicorn/unicorn.h | 13 ++++++------- uc.c | 40 +++++++++++++++++++-------------------- 4 files changed, 41 insertions(+), 44 deletions(-) diff --git a/hook.c b/hook.c index 468d79b7..31fcaabf 100644 --- a/hook.c +++ b/hook.c @@ -91,47 +91,45 @@ size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, vo } // return 0 on success, -1 on failure -uc_err hook_del(struct uc_struct *uc, uch *h2) +uc_err hook_del(struct uc_struct *uc, uc_hook_h hh) { - if (*h2 == uc->hook_block_idx) { + if (hh == uc->hook_block_idx) { uc->hook_block_idx = 0; } - if (*h2 == uc->hook_insn_idx) { + if (hh == uc->hook_insn_idx) { uc->hook_insn_idx = 0; } - if (*h2 == uc->hook_read_idx) { + if (hh == uc->hook_read_idx) { uc->hook_read_idx = 0; } - if (*h2 == uc->hook_write_idx) { + if (hh == uc->hook_write_idx) { uc->hook_write_idx = 0; } - if (*h2 == uc->hook_mem_idx) { + if (hh == uc->hook_mem_idx) { uc->hook_mem_idx = 0; } - if (*h2 == uc->hook_intr_idx) { + if (hh == uc->hook_intr_idx) { uc->hook_intr_idx = 0; } - if (*h2 == uc->hook_out_idx) { + if (hh == uc->hook_out_idx) { uc->hook_out_idx = 0; } - if (*h2 == uc->hook_in_idx) { + if (hh == uc->hook_in_idx) { uc->hook_in_idx = 0; } - uc->hook_callbacks[*h2].callback = NULL; - uc->hook_callbacks[*h2].user_data = NULL; - uc->hook_callbacks[*h2].hook_type = 0; - uc->hook_callbacks[*h2].begin = 0; - uc->hook_callbacks[*h2].end = 0; - - *h2 = 0; + uc->hook_callbacks[hh].callback = NULL; + uc->hook_callbacks[hh].user_data = NULL; + uc->hook_callbacks[hh].hook_type = 0; + uc->hook_callbacks[hh].begin = 0; + uc->hook_callbacks[hh].end = 0; return UC_ERR_OK; } diff --git a/include/hook.h b/include/hook.h index 72e255a7..8c095b28 100644 --- a/include/hook.h +++ b/include/hook.h @@ -8,7 +8,7 @@ size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, void *callback, void *user_data); // return 0 on success, -1 on failure -uc_err hook_del(struct uc_struct *uc, uch *traceh); +uc_err hook_del(struct uc_struct *uc, uc_hook_h hh); // return NULL on failure struct hook_struct *hook_find(struct uc_struct *uc, int type, uint64_t address); diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 9fd38435..d7ac2a33 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -21,8 +21,7 @@ extern "C" { struct uc_struct; -// Handle to use with all APIs -typedef size_t uch; +typedef size_t uc_hook_h; #include "m68k.h" #include "x86.h" @@ -358,7 +357,7 @@ uc_err uc_emu_stop(struct uc_struct *uc); The callback will be run when the hook event is hit. @uc: handle returned by uc_open() - @h2: hook handle returned from this registration. To be used in uc_hook_del() API + @hh: hook handle returned from this registration. To be used in uc_hook_del() API @type: hook type @callback: callback to be run when instruction is hit @user_data: user-defined data. This will be passed to callback function in its @@ -369,22 +368,22 @@ uc_err uc_emu_stop(struct uc_struct *uc); for detailed error). */ UNICORN_EXPORT -uc_err uc_hook_add(struct uc_struct *uc, uch *h2, uc_hook_t type, void *callback, void *user_data, ...); +uc_err uc_hook_add(struct uc_struct *uc, uc_hook_h *hh, uc_hook_t type, void *callback, void *user_data, ...); /* Unregister (remove) a hook callback. This API removes the hook callback registered by uc_hook_add(). NOTE: this should be called only when you no longer want to trace. - After this, @h2 is invalid, and nolonger usable. + After this, @hh is invalid, and nolonger usable. @uc: handle returned by uc_open() - @h2: handle returned by uc_hook_add() + @hh: handle returned by uc_hook_add() @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_del(struct uc_struct *uc, uch *h2); +uc_err uc_hook_del(struct uc_struct *uc, uc_hook_h *hh); /* Map memory in for emulation. diff --git a/uc.c b/uc.c index 2a808ce8..7bb690c7 100644 --- a/uc.c +++ b/uc.c @@ -339,7 +339,7 @@ static void *_timeout_fn(void *arg) // timeout before emulation is done? if (!uc->emulation_done) { // force emulation to stop - uc_emu_stop((uch)uc); + uc_emu_stop(uc); } return NULL; @@ -441,7 +441,7 @@ uc_err uc_emu_stop(struct uc_struct *uc) static int _hook_code(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, - void *callback, void *user_data, uch *h2) + void *callback, void *user_data, uc_hook_h *hh) { int i; @@ -449,7 +449,7 @@ static int _hook_code(struct uc_struct *uc, int type, uint64_t begin, uint64_t e if (i == 0) return UC_ERR_OOM; // FIXME - *h2 = i; + *hh = i; return UC_ERR_OK; } @@ -457,7 +457,7 @@ static int _hook_code(struct uc_struct *uc, int type, uint64_t begin, uint64_t e static uc_err _hook_mem_access(struct uc_struct *uc, uc_mem_type type, uint64_t begin, uint64_t end, - void *callback, void *user_data, uch *h2) + void *callback, void *user_data, uc_hook_h *hh) { int i; @@ -465,7 +465,7 @@ static uc_err _hook_mem_access(struct uc_struct *uc, uc_mem_type type, if (i == 0) return UC_ERR_OOM; // FIXME - *h2 = i; + *hh = i; return UC_ERR_OK; } @@ -507,7 +507,7 @@ bool memory_mapping(uint64_t address) } static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_eventmem_t callback, - void *user_data, uch *evh) + void *user_data, uc_hook_h *evh) { size_t i; @@ -526,7 +526,7 @@ static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_eventmem_t callback, static uc_err _hook_intr(struct uc_struct* uc, void *callback, - void *user_data, uch *evh) + void *user_data, uc_hook_h *evh) { size_t i; @@ -545,7 +545,7 @@ static uc_err _hook_intr(struct uc_struct* uc, void *callback, static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callback, - void *user_data, uch *evh) + void *user_data, uc_hook_h *evh) { size_t i; @@ -596,7 +596,7 @@ static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callb } UNICORN_EXPORT -uc_err uc_hook_add(struct uc_struct *uc, uch *h2, uc_hook_t type, void *callback, void *user_data, ...) +uc_err uc_hook_add(struct uc_struct *uc, uc_hook_h *hh, uc_hook_t type, void *callback, void *user_data, ...) { va_list valist; int ret = UC_ERR_OK; @@ -610,38 +610,38 @@ uc_err uc_hook_add(struct uc_struct *uc, uch *h2, uc_hook_t type, void *callback ret = UC_ERR_HOOK; break; case UC_HOOK_INTR: - ret = _hook_intr(uc, callback, user_data, h2); + ret = _hook_intr(uc, callback, user_data, hh); break; case UC_HOOK_INSN: id = va_arg(valist, int); - ret = _hook_insn(uc, id, callback, user_data, h2); + ret = _hook_insn(uc, id, callback, user_data, hh); break; case UC_HOOK_CODE: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_code(uc, UC_HOOK_CODE, begin, end, callback, user_data, h2); + ret = _hook_code(uc, UC_HOOK_CODE, begin, end, callback, user_data, hh); break; case UC_HOOK_BLOCK: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_code(uc, UC_HOOK_BLOCK, begin, end, callback, user_data, h2); + ret = _hook_code(uc, UC_HOOK_BLOCK, begin, end, callback, user_data, hh); break; case UC_HOOK_MEM_INVALID: - ret = _hook_mem_invalid(uc, callback, user_data, h2); + ret = _hook_mem_invalid(uc, callback, user_data, hh); break; case UC_HOOK_MEM_READ: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_mem_access(uc, UC_MEM_READ, begin, end, callback, user_data, h2); + ret = _hook_mem_access(uc, UC_MEM_READ, begin, end, callback, user_data, hh); break; case UC_HOOK_MEM_WRITE: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_mem_access(uc, UC_MEM_WRITE, begin, end, callback, user_data, h2); + ret = _hook_mem_access(uc, UC_MEM_WRITE, begin, end, callback, user_data, hh); case UC_HOOK_MEM_READ_WRITE: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_mem_access(uc, UC_MEM_READ_WRITE, begin, end, callback, user_data, h2); + ret = _hook_mem_access(uc, UC_MEM_READ_WRITE, begin, end, callback, user_data, hh); break; } @@ -651,12 +651,12 @@ uc_err uc_hook_add(struct uc_struct *uc, uch *h2, uc_hook_t type, void *callback } UNICORN_EXPORT -uc_err uc_hook_del(struct uc_struct *uc, uch *h2) +uc_err uc_hook_del(struct uc_struct *uc, uc_hook_h *hh) { - if (*h2 == 0) + if (*hh == 0) // invalid handle return UC_ERR_HANDLE; - return hook_del(uc, h2); + return hook_del(uc, hh); } From ad59de2b5132ab87d9759930f084ae61ed492ad1 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 07:35:42 -0400 Subject: [PATCH 12/64] remove UC_ERR_UCH not used anymore --- include/unicorn/unicorn.h | 1 - uc.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index d7ac2a33..714feaae 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -108,7 +108,6 @@ typedef enum uc_err { UC_ERR_OOM, // Out-Of-Memory error: uc_open(), uc_emulate() UC_ERR_ARCH, // Unsupported architecture: uc_open() UC_ERR_HANDLE, // Invalid handle - UC_ERR_UCH, // Invalid handle (uch) UC_ERR_MODE, // Invalid/unsupported mode: uc_open() UC_ERR_VERSION, // Unsupported version (bindings) UC_ERR_MEM_READ, // Quit emulation due to invalid memory READ: uc_emu_start() diff --git a/uc.c b/uc.c index 7bb690c7..3db2778f 100644 --- a/uc.c +++ b/uc.c @@ -69,8 +69,6 @@ const char *uc_strerror(uc_err code) return "Invalid/unsupported architecture(UC_ERR_ARCH)"; case UC_ERR_HANDLE: return "Invalid handle (UC_ERR_HANDLE)"; - case UC_ERR_UCH: - return "Invalid uch (UC_ERR_UCH)"; case UC_ERR_MODE: return "Invalid mode (UC_ERR_MODE)"; case UC_ERR_VERSION: From 20bdbf638d1d9312676f4d3ec96d0f52fb8508cd Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 07:36:20 -0400 Subject: [PATCH 13/64] change uc_hook_del() to take hook handle by value --- include/unicorn/unicorn.h | 2 +- uc.c | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 714feaae..14102c97 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -382,7 +382,7 @@ uc_err uc_hook_add(struct uc_struct *uc, uc_hook_h *hh, uc_hook_t type, void *ca for detailed error). */ UNICORN_EXPORT -uc_err uc_hook_del(struct uc_struct *uc, uc_hook_h *hh); +uc_err uc_hook_del(struct uc_struct *uc, uc_hook_h hh); /* Map memory in for emulation. diff --git a/uc.c b/uc.c index 3db2778f..3effa782 100644 --- a/uc.c +++ b/uc.c @@ -649,12 +649,8 @@ uc_err uc_hook_add(struct uc_struct *uc, uc_hook_h *hh, uc_hook_t type, void *ca } UNICORN_EXPORT -uc_err uc_hook_del(struct uc_struct *uc, uc_hook_h *hh) +uc_err uc_hook_del(struct uc_struct *uc, uc_hook_h hh) { - if (*hh == 0) - // invalid handle - return UC_ERR_HANDLE; - return hook_del(uc, hh); } From 7ac92ac50a76f9a0562390adfbf6b62c0ff75876 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 08:24:17 -0400 Subject: [PATCH 14/64] samples: update sample_mips to use new API --- samples/sample_mips.c | 48 +++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/samples/sample_mips.c b/samples/sample_mips.c index 43d0682e..5b921257 100644 --- a/samples/sample_mips.c +++ b/samples/sample_mips.c @@ -15,28 +15,28 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_block(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_mips_eb(void) { - uch handle; + struct uc_struct *uc; uc_err err; - uch trace1, trace2; + uc_hook_h trace1, trace2; int r1 = 0x6789; // R1 register printf("Emulate MIPS code (big-endian)\n"); // Initialize emulator in MIPS mode - err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN, &handle); + err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -44,23 +44,23 @@ static void test_mips_eb(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)MIPS_CODE_EB, sizeof(MIPS_CODE_EB) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)MIPS_CODE_EB, sizeof(MIPS_CODE_EB) - 1); // initialize machine registers - uc_reg_write(handle, UC_MIPS_REG_1, &r1); + uc_reg_write(uc, UC_MIPS_REG_1, &r1); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EB) - 1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EB) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err)); } @@ -68,17 +68,17 @@ static void test_mips_eb(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_MIPS_REG_1, &r1); + uc_reg_read(uc, UC_MIPS_REG_1, &r1); printf(">>> R1 = 0x%x\n", r1); - uc_close(&handle); + uc_close(uc); } static void test_mips_el(void) { - uch handle; + struct uc_struct *uc; uc_err err; - uch trace1, trace2; + uc_hook_h trace1, trace2; int r1 = 0x6789; // R1 register @@ -86,7 +86,7 @@ static void test_mips_el(void) printf("Emulate MIPS code (little-endian)\n"); // Initialize emulator in MIPS mode - err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &handle); + err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -94,23 +94,23 @@ static void test_mips_el(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)MIPS_CODE_EL, sizeof(MIPS_CODE_EL) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)MIPS_CODE_EL, sizeof(MIPS_CODE_EL) - 1); // initialize machine registers - uc_reg_write(handle, UC_MIPS_REG_1, &r1); + uc_reg_write(uc, UC_MIPS_REG_1, &r1); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EL) - 1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EL) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err)); } @@ -118,10 +118,10 @@ static void test_mips_el(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_MIPS_REG_1, &r1); + uc_reg_read(uc, UC_MIPS_REG_1, &r1); printf(">>> R1 = 0x%x\n", r1); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) From 7406367a3462ee30231774e6a6ae174020bcf88f Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 08:28:04 -0400 Subject: [PATCH 15/64] samples: update sample_arm to use new API --- samples/sample_arm.c | 54 ++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/samples/sample_arm.c b/samples/sample_arm.c index cb5cc6b3..78476e03 100644 --- a/samples/sample_arm.c +++ b/samples/sample_arm.c @@ -15,21 +15,21 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_block(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_arm(void) { - uch handle; + struct uc_struct *uc; uc_err err; - uch trace1, trace2; + uc_hook_h trace1, trace2; int r0 = 0x1234; // R0 register int r2 = 0x6789; // R1 register @@ -39,7 +39,7 @@ static void test_arm(void) printf("Emulate ARM code\n"); // Initialize emulator in ARM mode - err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &handle); + err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -47,25 +47,25 @@ static void test_arm(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1); // initialize machine registers - uc_reg_write(handle, UC_ARM_REG_R0, &r0); - uc_reg_write(handle, UC_ARM_REG_R2, &r2); - uc_reg_write(handle, UC_ARM_REG_R3, &r3); + uc_reg_write(uc, UC_ARM_REG_R0, &r0); + uc_reg_write(uc, UC_ARM_REG_R2, &r2); + uc_reg_write(uc, UC_ARM_REG_R3, &r3); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u\n", err); } @@ -73,26 +73,26 @@ static void test_arm(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_ARM_REG_R0, &r0); - uc_reg_read(handle, UC_ARM_REG_R1, &r1); + uc_reg_read(uc, UC_ARM_REG_R0, &r0); + uc_reg_read(uc, UC_ARM_REG_R1, &r1); printf(">>> R0 = 0x%x\n", r0); printf(">>> R1 = 0x%x\n", r1); - uc_close(&handle); + uc_close(uc); } static void test_thumb(void) { - uch handle; + struct uc_struct *uc; uc_err err; - uch trace1, trace2; + uc_hook_h trace1, trace2; int sp = 0x1234; // R0 register printf("Emulate THUMB code\n"); // Initialize emulator in ARM mode - err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &handle); + err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -100,23 +100,23 @@ static void test_thumb(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)THUMB_CODE, sizeof(THUMB_CODE) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)THUMB_CODE, sizeof(THUMB_CODE) - 1); // initialize machine registers - uc_reg_write(handle, UC_ARM_REG_SP, &sp); + uc_reg_write(uc, UC_ARM_REG_SP, &sp); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(THUMB_CODE) -1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(THUMB_CODE) -1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u\n", err); } @@ -124,10 +124,10 @@ static void test_thumb(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_ARM_REG_SP, &sp); + uc_reg_read(uc, UC_ARM_REG_SP, &sp); printf(">>> SP = 0x%x\n", sp); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) From 0d69d81c2ece9782c18a86f56a174cd8e481f757 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 08:30:49 -0400 Subject: [PATCH 16/64] samples: update sample_arm64 to use new API --- samples/sample_arm64.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/samples/sample_arm64.c b/samples/sample_arm64.c index f1c5ffbc..1626f20b 100644 --- a/samples/sample_arm64.c +++ b/samples/sample_arm64.c @@ -14,21 +14,21 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_block(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_arm64(void) { - uch handle; + struct uc_struct *uc; uc_err err; - uch trace1, trace2; + uc_hook_h trace1, trace2; int64_t x11 = 0x1234; // X11 register int64_t x13 = 0x6789; // X13 register @@ -37,7 +37,7 @@ static void test_arm64(void) printf("Emulate ARM64 code\n"); // Initialize emulator in ARM mode - err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &handle); + err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -45,25 +45,25 @@ static void test_arm64(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1); // initialize machine registers - uc_reg_write(handle, UC_ARM64_REG_X11, &x11); - uc_reg_write(handle, UC_ARM64_REG_X13, &x13); - uc_reg_write(handle, UC_ARM64_REG_X15, &x15); + uc_reg_write(uc, UC_ARM64_REG_X11, &x11); + uc_reg_write(uc, UC_ARM64_REG_X13, &x13); + uc_reg_write(uc, UC_ARM64_REG_X15, &x15); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u\n", err); } @@ -71,10 +71,10 @@ static void test_arm64(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_ARM64_REG_X11, &x11); + uc_reg_read(uc, UC_ARM64_REG_X11, &x11); printf(">>> X11 = 0x%" PRIx64 "\n", x11); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) From fa11e9dddb3e395da0ab50b6c5664810aa94cf84 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 08:31:53 -0400 Subject: [PATCH 17/64] samples: update sample_sparc to use new API --- samples/sample_sparc.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index 52bb373d..c74b31f3 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -15,21 +15,21 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_block(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_sparc(void) { - uch handle; + struct uc_struct *uc; uc_err err; - uch trace1, trace2; + uc_hook_h trace1, trace2; int g1 = 0x1230; // G1 register int g2 = 0x6789; // G2 register @@ -38,7 +38,7 @@ static void test_sparc(void) printf("Emulate SPARC code\n"); // Initialize emulator in Sparc mode - err = uc_open(UC_ARCH_SPARC, UC_MODE_BIG_ENDIAN, &handle); + err = uc_open(UC_ARCH_SPARC, UC_MODE_BIG_ENDIAN, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -46,25 +46,25 @@ static void test_sparc(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)SPARC_CODE, sizeof(SPARC_CODE) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)SPARC_CODE, sizeof(SPARC_CODE) - 1); // initialize machine registers - uc_reg_write(handle, UC_SPARC_REG_G1, &g1); - uc_reg_write(handle, UC_SPARC_REG_G2, &g2); - uc_reg_write(handle, UC_SPARC_REG_G3, &g3); + uc_reg_write(uc, UC_SPARC_REG_G1, &g1); + uc_reg_write(uc, UC_SPARC_REG_G2, &g2); + uc_reg_write(uc, UC_SPARC_REG_G3, &g3); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(SPARC_CODE) -1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(SPARC_CODE) -1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -73,10 +73,10 @@ static void test_sparc(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_SPARC_REG_G3, &g3); + uc_reg_read(uc, UC_SPARC_REG_G3, &g3); printf(">>> G3 = 0x%x\n", g3); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) From 4c9e78d2f97df38545e475cefc2001943f472860 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 08:35:03 -0400 Subject: [PATCH 18/64] samples: update sample_x86 to use new API --- samples/sample_x86.c | 319 +++++++++++++++++++++---------------------- 1 file changed, 159 insertions(+), 160 deletions(-) diff --git a/samples/sample_x86.c b/samples/sample_x86.c index 4e4a736d..14c6b234 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -31,41 +31,41 @@ #define ADDRESS 0x1000000 // callback for tracing basic blocks -static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_block(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } // callback for tracing instruction -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { int eflags; printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); - uc_reg_read(handle, UC_X86_REG_EFLAGS, &eflags); + uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags); printf(">>> --- EFLAGS is 0x%x\n", eflags); // Uncomment below code to stop the emulation using uc_emu_stop() // if (address == 0x1000009) - // uc_emu_stop(handle); + // uc_emu_stop(uc); } // callback for tracing instruction -static void hook_code64(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code64(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { uint64_t rip; - uc_reg_read(handle, UC_X86_REG_RIP, &rip); + uc_reg_read(uc, UC_X86_REG_RIP, &rip); printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); printf(">>> RIP is 0x%"PRIx64 "\n", rip); // Uncomment below code to stop the emulation using uc_emu_stop() // if (address == 0x1000009) - // uc_emu_stop(handle); + // uc_emu_stop(uc); } // callback for tracing memory access (READ or WRITE) -static bool hook_mem_invalid(uch handle, uc_mem_type type, +static bool hook_mem_invalid(struct uc_struct *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { switch(type) { @@ -76,13 +76,13 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, printf(">>> Missing memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", address, size, value); // map this memory in with 2MB in size - uc_mem_map(handle, 0xaaaa0000, 2 * 1024*1024); + uc_mem_map(uc, 0xaaaa0000, 2 * 1024*1024); // return true to indicate we want to continue return true; } } -static void hook_mem64(uch handle, uc_mem_type type, +static void hook_mem64(struct uc_struct *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { switch(type) { @@ -100,11 +100,11 @@ static void hook_mem64(uch handle, uc_mem_type type, // callback for IN instruction (X86). // this returns the data read from the port -static uint32_t hook_in(uch handle, uint32_t port, int size, void *user_data) +static uint32_t hook_in(struct uc_struct *uc, uint32_t port, int size, void *user_data) { uint32_t eip; - uc_reg_read(handle, UC_X86_REG_EIP, &eip); + uc_reg_read(uc, UC_X86_REG_EIP, &eip); printf("--- reading from port 0x%x, size: %u, address: 0x%x\n", port, size, eip); @@ -125,12 +125,12 @@ static uint32_t hook_in(uch handle, uint32_t port, int size, void *user_data) } // callback for OUT instruction (X86). -static void hook_out(uch handle, uint32_t port, int size, uint32_t value, void *user_data) +static void hook_out(struct uc_struct *uc, uint32_t port, int size, uint32_t value, void *user_data) { uint32_t tmp; uint32_t eip; - uc_reg_read(handle, UC_X86_REG_EIP, &eip); + uc_reg_read(uc, UC_X86_REG_EIP, &eip); printf("--- writing to port 0x%x, size: %u, value: 0x%x, address: 0x%x\n", port, size, value, eip); @@ -139,13 +139,13 @@ static void hook_out(uch handle, uint32_t port, int size, uint32_t value, void * default: return; // should never reach this case 1: - uc_reg_read(handle, UC_X86_REG_AL, &tmp); + uc_reg_read(uc, UC_X86_REG_AL, &tmp); break; case 2: - uc_reg_read(handle, UC_X86_REG_AX, &tmp); + uc_reg_read(uc, UC_X86_REG_AX, &tmp); break; case 4: - uc_reg_read(handle, UC_X86_REG_EAX, &tmp); + uc_reg_read(uc, UC_X86_REG_EAX, &tmp); break; } @@ -154,10 +154,10 @@ static void hook_out(uch handle, uint32_t port, int size, uint32_t value, void * static void test_i386(void) { - uch handle; + struct uc_struct *uc; uc_err err; uint32_t tmp; - uch trace1, trace2; + uc_hook_h trace1, trace2; int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register @@ -165,33 +165,33 @@ static void test_i386(void) printf("Emulate i386 code\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return; } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32, sizeof(X86_CODE32) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)X86_CODE32, sizeof(X86_CODE32) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers - uc_reg_write(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_write(handle, UC_X86_REG_EDX, &r_edx); + uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing all instruction by having @begin > @end - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); // emulate machine code in infinite time - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -200,54 +200,54 @@ static void test_i386(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_read(handle, UC_X86_REG_EDX, &r_edx); + uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); printf(">>> ECX = 0x%x\n", r_ecx); printf(">>> EDX = 0x%x\n", r_edx); // read from memory - if (!uc_mem_read(handle, ADDRESS, (uint8_t *)&tmp, 4)) + if (!uc_mem_read(uc, ADDRESS, (uint8_t *)&tmp, 4)) printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", ADDRESS, tmp); else printf(">>> Failed to read 4 bytes from [0x%x]\n", ADDRESS); - uc_close(&handle); + uc_close(uc); } static void test_i386_jump(void) { - uch handle; + struct uc_struct *uc; uc_err err; - uch trace1, trace2; + uc_hook_h trace1, trace2; printf("===================================\n"); printf("Emulate i386 code with jump\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return; } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_JUMP, + if (uc_mem_write(uc, ADDRESS, (uint8_t *)X86_CODE32_JUMP, sizeof(X86_CODE32_JUMP) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // tracing 1 basic block with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // tracing 1 instruction at ADDRESS - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_JUMP) - 1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_JUMP) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -255,13 +255,13 @@ static void test_i386_jump(void) printf(">>> Emulation done. Below is the CPU context\n"); - uc_close(&handle); + uc_close(uc); } // emulate code that loop forever static void test_i386_loop(void) { - uch handle; + struct uc_struct *uc; uc_err err; int r_ecx = 0x1234; // ECX register @@ -271,28 +271,28 @@ static void test_i386_loop(void) printf("Emulate i386 code that loop forever\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return; } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_LOOP, sizeof(X86_CODE32_LOOP) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)X86_CODE32_LOOP, sizeof(X86_CODE32_LOOP) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers - uc_reg_write(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_write(handle, UC_X86_REG_EDX, &r_edx); + uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // emulate machine code in 2 seconds, so we can quit even // if the code loops - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_LOOP) - 1, 2 * UC_SECOND_SCALE, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_LOOP) - 1, 2 * UC_SECOND_SCALE, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -301,20 +301,20 @@ static void test_i386_loop(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_read(handle, UC_X86_REG_EDX, &r_edx); + uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); printf(">>> ECX = 0x%x\n", r_ecx); printf(">>> EDX = 0x%x\n", r_edx); - uc_close(&handle); + uc_close(uc); } // emulate code that read invalid memory static void test_i386_invalid_mem_read(void) { - uch handle; + struct uc_struct *uc; uc_err err; - uch trace1, trace2; + uc_hook_h trace1, trace2; int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register @@ -323,33 +323,33 @@ static void test_i386_invalid_mem_read(void) printf("Emulate i386 code that read from invalid memory\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return; } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_MEM_READ, sizeof(X86_CODE32_MEM_READ) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)X86_CODE32_MEM_READ, sizeof(X86_CODE32_MEM_READ) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers - uc_reg_write(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_write(handle, UC_X86_REG_EDX, &r_edx); + uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing all instruction by having @begin > @end - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); // emulate machine code in infinite time - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_READ) - 1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_READ) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -358,20 +358,20 @@ static void test_i386_invalid_mem_read(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_read(handle, UC_X86_REG_EDX, &r_edx); + uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); printf(">>> ECX = 0x%x\n", r_ecx); printf(">>> EDX = 0x%x\n", r_edx); - uc_close(&handle); + uc_close(uc); } // emulate code that read invalid memory static void test_i386_invalid_mem_write(void) { - uch handle, evh; + struct uc_struct *uc; uc_err err; - uch trace1, trace2; //, trace3; + uc_hook_h trace1, trace2, trace3; uint32_t tmp; int r_ecx = 0x1234; // ECX register @@ -381,36 +381,36 @@ static void test_i386_invalid_mem_write(void) printf("Emulate i386 code that write to invalid memory\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return; } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_MEM_WRITE, sizeof(X86_CODE32_MEM_WRITE) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)X86_CODE32_MEM_WRITE, sizeof(X86_CODE32_MEM_WRITE) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers - uc_reg_write(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_write(handle, UC_X86_REG_EDX, &r_edx); + uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing all instruction by having @begin > @end - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); // intercept invalid memory events - uc_hook_add(handle, &evh, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace3, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); // emulate machine code in infinite time - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_WRITE) - 1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_WRITE) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -419,31 +419,31 @@ static void test_i386_invalid_mem_write(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_read(handle, UC_X86_REG_EDX, &r_edx); + uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); printf(">>> ECX = 0x%x\n", r_ecx); printf(">>> EDX = 0x%x\n", r_edx); // read from memory - if (!uc_mem_read(handle, 0xaaaaaaaa, (uint8_t *)&tmp, 4)) + if (!uc_mem_read(uc, 0xaaaaaaaa, (uint8_t *)&tmp, 4)) printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xaaaaaaaa, tmp); else printf(">>> Failed to read 4 bytes from [0x%x]\n", 0xffffffaa); - if (!uc_mem_read(handle, 0xffffffaa, (uint8_t *)&tmp, 4)) + if (!uc_mem_read(uc, 0xffffffaa, (uint8_t *)&tmp, 4)) printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xffffffaa, tmp); else printf(">>> Failed to read 4 bytes from [0x%x]\n", 0xffffffaa); - uc_close(&handle); + uc_close(uc); } // emulate code that jump to invalid memory static void test_i386_jump_invalid(void) { - uch handle; + struct uc_struct *uc; uc_err err; - uch trace1, trace2; + uc_hook_h trace1, trace2; int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register @@ -452,33 +452,33 @@ static void test_i386_jump_invalid(void) printf("Emulate i386 code that jumps to invalid memory\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return; } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_JMP_INVALID, sizeof(X86_CODE32_JMP_INVALID) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)X86_CODE32_JMP_INVALID, sizeof(X86_CODE32_JMP_INVALID) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers - uc_reg_write(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_write(handle, UC_X86_REG_EDX, &r_edx); + uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing all instructions by having @begin > @end - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); // emulate machine code in infinite time - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_JMP_INVALID) - 1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_JMP_INVALID) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -487,20 +487,19 @@ static void test_i386_jump_invalid(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_read(handle, UC_X86_REG_EDX, &r_edx); + uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); printf(">>> ECX = 0x%x\n", r_ecx); printf(">>> EDX = 0x%x\n", r_edx); - uc_close(&handle); + uc_close(uc); } static void test_i386_inout(void) { - uch handle; + struct uc_struct *uc; uc_err err; - uch trace1, trace2; - uch trace3, trace4; + uc_hook_h trace1, trace2, trace3, trace4; int r_eax = 0x1234; // EAX register int r_ecx = 0x6789; // ECX register @@ -509,38 +508,38 @@ static void test_i386_inout(void) printf("Emulate i386 code with IN/OUT instructions\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return; } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_INOUT, sizeof(X86_CODE32_INOUT) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)X86_CODE32_INOUT, sizeof(X86_CODE32_INOUT) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers - uc_reg_write(handle, UC_X86_REG_EAX, &r_eax); - uc_reg_write(handle, UC_X86_REG_ECX, &r_ecx); + uc_reg_write(uc, UC_X86_REG_EAX, &r_eax); + uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing all instructions - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); - // handle IN instruction - uc_hook_add(handle, &trace3, UC_HOOK_INSN, hook_in, NULL, UC_X86_INS_IN); - // handle OUT instruction - uc_hook_add(handle, &trace4, UC_HOOK_INSN, hook_out, NULL, UC_X86_INS_OUT); + // uc IN instruction + uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, UC_X86_INS_IN); + // uc OUT instruction + uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, UC_X86_INS_OUT); // emulate machine code in infinite time - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_INOUT) - 1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INOUT) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -549,19 +548,19 @@ static void test_i386_inout(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_EAX, &r_eax); - uc_reg_read(handle, UC_X86_REG_ECX, &r_ecx); + uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); + uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); printf(">>> EAX = 0x%x\n", r_eax); printf(">>> ECX = 0x%x\n", r_ecx); - uc_close(&handle); + uc_close(uc); } static void test_x86_64(void) { - uch handle; + struct uc_struct *uc; uc_err err; - uch trace1, trace2, trace3, trace4; + uc_hook_h trace1, trace2, trace3, trace4; int64_t rax = 0x71f3029efd49d41d; int64_t rbx = 0xd87b45277f133ddb; @@ -584,54 +583,54 @@ static void test_x86_64(void) printf("Emulate x86_64 code\n"); // Initialize emulator in X86-64bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_64, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return; } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE64, sizeof(X86_CODE64) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)X86_CODE64, sizeof(X86_CODE64) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers - uc_reg_write(handle, UC_X86_REG_RSP, &rsp); + uc_reg_write(uc, UC_X86_REG_RSP, &rsp); - uc_reg_write(handle, UC_X86_REG_RAX, &rax); - uc_reg_write(handle, UC_X86_REG_RBX, &rbx); - uc_reg_write(handle, UC_X86_REG_RCX, &rcx); - uc_reg_write(handle, UC_X86_REG_RDX, &rdx); - uc_reg_write(handle, UC_X86_REG_RSI, &rsi); - uc_reg_write(handle, UC_X86_REG_RDI, &rdi); - uc_reg_write(handle, UC_X86_REG_R8, &r8); - uc_reg_write(handle, UC_X86_REG_R9, &r9); - uc_reg_write(handle, UC_X86_REG_R10, &r10); - uc_reg_write(handle, UC_X86_REG_R11, &r11); - uc_reg_write(handle, UC_X86_REG_R12, &r12); - uc_reg_write(handle, UC_X86_REG_R13, &r13); - uc_reg_write(handle, UC_X86_REG_R14, &r14); - uc_reg_write(handle, UC_X86_REG_R15, &r15); + uc_reg_write(uc, UC_X86_REG_RAX, &rax); + uc_reg_write(uc, UC_X86_REG_RBX, &rbx); + uc_reg_write(uc, UC_X86_REG_RCX, &rcx); + uc_reg_write(uc, UC_X86_REG_RDX, &rdx); + uc_reg_write(uc, UC_X86_REG_RSI, &rsi); + uc_reg_write(uc, UC_X86_REG_RDI, &rdi); + uc_reg_write(uc, UC_X86_REG_R8, &r8); + uc_reg_write(uc, UC_X86_REG_R9, &r9); + uc_reg_write(uc, UC_X86_REG_R10, &r10); + uc_reg_write(uc, UC_X86_REG_R11, &r11); + uc_reg_write(uc, UC_X86_REG_R12, &r12); + uc_reg_write(uc, UC_X86_REG_R13, &r13); + uc_reg_write(uc, UC_X86_REG_R14, &r14); + uc_reg_write(uc, UC_X86_REG_R15, &r15); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing all instructions in the range [ADDRESS, ADDRESS+20] - uc_hook_add(handle, &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, (uint64_t)ADDRESS, (uint64_t)(ADDRESS+20)); // tracing all memory WRITE access (with @begin > @end) - uc_hook_add(handle, &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, (uint64_t)1, (uint64_t)0); // tracing all memory READ access (with @begin > @end) - uc_hook_add(handle, &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, (uint64_t)1, (uint64_t)0); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE64) - 1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE64) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -640,20 +639,20 @@ static void test_x86_64(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_RAX, &rax); - uc_reg_read(handle, UC_X86_REG_RBX, &rbx); - uc_reg_read(handle, UC_X86_REG_RCX, &rcx); - uc_reg_read(handle, UC_X86_REG_RDX, &rdx); - uc_reg_read(handle, UC_X86_REG_RSI, &rsi); - uc_reg_read(handle, UC_X86_REG_RDI, &rdi); - uc_reg_read(handle, UC_X86_REG_R8, &r8); - uc_reg_read(handle, UC_X86_REG_R9, &r9); - uc_reg_read(handle, UC_X86_REG_R10, &r10); - uc_reg_read(handle, UC_X86_REG_R11, &r11); - uc_reg_read(handle, UC_X86_REG_R12, &r12); - uc_reg_read(handle, UC_X86_REG_R13, &r13); - uc_reg_read(handle, UC_X86_REG_R14, &r14); - uc_reg_read(handle, UC_X86_REG_R15, &r15); + uc_reg_read(uc, UC_X86_REG_RAX, &rax); + uc_reg_read(uc, UC_X86_REG_RBX, &rbx); + uc_reg_read(uc, UC_X86_REG_RCX, &rcx); + uc_reg_read(uc, UC_X86_REG_RDX, &rdx); + uc_reg_read(uc, UC_X86_REG_RSI, &rsi); + uc_reg_read(uc, UC_X86_REG_RDI, &rdi); + uc_reg_read(uc, UC_X86_REG_R8, &r8); + uc_reg_read(uc, UC_X86_REG_R9, &r9); + uc_reg_read(uc, UC_X86_REG_R10, &r10); + uc_reg_read(uc, UC_X86_REG_R11, &r11); + uc_reg_read(uc, UC_X86_REG_R12, &r12); + uc_reg_read(uc, UC_X86_REG_R13, &r13); + uc_reg_read(uc, UC_X86_REG_R14, &r14); + uc_reg_read(uc, UC_X86_REG_R15, &r15); printf(">>> RAX = 0x%" PRIx64 "\n", rax); printf(">>> RBX = 0x%" PRIx64 "\n", rbx); @@ -670,12 +669,12 @@ static void test_x86_64(void) printf(">>> R14 = 0x%" PRIx64 "\n", r14); printf(">>> R15 = 0x%" PRIx64 "\n", r15); - uc_close(&handle); + uc_close(uc); } static void test_x86_16(void) { - uch handle; + struct uc_struct *uc; uc_err err; uint8_t tmp; @@ -686,29 +685,29 @@ static void test_x86_16(void) printf("Emulate x86 16-bit code\n"); // Initialize emulator in X86-16bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_16, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_16, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return; } // map 8KB memory for this emulation - uc_mem_map(handle, 0, 8 * 1024); + uc_mem_map(uc, 0, 8 * 1024); // write machine code to be emulated to memory - if (uc_mem_write(handle, 0, (uint8_t *)X86_CODE16, sizeof(X86_CODE64) - 1)) { + if (uc_mem_write(uc, 0, (uint8_t *)X86_CODE16, sizeof(X86_CODE64) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers - uc_reg_write(handle, UC_X86_REG_EAX, &eax); - uc_reg_write(handle, UC_X86_REG_EBX, &ebx); - uc_reg_write(handle, UC_X86_REG_ESI, &esi); + uc_reg_write(uc, UC_X86_REG_EAX, &eax); + uc_reg_write(uc, UC_X86_REG_EBX, &ebx); + uc_reg_write(uc, UC_X86_REG_ESI, &esi); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, 0, sizeof(X86_CODE16) - 1, 0, 0); + err = uc_emu_start(uc, 0, sizeof(X86_CODE16) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -718,12 +717,12 @@ static void test_x86_16(void) printf(">>> Emulation done. Below is the CPU context\n"); // read from memory - if (!uc_mem_read(handle, 11, &tmp, 1)) + if (!uc_mem_read(uc, 11, &tmp, 1)) printf(">>> Read 1 bytes from [0x%x] = 0x%x\n", 11, tmp); else printf(">>> Failed to read 1 bytes from [0x%x]\n", 11); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) From 0202a57d32c142679f8a3565c4f86395d280402f Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 08:37:45 -0400 Subject: [PATCH 19/64] samples: update shellcode.c to use new API --- samples/shellcode.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/samples/shellcode.c b/samples/shellcode.c index 51dfb481..bd336882 100644 --- a/samples/shellcode.c +++ b/samples/shellcode.c @@ -20,18 +20,18 @@ #define MIN(a, b) (a < b? a : b) // callback for tracing instruction -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { int r_eip; char tmp[16]; printf("Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); - uc_reg_read(handle, UC_X86_REG_EIP, &r_eip); + uc_reg_read(uc, UC_X86_REG_EIP, &r_eip); printf("*** EIP = %x ***: ", r_eip); size = MIN(sizeof(tmp), size); - if (!uc_mem_read(handle, address, (uint8_t *)tmp, size)) { + if (!uc_mem_read(uc, address, (uint8_t *)tmp, size)) { int i; for (i=0; i>> 0x%x: interrupt 0x%x, SYS_EXIT. quit!\n\n", r_eip, intno); - uc_emu_stop(handle); + uc_emu_stop(uc); break; case 4: // sys_write // ECX = buffer address - uc_reg_read(handle, UC_X86_REG_ECX, &r_ecx); + uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); // EDX = buffer size - uc_reg_read(handle, UC_X86_REG_EDX, &r_edx); + uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); // read the buffer in size = MIN(sizeof(buffer)-1, r_edx); - if (!uc_mem_read(handle, r_ecx, buffer, size)) { + if (!uc_mem_read(uc, r_ecx, buffer, size)) { buffer[size] = '\0'; printf(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u, content = '%s'\n", r_eip, intno, r_ecx, r_edx, buffer); @@ -88,44 +88,44 @@ static void hook_intr(uch handle, uint32_t intno, void *user_data) static void test_i386(void) { - uch handle, evh; + struct uc_struct *uc; uc_err err; - uch trace1; + uc_hook_h trace1, trace2; int r_esp = ADDRESS + 0x200000; // ESP register printf("Emulate i386 code\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return; } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_SELF, sizeof(X86_CODE32_SELF) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)X86_CODE32_SELF, sizeof(X86_CODE32_SELF) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers - uc_reg_write(handle, UC_X86_REG_ESP, &r_esp); + uc_reg_write(uc, UC_X86_REG_ESP, &r_esp); // tracing all instructions by having @begin > @end - uc_hook_add(handle, &trace1, UC_HOOK_CODE, hook_code, NULL, 1, 0); + uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code, NULL, 1, 0); // handle interrupt ourself - uc_hook_add(handle, &evh, UC_HOOK_INTR, hook_intr, NULL); + uc_hook_add(uc, &trace2, UC_HOOK_INTR, hook_intr, NULL); printf("\n>>> Start tracing this Linux code\n"); // emulate machine code in infinite time - // err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_SELF), 0, 12); <--- emulate only 12 instructions - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_SELF) - 1, 0, 0); + // err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_SELF), 0, 12); <--- emulate only 12 instructions + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_SELF) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -133,7 +133,7 @@ static void test_i386(void) printf("\n>>> Emulation done.\n"); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) From db563bfcdba55facef6ee66d84a3629cbc820f0f Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 08:38:50 -0400 Subject: [PATCH 20/64] samples: update sample_m68k to use new API --- samples/sample_m68k.c | 94 +++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/samples/sample_m68k.c b/samples/sample_m68k.c index 02452e5d..f482a786 100644 --- a/samples/sample_m68k.c +++ b/samples/sample_m68k.c @@ -12,20 +12,20 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_block(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_m68k(void) { - uch handle; - uch trace1, trace2; + struct uc_struct *uc; + uc_hook_h trace1, trace2; uc_err err; int d0 = 0x0000; // d0 data register @@ -52,7 +52,7 @@ static void test_m68k(void) printf("Emulate M68K code\n"); // Initialize emulator in M68K mode - err = uc_open(UC_ARCH_M68K, UC_MODE_BIG_ENDIAN, &handle); + err = uc_open(UC_ARCH_M68K, UC_MODE_BIG_ENDIAN, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -60,42 +60,42 @@ static void test_m68k(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)M68K_CODE, sizeof(M68K_CODE) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)M68K_CODE, sizeof(M68K_CODE) - 1); // initialize machine registers - uc_reg_write(handle, UC_M68K_REG_D0, &d0); - uc_reg_write(handle, UC_M68K_REG_D1, &d1); - uc_reg_write(handle, UC_M68K_REG_D2, &d2); - uc_reg_write(handle, UC_M68K_REG_D3, &d3); - uc_reg_write(handle, UC_M68K_REG_D4, &d4); - uc_reg_write(handle, UC_M68K_REG_D5, &d5); - uc_reg_write(handle, UC_M68K_REG_D6, &d6); - uc_reg_write(handle, UC_M68K_REG_D7, &d7); + uc_reg_write(uc, UC_M68K_REG_D0, &d0); + uc_reg_write(uc, UC_M68K_REG_D1, &d1); + uc_reg_write(uc, UC_M68K_REG_D2, &d2); + uc_reg_write(uc, UC_M68K_REG_D3, &d3); + uc_reg_write(uc, UC_M68K_REG_D4, &d4); + uc_reg_write(uc, UC_M68K_REG_D5, &d5); + uc_reg_write(uc, UC_M68K_REG_D6, &d6); + uc_reg_write(uc, UC_M68K_REG_D7, &d7); - uc_reg_write(handle, UC_M68K_REG_A0, &a0); - uc_reg_write(handle, UC_M68K_REG_A1, &a1); - uc_reg_write(handle, UC_M68K_REG_A2, &a2); - uc_reg_write(handle, UC_M68K_REG_A3, &a3); - uc_reg_write(handle, UC_M68K_REG_A4, &a4); - uc_reg_write(handle, UC_M68K_REG_A5, &a5); - uc_reg_write(handle, UC_M68K_REG_A6, &a6); - uc_reg_write(handle, UC_M68K_REG_A7, &a7); + uc_reg_write(uc, UC_M68K_REG_A0, &a0); + uc_reg_write(uc, UC_M68K_REG_A1, &a1); + uc_reg_write(uc, UC_M68K_REG_A2, &a2); + uc_reg_write(uc, UC_M68K_REG_A3, &a3); + uc_reg_write(uc, UC_M68K_REG_A4, &a4); + uc_reg_write(uc, UC_M68K_REG_A5, &a5); + uc_reg_write(uc, UC_M68K_REG_A6, &a6); + uc_reg_write(uc, UC_M68K_REG_A7, &a7); - uc_reg_write(handle, UC_M68K_REG_PC, &pc); - uc_reg_write(handle, UC_M68K_REG_SR, &sr); + uc_reg_write(uc, UC_M68K_REG_PC, &pc); + uc_reg_write(uc, UC_M68K_REG_SR, &sr); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing all instruction - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(M68K_CODE)-1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(M68K_CODE)-1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u\n", err); } @@ -103,26 +103,26 @@ static void test_m68k(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_M68K_REG_D0, &d0); - uc_reg_read(handle, UC_M68K_REG_D1, &d1); - uc_reg_read(handle, UC_M68K_REG_D2, &d2); - uc_reg_read(handle, UC_M68K_REG_D3, &d3); - uc_reg_read(handle, UC_M68K_REG_D4, &d4); - uc_reg_read(handle, UC_M68K_REG_D5, &d5); - uc_reg_read(handle, UC_M68K_REG_D6, &d6); - uc_reg_read(handle, UC_M68K_REG_D7, &d7); + uc_reg_read(uc, UC_M68K_REG_D0, &d0); + uc_reg_read(uc, UC_M68K_REG_D1, &d1); + uc_reg_read(uc, UC_M68K_REG_D2, &d2); + uc_reg_read(uc, UC_M68K_REG_D3, &d3); + uc_reg_read(uc, UC_M68K_REG_D4, &d4); + uc_reg_read(uc, UC_M68K_REG_D5, &d5); + uc_reg_read(uc, UC_M68K_REG_D6, &d6); + uc_reg_read(uc, UC_M68K_REG_D7, &d7); - uc_reg_read(handle, UC_M68K_REG_A0, &a0); - uc_reg_read(handle, UC_M68K_REG_A1, &a1); - uc_reg_read(handle, UC_M68K_REG_A2, &a2); - uc_reg_read(handle, UC_M68K_REG_A3, &a3); - uc_reg_read(handle, UC_M68K_REG_A4, &a4); - uc_reg_read(handle, UC_M68K_REG_A5, &a5); - uc_reg_read(handle, UC_M68K_REG_A6, &a6); - uc_reg_read(handle, UC_M68K_REG_A7, &a7); + uc_reg_read(uc, UC_M68K_REG_A0, &a0); + uc_reg_read(uc, UC_M68K_REG_A1, &a1); + uc_reg_read(uc, UC_M68K_REG_A2, &a2); + uc_reg_read(uc, UC_M68K_REG_A3, &a3); + uc_reg_read(uc, UC_M68K_REG_A4, &a4); + uc_reg_read(uc, UC_M68K_REG_A5, &a5); + uc_reg_read(uc, UC_M68K_REG_A6, &a6); + uc_reg_read(uc, UC_M68K_REG_A7, &a7); - uc_reg_read(handle, UC_M68K_REG_PC, &pc); - uc_reg_read(handle, UC_M68K_REG_SR, &sr); + uc_reg_read(uc, UC_M68K_REG_PC, &pc); + uc_reg_read(uc, UC_M68K_REG_SR, &sr); printf(">>> A0 = 0x%x\t\t>>> D0 = 0x%x\n", a0, d0); printf(">>> A1 = 0x%x\t\t>>> D1 = 0x%x\n", a1, d1); @@ -135,7 +135,7 @@ static void test_m68k(void) printf(">>> PC = 0x%x\n", pc); printf(">>> SR = 0x%x\n", sr); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) From e74bc0db88e13db4ecd3b5454e0aba633353a14e Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 26 Aug 2015 09:29:28 -0400 Subject: [PATCH 21/64] regress: update C programs to use new API --- regress/block_test.c | 16 ++++++++-------- regress/map_crash.c | 10 +++++----- regress/sigill.c | 20 ++++++++++---------- regress/sigill2.c | 14 +++++++------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/regress/block_test.c b/regress/block_test.c index cc372fed..0d778222 100644 --- a/regress/block_test.c +++ b/regress/block_test.c @@ -12,7 +12,7 @@ static int count = 1; // @address: address where the code is being executed // @size: size of machine instruction being executed // @user_data: user data passed to tracing APIs. -void cb_hookblock(uch handle, uint64_t address, uint32_t size, void *user_data) { +void cb_hookblock(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { fprintf(stderr, "# >>> Tracing basic block at 0x%llx, block size = 0x%x\n", address, size); if (address != 0x1000000 && address != 0x1000200) { fprintf(stderr, "not ok %d - address != 0x1000000 && address != 0x1000200\n", count++); @@ -27,19 +27,19 @@ void cb_hookblock(uch handle, uint64_t address, uint32_t size, void *user_data) } int main() { - uch u; + struct uc_struct *uc; fprintf(stderr, "# basic block callback test\n"); fprintf(stderr, "# there are only two basic blocks 0x1000000-0x10001ff and 0x1000200-0x10003ff\n"); - uc_err err = uc_open(UC_ARCH_X86, UC_MODE_32, &u); + uc_err err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); } fprintf(stderr, "ok %d - uc_open\n", count++); - err = uc_mem_map(u, 0x1000000, 4096); + err = uc_mem_map(uc, 0x1000000, 4096); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); @@ -55,23 +55,23 @@ int main() { memset(code, 0x90, sizeof(code)); memcpy(code + 1024 - 5, "\xe9\x00\xfe\xff\xff", 5); - err = uc_mem_write(u, 0x1000000, code, sizeof(code)); + err = uc_mem_write(uc, 0x1000000, code, sizeof(code)); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); } fprintf(stderr, "ok %d - uc_mem_write\n", count++); - uch h1, h2; + uc_hook_h h1, h2; - err = uc_hook_add(u, &h1, UC_HOOK_BLOCK, cb_hookblock, NULL, (uint64_t)1, (uint64_t)0); + err = uc_hook_add(uc, &h1, UC_HOOK_BLOCK, cb_hookblock, NULL, (uint64_t)1, (uint64_t)0); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); } fprintf(stderr, "ok %d - uc_hook_add\n", count++); - err = uc_emu_start(u, 0x1000000, 0x1000000 + sizeof(code), 0, 1030); + err = uc_emu_start(uc, 0x1000000, 0x1000000 + sizeof(code), 0, 1030); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); diff --git a/regress/map_crash.c b/regress/map_crash.c index 4d6bc8fe..9da92447 100644 --- a/regress/map_crash.c +++ b/regress/map_crash.c @@ -9,8 +9,8 @@ int main() { int size; uint8_t *buf; - uch uh; - uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uh); + struct uc_struct *uc; + uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc); if (err) { fprintf (stderr, "Cannot initialize unicorn\n"); return 1; @@ -22,9 +22,9 @@ int main() { return 1; } memset (buf, 0, size); - if (!uc_mem_map (uh, UC_BUG_WRITE_ADDR, size)) { - uc_mem_write (uh, UC_BUG_WRITE_ADDR, buf, size); + if (!uc_mem_map(uc, UC_BUG_WRITE_ADDR, size)) { + uc_mem_write(uc, UC_BUG_WRITE_ADDR, buf, size); } - uc_close (&uh); + uc_close(uc); return 0; } diff --git a/regress/sigill.c b/regress/sigill.c index 099bbec3..151ad8ec 100644 --- a/regress/sigill.c +++ b/regress/sigill.c @@ -8,9 +8,9 @@ int got_sigill = 0; -void _interrupt(uch handle, uint32_t intno, void *user_data) { +void _interrupt(struct uc_struct *uc, uint32_t intno, void *user_data) { if (intno == 6) { - uc_emu_stop (handle); + uc_emu_stop(uc); got_sigill = 1; } } @@ -18,9 +18,9 @@ void _interrupt(uch handle, uint32_t intno, void *user_data) { int main() { int size; uint8_t *buf; - uch uh; - uch uh_trap; - uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uh); + struct uc_struct *uc; + uc_hook_h uh_trap; + uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc); if (err) { fprintf (stderr, "Cannot initialize unicorn\n"); return 1; @@ -32,13 +32,13 @@ int main() { return 1; } memset (buf, 0, size); - if (!uc_mem_map (uh, UC_BUG_WRITE_ADDR, size)) { - uc_mem_write (uh, UC_BUG_WRITE_ADDR, + if (!uc_mem_map(uc, UC_BUG_WRITE_ADDR, size)) { + uc_mem_write(uc, UC_BUG_WRITE_ADDR, (const uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff", 8); } - uc_hook_add (uh, &uh_trap, UC_HOOK_INTR, _interrupt, NULL); - uc_emu_start (uh, UC_BUG_WRITE_ADDR, UC_BUG_WRITE_ADDR+8, 0, 1); - uc_close (&uh); + uc_hook_add(uc, &uh_trap, UC_HOOK_INTR, _interrupt, NULL); + uc_emu_start(uc, UC_BUG_WRITE_ADDR, UC_BUG_WRITE_ADDR+8, 0, 1); + uc_close(uc); printf ("Correct: %s\n", got_sigill? "YES": "NO"); return got_sigill? 0: 1; } diff --git a/regress/sigill2.c b/regress/sigill2.c index 97cd7199..2985c836 100644 --- a/regress/sigill2.c +++ b/regress/sigill2.c @@ -10,20 +10,20 @@ int main() { int size; uint8_t *buf; - uch uh; - uch uh_trap; - uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uh); + struct uc_struct *uc; + + uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc); if (err) { fprintf (stderr, "Cannot initialize unicorn\n"); return 1; } size = UC_BUG_WRITE_SIZE; - if (!uc_mem_map (uh, UC_BUG_WRITE_ADDR, size)) { - uc_mem_write (uh, UC_BUG_WRITE_ADDR, + if (!uc_mem_map(uc, UC_BUG_WRITE_ADDR, size)) { + uc_mem_write(uc, UC_BUG_WRITE_ADDR, (const uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff", 8); } - err = uc_emu_start (uh, UC_BUG_WRITE_ADDR, UC_BUG_WRITE_ADDR+8, 0, 1); - uc_close (&uh); + err = uc_emu_start(uc, UC_BUG_WRITE_ADDR, UC_BUG_WRITE_ADDR+8, 0, 1); + uc_close(uc); printf ("Error = %u (%s)\n", err, uc_strerror(err)); return err? -1: 0; } From 7f63d76908c810d6501e84a988418dbedf96fdba Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Fri, 28 Aug 2015 12:58:53 -0700 Subject: [PATCH 22/64] add comments to source for ro_mem_test.c --- regress/ro_mem_test.c | 3 +++ 1 file changed, 3 insertions(+) mode change 100644 => 100755 regress/ro_mem_test.c diff --git a/regress/ro_mem_test.c b/regress/ro_mem_test.c old mode 100644 new mode 100755 index 1cce6189..19d66bf3 --- a/regress/ro_mem_test.c +++ b/regress/ro_mem_test.c @@ -156,8 +156,11 @@ int main(int argc, char **argv, char **envp) // emulate machine code in infinite time printf("BEGIN execution - 2\n"); + //update eax to point to aligned memory (same as add eax,7 above) uint32_t eax = 0x40002C; uc_reg_write(handle, UC_X86_REG_EAX, &eax); + //resume execution at the mov dword [eax], 0x87654321 + //to test an aligned write as well err = uc_emu_start(handle, 0x400015, 0x400000 + sizeof(PROGRAM), 0, 2); if (err) { printf("Expected failure on uc_emu_start() with error returned %u: %s\n", From 9ba59e4988b7fa84bb5fd3d52ab8c6482a98a108 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Fri, 28 Aug 2015 18:59:45 -0700 Subject: [PATCH 23/64] Step one towards uc_mem_protect, uc_mem_unmap, and support for UC_PROT_EXEC and NX regions --- include/unicorn/unicorn.h | 25 ++++++++++- qemu/softmmu_template.h | 88 ++++++++++++++++++++++++--------------- uc.c | 88 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 163 insertions(+), 38 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 556b6c17..ce887aa3 100755 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -151,6 +151,7 @@ typedef enum uc_mem_type { UC_MEM_READ_WRITE, // Memory is accessed (either READ or WRITE) UC_MEM_WRITE_NW, // write to non-writable UC_MEM_READ_NR, // read from non-readable + UC_MEM_NX, // read from non-readable } uc_mem_type; // All type of hooks for uc_hook_add() API. @@ -391,12 +392,13 @@ uc_err uc_hook_del(uch handle, uch *h2); typedef enum uc_prot { UC_PROT_READ = 1, UC_PROT_WRITE = 2, + UC_PROT_EXEC = 4, } uc_prot; /* Map memory in for emulation. This API adds a memory region that can be used by emulation. The region is mapped - with permissions UC_PROT_READ | UC_PROT_WRITE. + with permissions UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC. @handle: handle returned by uc_open() @address: starting address of the new memory region to be mapped in. @@ -420,7 +422,7 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size); @size: size of the new memory region to be mapped in. This size must be multiple of 4KB, or this will return with UC_ERR_MAP error. @perms: Permissions for the newly mapped region. - This must be some combination of UC_PROT_READ | UC_PROT_WRITE, + This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, or this will return with UC_ERR_MAP error. @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum @@ -429,6 +431,25 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size); UNICORN_EXPORT uc_err uc_mem_map_ex(uch handle, uint64_t address, size_t size, uint32_t perms); +/* + Set memory permissions for emulation memory. + This API changes permissions on an existing memory region. + + @handle: handle returned by uc_open() + @start: starting address of the memory region to be modified. + This address must be aligned to 4KB, or this will return with UC_ERR_MAP error. + @block_size: size of the memory region to be modified. + This size must be multiple of 4KB, or this will return with UC_ERR_MAP error. + @perms: New permissions for the mapped region. + This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, + or this will return with UC_ERR_MAP error. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_mem_protect(uch handle, uint64_t start, size_t block_size, uint32_t perms); + #ifdef __cplusplus } #endif diff --git a/qemu/softmmu_template.h b/qemu/softmmu_template.h index 56f657a4..8c181824 100755 --- a/qemu/softmmu_template.h +++ b/qemu/softmmu_template.h @@ -181,6 +181,24 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, struct uc_struct *uc = env->uc; MemoryRegion *mr = memory_mapping(uc, addr); +#if defined(SOFTMMU_CODE_ACCESS) + // Unicorn: callback on fetch from NX + if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { //non-executable + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + (uch)uc, UC_MEM_NX, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_idx].user_data)) { + env->invalid_error = UC_ERR_OK; + } + else { + env->invalid_addr = addr; + env->invalid_error = UC_ERR_MEM_READ; + // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); + cpu_exit(uc->current_cpu); + return 0; + } + } +#endif + // Unicorn: callback on memory read if (env->uc->hook_mem_read && READ_ACCESS_TYPE == MMU_DATA_LOAD) { struct hook_struct *trace = hook_find((uch)env->uc, UC_MEM_READ, addr); @@ -206,15 +224,11 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, } } - // Unicorn: callback on read only memory + // Unicorn: callback on non-readable memory if (mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable - bool result = false; - if (uc->hook_mem_idx) { - result = ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_READ_NR, addr, DATA_SIZE, 0, - uc->hook_callbacks[uc->hook_mem_idx].user_data); - } - if (result) { + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + (uch)uc, UC_MEM_READ_NR, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { @@ -326,6 +340,24 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, struct uc_struct *uc = env->uc; MemoryRegion *mr = memory_mapping(uc, addr); +#if defined(SOFTMMU_CODE_ACCESS) + // Unicorn: callback on fetch from NX + if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { //non-executable + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + (uch)uc, UC_MEM_NX, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_idx].user_data)) { + env->invalid_error = UC_ERR_OK; + } + else { + env->invalid_addr = addr; + env->invalid_error = UC_ERR_MEM_READ; + // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); + cpu_exit(uc->current_cpu); + return 0; + } + } +#endif + // Unicorn: callback on memory read if (env->uc->hook_mem_read && READ_ACCESS_TYPE == MMU_DATA_LOAD) { struct hook_struct *trace = hook_find((uch)env->uc, UC_MEM_READ, addr); @@ -351,15 +383,11 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, } } - // Unicorn: callback on read only memory + // Unicorn: callback on non-readable memory if (mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable - bool result = false; - if (uc->hook_mem_idx) { - result = ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_READ_NR, addr, DATA_SIZE, 0, - uc->hook_callbacks[uc->hook_mem_idx].user_data); - } - if (result) { + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + (uch)uc, UC_MEM_READ_NR, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { @@ -534,15 +562,11 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, } } - // Unicorn: callback on read only memory - if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //read only memory - bool result = false; - if (uc->hook_mem_idx) { - result = ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_WRITE_NW, addr, DATA_SIZE, (int64_t)val, - uc->hook_callbacks[uc->hook_mem_idx].user_data); - } - if (result) { + // Unicorn: callback on non-writable memory + if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + (uch)uc, UC_MEM_WRITE_NW, addr, DATA_SIZE, (int64_t)val, + uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { @@ -672,15 +696,11 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, } } - // Unicorn: callback on read only memory - if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //read only memory - bool result = false; - if (uc->hook_mem_idx) { - result = ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_WRITE_NW, addr, DATA_SIZE, (int64_t)val, - uc->hook_callbacks[uc->hook_mem_idx].user_data); - } - if (result) { + // Unicorn: callback on non-writable memory + if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + (uch)uc, UC_MEM_WRITE_NW, addr, DATA_SIZE, (int64_t)val, + uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { diff --git a/uc.c b/uc.c index 3192c627..18d70b63 100755 --- a/uc.c +++ b/uc.c @@ -568,7 +568,7 @@ uc_err uc_mem_map_ex(uch handle, uint64_t address, size_t size, uint32_t perms) return UC_ERR_MAP; // check for only valid permissions - if ((perms & ~(UC_PROT_READ | UC_PROT_WRITE)) != 0) + if ((perms & ~(UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC)) != 0) return UC_ERR_MAP; if ((uc->mapped_block_count & (MEM_BLOCK_INCR - 1)) == 0) { //time to grow @@ -588,7 +588,91 @@ UNICORN_EXPORT uc_err uc_mem_map(uch handle, uint64_t address, size_t size) { //old api, maps RW by default - return uc_mem_map_ex(handle, address, size, UC_PROT_READ | UC_PROT_WRITE); + return uc_mem_map_ex(handle, address, size, UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC); +} + +UNICORN_EXPORT +uc_err uc_mem_protect(uch handle, uint64_t start, size_t block_size, uint32_t perms) +{ + uint64_t address; + uint64_t size; + struct uc_struct* uc = (struct uc_struct *)handle; + + if (handle == 0) + // invalid handle + return UC_ERR_UCH; + + if (block_size == 0) + // invalid memory mapping + return UC_ERR_MAP; + + // address must be aligned to 4KB + if ((start & (4*1024 - 1)) != 0) + return UC_ERR_MAP; + + // size must be multiple of 4KB + if ((block_size & (4*1024 - 1)) != 0) + return UC_ERR_MAP; + + // check for only valid permissions + if ((perms & ~(UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC)) != 0) + return UC_ERR_MAP; + + //check that users entire requested block is mapped + address = start; + size = block_size; + while (size > 0) { + uint64_t region_size; + MemoryRegion *mr = memory_mapping(uc, address); + if (mr == NULL) { + return UC_ERR_MAP; + } + region_size = int128_get64(mr->size); + if (address > mr->addr) { + //in case start address is not aligned with start of region + region_size -= address - mr->addr; + } + if (size < region_size) { + //entire region is covered + break; + } + size -= region_size; + address += region_size; + } + + //Now we know entire region is mapped, so change permissions + address = start; + size = block_size; + while (size > 0) { + MemoryRegion *mr = memory_mapping(uc, address); + uint64_t region_size = int128_get64(mr->size); + if (address > mr->addr) { + //in case start address is not aligned with start of region + region_size -= address - mr->addr; + //TODO Learn how to split regions + //In this case some proper subset of the region is having it's permissions changed + //need to split region and add new portions into uc->mapped_blocks list + //In this case, there is a portion of the region with original perms: mr->addr..start + //and a portion getting new perms: start..start+block_size + + //split the block and stay in the loop + } + if (size < int128_get64(mr->size)) { + //TODO Learn how to split regions + //In this case some proper subset of the region is having it's permissions changed + //need to split region and add new portions into uc->mapped_blocks list + //In this case, there is a portion of the region with new perms: start..start+block_size + //and a portion getting new perms: mr->addr+size..mr->addr+mr->size + + //split the block and break + break; + } + size -= int128_get64(mr->size); + address += int128_get64(mr->size); + mr->perms = perms; + uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0); + } + return UC_ERR_OK; } MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) From 6beb1b8a13087da29b289c977e3c6a010aaf798b Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sat, 29 Aug 2015 21:17:30 -0700 Subject: [PATCH 24/64] intermediate commit, working unmap of complete blocks, still need sub-blocks, and cross block --- include/uc_priv.h | 3 + include/unicorn/unicorn.h | 22 +++++- qemu/aarch64.h | 1 + qemu/arm.h | 1 + qemu/header_gen.py | 1 + qemu/include/exec/memory.h | 1 + qemu/m68k.h | 1 + qemu/memory.c | 12 +++ qemu/mips.h | 1 + qemu/mips64.h | 1 + qemu/mips64el.h | 1 + qemu/mipsel.h | 1 + qemu/powerpc.h | 1 + qemu/sparc.h | 1 + qemu/sparc64.h | 1 + qemu/unicorn_common.h | 1 + qemu/x86_64.h | 1 + uc.c | 155 +++++++++++++++++++++++-------------- 18 files changed, 147 insertions(+), 59 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 686ab9e5..7e76513a 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -47,6 +47,8 @@ typedef void (*uc_args_uc_u64_t)(struct uc_struct *, uint64_t addr); typedef MemoryRegion* (*uc_args_uc_ram_size_t)(struct uc_struct*, ram_addr_t begin, size_t size, uint32_t perms); +typedef void (*uc_mem_unmap_t)(struct uc_struct*, MemoryRegion *mr); + typedef void (*uc_readonly_mem_t)(MemoryRegion *mr, bool readonly); // which interrupt should make emulation stop? @@ -90,6 +92,7 @@ struct uc_struct { uc_args_tcg_enable_t tcg_enabled; uc_args_uc_long_t tcg_exec_init; uc_args_uc_ram_size_t memory_map; + uc_mem_unmap_t memory_unmap; uc_readonly_mem_t readonly_mem; // list of cpu void* cpu; diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 991db568..fee75297 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -422,9 +422,9 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms); This API changes permissions on an existing memory region. @handle: handle returned by uc_open() - @start: starting address of the memory region to be modified. + @address: starting address of the memory region to be modified. This address must be aligned to 4KB, or this will return with UC_ERR_MAP error. - @block_size: size of the memory region to be modified. + @size: size of the memory region to be modified. This size must be multiple of 4KB, or this will return with UC_ERR_MAP error. @perms: New permissions for the mapped region. This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, @@ -434,7 +434,23 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms); for detailed error). */ UNICORN_EXPORT -uc_err uc_mem_protect(uch handle, uint64_t start, size_t block_size, uint32_t perms); +uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms); + +/* + Unmap a region of emulation memory. + This API deletes a memory mapping from the emulation memory space. + + @handle: handle returned by uc_open() + @address: starting address of the memory region to be unmapped. + This address must be aligned to 4KB, or this will return with UC_ERR_MAP error. + @size: size of the memory region to be modified. + This size must be multiple of 4KB, or this will return with UC_ERR_MAP error. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size); #ifdef __cplusplus } diff --git a/qemu/aarch64.h b/qemu/aarch64.h index 9ab06273..77de1644 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_aarch64 #define tb_cleanup tb_cleanup_aarch64 #define memory_map memory_map_aarch64 +#define memory_unmap memory_unmap_aarch64 #define memory_free memory_free_aarch64 #define helper_raise_exception helper_raise_exception_aarch64 #define tcg_enabled tcg_enabled_aarch64 diff --git a/qemu/arm.h b/qemu/arm.h index c24329b3..3d405fac 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_arm #define tb_cleanup tb_cleanup_arm #define memory_map memory_map_arm +#define memory_unmap memory_unmap_arm #define memory_free memory_free_arm #define helper_raise_exception helper_raise_exception_arm #define tcg_enabled tcg_enabled_arm diff --git a/qemu/header_gen.py b/qemu/header_gen.py index ff8a1ca5..67982502 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -13,6 +13,7 @@ symbols = ( 'phys_mem_clean', 'tb_cleanup', 'memory_map', + 'memory_unmap', 'memory_free', 'helper_raise_exception', 'tcg_enabled', diff --git a/qemu/include/exec/memory.h b/qemu/include/exec/memory.h index 4df8bd85..45c51e4d 100644 --- a/qemu/include/exec/memory.h +++ b/qemu/include/exec/memory.h @@ -939,6 +939,7 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len, void memory_register_types(struct uc_struct *uc); MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, uint32_t perms); +void memory_unmap(struct uc_struct *uc, MemoryRegion *mr); int memory_free(struct uc_struct *uc); #endif diff --git a/qemu/m68k.h b/qemu/m68k.h index 5dbefab7..4be757ba 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_m68k #define tb_cleanup tb_cleanup_m68k #define memory_map memory_map_m68k +#define memory_unmap memory_unmap_m68k #define memory_free memory_free_m68k #define helper_raise_exception helper_raise_exception_m68k #define tcg_enabled tcg_enabled_m68k diff --git a/qemu/memory.c b/qemu/memory.c index 3f8169d9..95336f5f 100644 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -45,6 +45,18 @@ MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, ui return uc->ram; } +void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) +{ + targer_ulong addr; + //make sure all pages associated with the MemoryRegion are flushed + for (addr = mr->addr; addr < mr->end; addr += 0x1000) { + tlb_flush_page(uc->current_cpu, addr); + } + mr->enabled = false; + memory_region_del_subregion(get_system_memory(uc), mr); + g_free(mr); +} + int memory_free(struct uc_struct *uc) { int i; diff --git a/qemu/mips.h b/qemu/mips.h index 059995e5..7a3e308a 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_mips #define tb_cleanup tb_cleanup_mips #define memory_map memory_map_mips +#define memory_unmap memory_unmap_mips #define memory_free memory_free_mips #define helper_raise_exception helper_raise_exception_mips #define tcg_enabled tcg_enabled_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index 74daddbc..9870cb15 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_mips64 #define tb_cleanup tb_cleanup_mips64 #define memory_map memory_map_mips64 +#define memory_unmap memory_unmap_mips64 #define memory_free memory_free_mips64 #define helper_raise_exception helper_raise_exception_mips64 #define tcg_enabled tcg_enabled_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 6ffc2dbc..5fde9e53 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_mips64el #define tb_cleanup tb_cleanup_mips64el #define memory_map memory_map_mips64el +#define memory_unmap memory_unmap_mips64el #define memory_free memory_free_mips64el #define helper_raise_exception helper_raise_exception_mips64el #define tcg_enabled tcg_enabled_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 94c4fdf7..caf1fe4d 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_mipsel #define tb_cleanup tb_cleanup_mipsel #define memory_map memory_map_mipsel +#define memory_unmap memory_unmap_mipsel #define memory_free memory_free_mipsel #define helper_raise_exception helper_raise_exception_mipsel #define tcg_enabled tcg_enabled_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index fd627665..92e614e1 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_powerpc #define tb_cleanup tb_cleanup_powerpc #define memory_map memory_map_powerpc +#define memory_unmap memory_unmap_powerpc #define memory_free memory_free_powerpc #define helper_raise_exception helper_raise_exception_powerpc #define tcg_enabled tcg_enabled_powerpc diff --git a/qemu/sparc.h b/qemu/sparc.h index 64803c11..6aa47aa5 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_sparc #define tb_cleanup tb_cleanup_sparc #define memory_map memory_map_sparc +#define memory_unmap memory_unmap_sparc #define memory_free memory_free_sparc #define helper_raise_exception helper_raise_exception_sparc #define tcg_enabled tcg_enabled_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 5042c38d..6d3d2a1d 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_sparc64 #define tb_cleanup tb_cleanup_sparc64 #define memory_map memory_map_sparc64 +#define memory_unmap memory_unmap_sparc64 #define memory_free memory_free_sparc64 #define helper_raise_exception helper_raise_exception_sparc64 #define tcg_enabled tcg_enabled_sparc64 diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index 176900cb..23ef0acb 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -73,6 +73,7 @@ static inline void uc_common_init(struct uc_struct* uc) uc->pause_all_vcpus = pause_all_vcpus; uc->vm_start = vm_start; uc->memory_map = memory_map; + uc->memory_unmap = memory_unmap; uc->readonly_mem = memory_region_set_readonly; if (!uc->release) diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 9a148e95..ac9f34f0 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_x86_64 #define tb_cleanup tb_cleanup_x86_64 #define memory_map memory_map_x86_64 +#define memory_unmap memory_unmap_x86_64 #define memory_free memory_free_x86_64 #define helper_raise_exception helper_raise_exception_x86_64 #define tcg_enabled tcg_enabled_x86_64 diff --git a/uc.c b/uc.c index 3c46e689..ec85ea61 100644 --- a/uc.c +++ b/uc.c @@ -643,87 +643,130 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms) } UNICORN_EXPORT -uc_err uc_mem_protect(uch handle, uint64_t start, size_t block_size, uint32_t perms) +uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) { - uint64_t address; - uint64_t size; struct uc_struct* uc = (struct uc_struct *)handle; + MemoryRegion *mr; if (handle == 0) // invalid handle return UC_ERR_UCH; - if (block_size == 0) + if (size == 0) // invalid memory mapping return UC_ERR_MAP; // address must be aligned to 4KB - if ((start & (4*1024 - 1)) != 0) + if ((address & (4*1024 - 1)) != 0) return UC_ERR_MAP; // size must be multiple of 4KB - if ((block_size & (4*1024 - 1)) != 0) + if ((size & (4*1024 - 1)) != 0) return UC_ERR_MAP; // check for only valid permissions if ((perms & ~(UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC)) != 0) return UC_ERR_MAP; - //check that users entire requested block is mapped - address = start; - size = block_size; - while (size > 0) { - uint64_t region_size; - MemoryRegion *mr = memory_mapping(uc, address); - if (mr == NULL) { - return UC_ERR_MAP; - } - region_size = int128_get64(mr->size); - if (address > mr->addr) { - //in case start address is not aligned with start of region - region_size -= address - mr->addr; - } - if (size < region_size) { - //entire region is covered - break; - } - size -= region_size; - address += region_size; - } + //check that user's entire requested block is mapped + if (!check_mem_area(uc, address, size)) + return UC_ERR_MAP; //Now we know entire region is mapped, so change permissions - address = start; - size = block_size; - while (size > 0) { - MemoryRegion *mr = memory_mapping(uc, address); - uint64_t region_size = int128_get64(mr->size); - if (address > mr->addr) { - //in case start address is not aligned with start of region - region_size -= address - mr->addr; - //TODO Learn how to split regions - //In this case some proper subset of the region is having it's permissions changed - //need to split region and add new portions into uc->mapped_blocks list - //In this case, there is a portion of the region with original perms: mr->addr..start - //and a portion getting new perms: start..start+block_size - - //split the block and stay in the loop - } - if (size < int128_get64(mr->size)) { - //TODO Learn how to split regions - //In this case some proper subset of the region is having it's permissions changed - //need to split region and add new portions into uc->mapped_blocks list - //In this case, there is a portion of the region with new perms: start..start+block_size - //and a portion getting new perms: mr->addr+size..mr->addr+mr->size - - //split the block and break - break; - } - size -= int128_get64(mr->size); - address += int128_get64(mr->size); + //check trivial case first + mr = memory_mapping(uc, address); + if (address == mr->addr && size == int128_get64(mr->size)) { + //regions exactly matches an existing region just change perms mr->perms = perms; uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0); } - return UC_ERR_OK; + else { + //ouch, we are going to need to subdivide blocks +/* + address = start; + size = block_size; + while (size > 0) { + MemoryRegion *mr = memory_mapping(uc, address); + uint64_t region_size = int128_get64(mr->size); + if (address > mr->addr) { + //in case start address is not aligned with start of region + region_size -= address - mr->addr; + //TODO Learn how to split regions + //In this case some proper subset of the region is having it's permissions changed + //need to split region and add new portions into uc->mapped_blocks list + //In this case, there is a portion of the region with original perms: mr->addr..start + //and a portion getting new perms: start..start+block_size + + //split the block and stay in the loop + } + if (size < int128_get64(mr->size)) { + //TODO Learn how to split regions + //In this case some proper subset of the region is having it's permissions changed + //need to split region and add new portions into uc->mapped_blocks list + //In this case, there is a portion of the region with new perms: start..start+block_size + //and a portion getting new perms: mr->addr+size..mr->addr+mr->size + + //split the block and break + break; + } + size -= int128_get64(mr->size); + address += int128_get64(mr->size); + mr->perms = perms; + uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0); + } +*/ + } + return UC_ERR_OK; +} + +UNICORN_EXPORT +uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) +{ + MemoryRegion *mr; + unsigned int i; + struct uc_struct* uc = (struct uc_struct *)handle; + + if (handle == 0) + // invalid handle + return UC_ERR_UCH; + + if (size == 0) + // nothing to unmap + return UC_ERR_OK; + + // address must be aligned to 4KB + if ((address & (4*1024 - 1)) != 0) + return UC_ERR_MAP; + + // size must be multiple of 4KB + if ((size & (4*1024 - 1)) != 0) + return UC_ERR_MAP; + + //check that user's entire requested block is mapped + if (!check_mem_area(uc, address, size)) + return UC_ERR_MAP; + + //Now we know entire region is mapped, so change permissions + //check trivial case first + mr = memory_mapping(uc, address); + if (address == mr->addr && size == int128_get64(mr->size)) { + //regions exactly matches an existing region just unmap it + uc->memory_unmap(uc, mr); + for (i = 0; i < uc->mapped_block_count; i++) { + if (uc->mapped_blocks[i] == mr) { + uc->mapped_block_count--; + //shift remainder of array down over deleted pointer + memcpy(&uc->mapped_blocks[i], &uc->mapped_blocks[i + 1], sizeof(MemoryRegion*) * (uc->mapped_block_count - i)); + break; + } + } + return UC_ERR_OK; + } + else { + //ouch, we are going to need to subdivide blocks + } + + return UC_ERR_MAP; } MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) From 942de0f2ae34a5134c976859fc330d86ddf0c124 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sun, 30 Aug 2015 00:22:18 -0700 Subject: [PATCH 25/64] implemented basic block splitting, uc_mem_unmap should work for sub=blocks or across contiguous blocks --- qemu/memory.c | 2 +- uc.c | 153 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 138 insertions(+), 17 deletions(-) mode change 100644 => 100755 qemu/memory.c mode change 100644 => 100755 uc.c diff --git a/qemu/memory.c b/qemu/memory.c old mode 100644 new mode 100755 index f44d32c2..5e9cc9b0 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -47,7 +47,7 @@ MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, ui void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) { - targer_ulong addr; + target_ulong addr; //make sure all pages associated with the MemoryRegion are flushed for (addr = mr->addr; addr < mr->end; addr += 0x1000) { tlb_flush_page(uc->current_cpu, addr); diff --git a/uc.c b/uc.c old mode 100644 new mode 100755 index 454d1a04..6dc2786d --- a/uc.c +++ b/uc.c @@ -31,6 +31,13 @@ #include "qemu/include/hw/boards.h" +//keep this a power of two! +#define UC_BLOCK_SIZE 0x1000 +#define UC_ALIGN_MASK (UC_BLOCK_SIZE - 1) + +static uint8_t *copy_region(uch uc, MemoryRegion *mr); +static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, size_t size, bool do_delete); + UNICORN_EXPORT unsigned int uc_version(unsigned int *major, unsigned int *minor) { @@ -622,12 +629,12 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms) // invalid memory mapping return UC_ERR_MAP; - // address must be aligned to 4KB - if ((address & (4*1024 - 1)) != 0) + // address must be aligned to UC_BLOCK_SIZE + if ((address & UC_ALIGN_MASK) != 0) return UC_ERR_MAP; - // size must be multiple of 4KB - if ((size & (4*1024 - 1)) != 0) + // size must be multiple of UC_BLOCK_SIZE + if ((size & UC_ALIGN_MASK) != 0) return UC_ERR_MAP; // check for only valid permissions @@ -647,6 +654,111 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms) return UC_ERR_OK; } +//create a backup copy of the indicated MemoryRegion +//generally used in prepartion for splitting a MemoryRegion +static uint8_t *copy_region(uch handle, MemoryRegion *mr) +{ + uint8_t *block = (uint8_t *)malloc(int128_get64(mr->size)); + if (block != NULL) { + uc_err err = uc_mem_read(handle, mr->addr, block, int128_get64(mr->size)); + if (err != UC_ERR_OK) { + free(block); + block = NULL; + } + } + return block; +} + +/* +Split the given MemoryRegion at the indicated address for the indicated size +this may result in the create of up to 3 spanning sections. If the delete +parameter is true, the no new section will be created to replace the indicate +range. This functions exists to support uc_mem_protect and uc_mem_unmap. + +This is a static function and callers have already done some preliminary +parameter validation. +*/ +//TODO: investigate whether qemu region manipulation functions already offer this capability +static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, size_t size, bool do_delete) +{ + uint8_t *backup; + uint32_t perms; + uint64_t begin, end, chunk_end; + size_t l_size, m_size, r_size; + chunk_end = address + size; + if (address <= mr->addr && chunk_end >= mr->end) { + //trivial case, if we are deleting, just unmap + if (do_delete) + return uc_mem_unmap(handle, mr->addr, int128_get64(mr->size)) == UC_ERR_OK; + return true; + } + + if (size == 0) + //trivial case + return true; + + if (address >= mr->end || chunk_end <= mr->addr) + //impossible case + return false; + + backup = copy_region(handle, mr); + if (backup == NULL) + return false; + + //save the essential information required for the split before mr gets deleted + perms = mr->perms; + begin = mr->addr; + end = mr->end; + + if (uc_mem_unmap(handle, mr->addr, int128_get64(mr->size)) != UC_ERR_OK) + goto error; + + /* overlapping cases + * |------mr------| + * case 1 |---size--| + * case 2 |--size--| + * case 3 |---size--| + */ + + //adjust some things + if (address < begin) + address = begin; + if (chunk_end > end) + chunk_end = end; + + //compute sub region sizes + l_size = (size_t)(address - begin); + r_size = (size_t)(end - chunk_end); + m_size = (size_t)(chunk_end - address); + + //If there are error in any of the below operations, things are too far gone + //at that point to recover. Could try to remap orignal region, but these smaller + //allocation just failed so no guarantee that we can recover the original + //allocation at this point + if (l_size > 0) { + if (uc_mem_map(handle, begin, l_size, perms) != UC_ERR_OK) + goto error; + if (uc_mem_write(handle, begin, backup, l_size) != UC_ERR_OK) + goto error; + } + if (m_size > 0 && !do_delete) { + if (uc_mem_map(handle, address, m_size, perms) != UC_ERR_OK) + goto error; + if (uc_mem_write(handle, address, backup + l_size, m_size) != UC_ERR_OK) + goto error; + } + if (r_size > 0) { + if (uc_mem_map(handle, chunk_end, r_size, perms) != UC_ERR_OK) + goto error; + if (uc_mem_write(handle, chunk_end, backup + l_size + m_size, r_size) != UC_ERR_OK) + goto error; + } + return true; +error: + free(backup); + return false; +} + UNICORN_EXPORT uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) { @@ -661,12 +773,12 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) // invalid memory mapping return UC_ERR_MAP; - // address must be aligned to 4KB - if ((address & (4*1024 - 1)) != 0) + // address must be aligned to UC_BLOCK_SIZE + if ((address & UC_ALIGN_MASK) != 0) return UC_ERR_MAP; - // size must be multiple of 4KB - if ((size & (4*1024 - 1)) != 0) + // size must be multiple of UC_BLOCK_SIZE + if ((size & UC_ALIGN_MASK) != 0) return UC_ERR_MAP; // check for only valid permissions @@ -730,6 +842,7 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) MemoryRegion *mr; unsigned int i; struct uc_struct* uc = (struct uc_struct *)handle; + size_t count, len; if (handle == 0) // invalid handle @@ -739,23 +852,24 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) // nothing to unmap return UC_ERR_OK; - // address must be aligned to 4KB - if ((address & (4*1024 - 1)) != 0) + // address must be aligned to UC_BLOCK_SIZE + if ((address & UC_ALIGN_MASK) != 0) return UC_ERR_MAP; - // size must be multiple of 4KB - if ((size & (4*1024 - 1)) != 0) + // size must be multiple of UC_BLOCK_SIZE + if ((size & UC_ALIGN_MASK) != 0) return UC_ERR_MAP; //check that user's entire requested block is mapped if (!check_mem_area(uc, address, size)) return UC_ERR_MAP; - //Now we know entire region is mapped, so change permissions + //Now we know entire region is mapped, so begin the delete //check trivial case first mr = memory_mapping(uc, address); if (address == mr->addr && size == int128_get64(mr->size)) { //regions exactly matches an existing region just unmap it + //this termiantes a possible recursion between this function and split_region uc->memory_unmap(uc, mr); for (i = 0; i < uc->mapped_block_count; i++) { if (uc->mapped_blocks[i] == mr) { @@ -765,13 +879,20 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) break; } } - return UC_ERR_OK; } else { //ouch, we are going to need to subdivide blocks + count = 0; + while(count < size) { + MemoryRegion *mr = memory_mapping(uc, address); + len = MIN(size - count, mr->end - address); + if (!split_region(handle, mr, address, len, true)) + return UC_ERR_MAP; + count += len; + address += len; + } } - - return UC_ERR_MAP; + return UC_ERR_OK; } MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) From 0a60fa4c8a6e83a3e1ed8e302241160ab596886a Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sun, 30 Aug 2015 00:22:49 -0700 Subject: [PATCH 26/64] fix perms --- qemu/memory.c | 0 uc.c | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 qemu/memory.c mode change 100755 => 100644 uc.c diff --git a/qemu/memory.c b/qemu/memory.c old mode 100755 new mode 100644 diff --git a/uc.c b/uc.c old mode 100755 new mode 100644 From 394461b941e4597a8ae04830587b6a4499ddb5cd Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sun, 30 Aug 2015 14:01:07 -0700 Subject: [PATCH 27/64] section splitting complete for uc_mem_protect --- samples/Makefile | 4 +- samples/mem_protect.c | 323 ++++++++++++++++++++++++++++++++++++++++++ samples/mem_unmap.c | 313 ++++++++++++++++++++++++++++++++++++++++ uc.c | 71 ++++------ 4 files changed, 665 insertions(+), 46 deletions(-) create mode 100755 samples/mem_protect.c create mode 100755 samples/mem_unmap.c diff --git a/samples/Makefile b/samples/Makefile index 1ebb891f..72d1ca45 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -97,6 +97,8 @@ endif ifneq (,$(findstring x86,$(UNICORN_ARCHS))) SOURCES += sample_x86.c SOURCES += shellcode.c +SOURCES += mem_unmap.c +SOURCES += mem_protect.c endif ifneq (,$(findstring m68k,$(UNICORN_ARCHS))) SOURCES += sample_m68k.c @@ -111,7 +113,7 @@ all: $(BINARY) clean: rm -rf *.o $(OBJS_ELF) $(BINARY) $(SAMPLEDIR)/*.exe $(SAMPLEDIR)/*.static $(OBJDIR)/lib$(LIBNAME)* $(OBJDIR)/$(LIBNAME)* rm -rf libunicorn*.so libunicorn*.lib libunicorn*.dylib unicorn*.dll unicorn*.lib - rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k shellcode + rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k shellcode mem_unmap mem_protect $(BINARY): $(OBJS) diff --git a/samples/mem_protect.c b/samples/mem_protect.c new file mode 100755 index 00000000..4afb88c1 --- /dev/null +++ b/samples/mem_protect.c @@ -0,0 +1,323 @@ +/* + +uc_mem_protect demo / unit test + +Copyright(c) 2015 Chris Eagle + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#define __STDC_FORMAT_MACROS +#include +#include +#include +#include +#include +#include + +#include + +unsigned char PROGRAM[] = + "\xc7\x05\x00\x00\x20\x00\x41\x41\x41\x41\x90\xc7\x05\x00\x00\x20" + "\x00\x42\x42\x42\x42\xc7\x05\x00\x00\x30\x00\x43\x43\x43\x43\x90" + "\xc7\x05\x00\x00\x30\x00\x44\x44\x44\x44\xc7\x05\x00\x00\x40\x00" + "\x45\x45\x45\x45\x90\xc7\x05\x00\x00\x40\x00\x46\x46\x46\x46\xc7" + "\x05\x00\xf8\x3f\x00\x47\x47\x47\x47\xc7\x05\x00\x18\x40\x00\x48" + "\x48\x48\x48\xf4"; +// total size: 84 bytes + +/* +bits 32 + +; assumes code section at 0x100000 +; assumes data section at 0x200000, initially rw +; assumes data section at 0x300000, initially rw +; assumes data section at 0x400000, initially rw + +; with installed hooks unmaps or maps on each nop + + mov dword [0x200000], 0x41414141 + nop ; mark it RO + mov dword [0x200000], 0x42424242 + + mov dword [0x300000], 0x43434343 + nop ; mark it RO + mov dword [0x300000], 0x44444444 + + mov dword [0x400000], 0x45454545 + nop ; mark it RO + mov dword [0x400000], 0x46464646 + mov dword [0x3ff800], 0x47474747 ; make sure surrounding areas remained RW + mov dword [0x401800], 0x48484848 ; make sure surrounding areas remained RW + + hlt ; tell hook function we are done +*/ + +int test_num = 0; +uint32_t tests[] = { + 0x41414141, + 0x43434343, + 0x45454545 +}; + +static int log_num = 1; + +#define CODE_SECTION 0x100000 +#define CODE_SIZE 0x1000 + +// callback for tracing instruction +static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) +{ + uint8_t opcode; + uint32_t testval; + if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } + printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr); + switch (opcode) { + case 0x90: //nop + printf("# Handling NOP\n"); + if (uc_mem_read(handle, 0x200000 + test_num * 0x100000, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + } + else { + printf("ok %d - good uc_mem_read for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + printf("# uc_mem_read for test %d\n", test_num); + + if (testval == tests[test_num]) { + printf("ok %d - passed test %d\n", log_num++, test_num); + } + else { + printf("not ok %d - failed test %d\n", log_num++, test_num); + printf("# Expected: 0x%x\n",tests[test_num]); + printf("# Received: 0x%x\n", testval); + } + } + if (uc_mem_protect(handle, 0x200000 + test_num * 0x100000, 0x1000, UC_PROT_READ) != UC_ERR_OK) { + printf("not ok %d - uc_mem_protect fail during hook_code callback, addr: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + } + else { + printf("ok %d - uc_mem_protect success\n", log_num++); + } + test_num++; + break; + case 0xf4: //hlt + printf("# Handling HLT\n"); + if (uc_emu_stop(handle) != UC_ERR_OK) { + printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + _exit(1); + } + else { + printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++); + } + break; + default: //all others + printf("# Handling OTHER\n"); + break; + } +} + +// callback for tracing memory access (READ or WRITE) +static void hook_mem_write(uch handle, uc_mem_type type, + uint64_t addr, int size, int64_t value, void *user_data) +{ + printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); +} + +// callback for tracing invalid memory access (READ or WRITE) +static bool hook_mem_invalid(uch handle, uc_mem_type type, + uint64_t addr, int size, int64_t value, void *user_data) +{ + uint32_t testval; + switch(type) { + default: + printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); + return false; + case UC_MEM_WRITE_NW: + printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); + + if (uc_mem_read(handle, addr, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail for address: 0x%" PRIx64 "\n", log_num++, addr); + } + else { + printf("ok %d - uc_mem_read success after mem_protect at test %d\n", log_num++, test_num - 1); + } + + if (uc_mem_protect(handle, addr & ~0xfff, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { + printf("not ok %d - uc_mem_protect fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } + else { + printf("ok %d - uc_mem_protect success\n", log_num++); + } + return true; + } +} + +int main(int argc, char **argv, char **envp) +{ + uch handle, trace1, trace2; + uc_err err; + uint32_t addr, testval; + int32_t buf1[1024], buf2[1024], readbuf[1024]; + int i; + + //don't really care about quality of randomness + srand(time(NULL)); + for (i = 0; i < 1024; i++) { + buf1[i] = rand(); + buf2[i] = rand(); + } + + printf("# Memory protect test\n"); + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + if (err) { + printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err); + return 1; + } + else { + printf("ok %d - uc_open() success\n", log_num++); + } + + uc_mem_map(handle, CODE_SECTION, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC); + uc_mem_map(handle, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(handle, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(handle, 0x3ff000, 0x3000, UC_PROT_READ | UC_PROT_WRITE); + + // fill in sections that shouldn't get touched + if (uc_mem_write(handle, 0x3ff000, (uint8_t*)buf1, 4096)) { + printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); + return 2; + } + else { + printf("ok %d - Random buffer 1 written to memory\n", log_num++); + } + + if (uc_mem_write(handle, 0x401000, (uint8_t*)buf2, 4096)) { + printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); + return 2; + } + else { + printf("ok %d - Random buffer 2 written to memory\n", log_num++); + } + + // write machine code to be emulated to memory + if (uc_mem_write(handle, CODE_SECTION, PROGRAM, sizeof(PROGRAM))) { + printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); + return 2; + } + else { + printf("ok %d - Program written to memory\n", log_num++); + } + + if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); + return 3; + } + else { + printf("ok %d - UC_HOOK_CODE installed\n", log_num++); + } + + // intercept memory write events + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); + return 4; + } + else { + printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); + } + + // intercept invalid memory events + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID handler\n", log_num++); + return 4; + } + else { + printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); + } + + // emulate machine code until told to stop by hook_code + printf("# BEGIN execution\n"); + err = uc_emu_start(handle, CODE_SECTION, CODE_SECTION + CODE_SIZE, 0, 100); + if (err != UC_ERR_OK) { + printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); + return 5; + } + else { + printf("ok %d - uc_emu_start complete\n", log_num++); + } + printf("# END execution\n"); + + //read from the remapped memory + testval = 0x42424242; + for (addr = 0x200000; addr <= 0x400000; addr += 0x100000) { + uint32_t val; + if (uc_mem_read(handle, addr, (uint8_t*)&val, sizeof(val)) != UC_ERR_OK) { + printf("not ok %d - Failed uc_mem_read for address 0x%x\n", log_num++, addr); + } + else { + printf("ok %d - Good uc_mem_read from 0x%x\n", log_num++, addr); + } + if (val != testval) { + printf("not ok %d - Read 0x%x, expected 0x%x\n", log_num++, val, testval); + } + else { + printf("ok %d - Correct value retrieved\n", log_num++); + } + testval += 0x02020202; + } + + //account for the two mods made by the machine code + buf1[512] = 0x47474747; + buf2[512] = 0x48484848; + + //make sure that random blocks didn't get nuked + // fill in sections that shouldn't get touched + if (uc_mem_read(handle, 0x3ff000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++); + } + else { + printf("ok %d - Random buffer 1 read from memory\n", log_num++); + if (memcmp(buf1, readbuf, 4096)) { + printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++); + } + else { + printf("ok %d - Random buffer 1 contents are correct\n", log_num++); + } + } + + if (uc_mem_read(handle, 0x401000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); + } + else { + printf("ok %d - Random buffer 2 read from memory\n", log_num++); + if (memcmp(buf2, readbuf, 4096)) { + printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++); + } + else { + printf("ok %d - Random buffer 2 contents are correct\n", log_num++); + } + } + + if (uc_close(&handle) == UC_ERR_OK) { + printf("ok %d - uc_close complete\n", log_num++); + } + else { + printf("not ok %d - uc_close complete\n", log_num++); + } + + return 0; +} diff --git a/samples/mem_unmap.c b/samples/mem_unmap.c new file mode 100755 index 00000000..60f3039a --- /dev/null +++ b/samples/mem_unmap.c @@ -0,0 +1,313 @@ +/* + +uc_mem_unmap demo / unit test + +Copyright(c) 2015 Chris Eagle + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#define __STDC_FORMAT_MACROS +#include +#include +#include +#include +#include +#include + +#include + +unsigned char PROGRAM[] = + "\xc7\x05\x00\x00\x20\x00\x41\x41\x41\x41\x90\xc7\x05\x00\x00\x20" + "\x00\x42\x42\x42\x42\xc7\x05\x00\x00\x30\x00\x43\x43\x43\x43\x90" + "\xc7\x05\x00\x00\x30\x00\x44\x44\x44\x44\xc7\x05\x00\x00\x40\x00" + "\x45\x45\x45\x45\x90\xc7\x05\x00\x00\x40\x00\x46\x46\x46\x46\xf4"; +// total size: 64 bytes + +/* +; assumes code section at 0x100000 +; assumes data section at 0x200000, initially rw +; assumes data section at 0x300000, initially rw +; assumes data section at 0x400000, initially rw + +; with installed hooks unmaps or maps on each nop + + mov dword [0x200000], 0x41414141 + nop ; unmap it + mov dword [0x200000], 0x42424242 + + mov dword [0x300000], 0x43434343 + nop ; unmap it + mov dword [0x300000], 0x44444444 + + mov dword [0x400000], 0x45454545 + nop ; unmap it + mov dword [0x400000], 0x46464646 + + hlt ; tell hook function we are done +*/ + +int test_num = 0; +uint32_t tests[] = { + 0x41414141, + 0x43434343, + 0x45454545 +}; + +static int log_num = 1; + +#define CODE_SECTION 0x100000 +#define CODE_SIZE 0x1000 + +// callback for tracing instruction +static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) +{ + uint8_t opcode; + uint32_t testval; + if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } + printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr); + switch (opcode) { + case 0x90: //nop + printf("# Handling NOP\n"); + if (uc_mem_read(handle, 0x200000 + test_num * 0x100000, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + } + else { + printf("ok %d - good uc_mem_read for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + printf("# uc_mem_read for test %d\n", test_num); + + if (testval == tests[test_num]) { + printf("ok %d - passed test %d\n", log_num++, test_num); + } + else { + printf("not ok %d - failed test %d\n", log_num++, test_num); + printf("# Expected: 0x%x\n",tests[test_num]); + printf("# Received: 0x%x\n", testval); + } + } + if (uc_mem_unmap(handle, 0x200000 + test_num * 0x100000, 0x1000) != UC_ERR_OK) { + printf("not ok %d - uc_mem_unmap fail during hook_code callback, addr: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + } + else { + printf("ok %d - uc_mem_unmap success\n", log_num++); + } + test_num++; + break; + case 0xf4: //hlt + printf("# Handling HLT\n"); + if (uc_emu_stop(handle) != UC_ERR_OK) { + printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + _exit(1); + } + else { + printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++); + } + break; + default: //all others + printf("# Handling OTHER\n"); + break; + } +} + +// callback for tracing memory access (READ or WRITE) +static void hook_mem_write(uch handle, uc_mem_type type, + uint64_t addr, int size, int64_t value, void *user_data) +{ + printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); +} + +// callback for tracing invalid memory access (READ or WRITE) +static bool hook_mem_invalid(uch handle, uc_mem_type type, + uint64_t addr, int size, int64_t value, void *user_data) +{ + uint32_t testval; + switch(type) { + default: + printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); + return false; + case UC_MEM_WRITE: + printf("# write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); + + if (uc_mem_read(handle, addr, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + printf("ok %d - uc_mem_read fail for address: 0x%" PRIx64 "\n", log_num++, addr); + } + else { + printf("not ok %d - uc_mem_read success after unmap at test %d\n", log_num++, test_num - 1); + } + + if (uc_mem_map(handle, addr & ~0xfff, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { + printf("not ok %d - uc_mem_map fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } + else { + printf("ok %d - uc_mem_map success\n", log_num++); + } + return true; + } +} + +int main(int argc, char **argv, char **envp) +{ + uch handle, trace1, trace2; + uc_err err; + uint32_t addr, testval; + int32_t buf1[1024], buf2[1024], readbuf[1024]; + int i; + + //don't really care about quality of randomness + srand(time(NULL)); + for (i = 0; i < 1024; i++) { + buf1[i] = rand(); + buf2[i] = rand(); + } + + printf("# Memory unmapping test\n"); + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + if (err) { + printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err); + return 1; + } + else { + printf("ok %d - uc_open() success\n", log_num++); + } + + uc_mem_map(handle, CODE_SECTION, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC); + uc_mem_map(handle, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(handle, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(handle, 0x3ff000, 0x3000, UC_PROT_READ | UC_PROT_WRITE); + + // fill in sections that shouldn't get touched + if (uc_mem_write(handle, 0x3ff000, (uint8_t*)buf1, 4096)) { + printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); + return 2; + } + else { + printf("ok %d - Random buffer 1 written to memory\n", log_num++); + } + + if (uc_mem_write(handle, 0x401000, (uint8_t*)buf2, 4096)) { + printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); + return 2; + } + else { + printf("ok %d - Random buffer 2 written to memory\n", log_num++); + } + + // write machine code to be emulated to memory + if (uc_mem_write(handle, CODE_SECTION, PROGRAM, sizeof(PROGRAM))) { + printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); + return 2; + } + else { + printf("ok %d - Program written to memory\n", log_num++); + } + + if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); + return 3; + } + else { + printf("ok %d - UC_HOOK_CODE installed\n", log_num++); + } + + // intercept memory write events + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); + return 4; + } + else { + printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); + } + + // intercept invalid memory events + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID handler\n", log_num++); + return 4; + } + else { + printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); + } + + // emulate machine code until told to stop by hook_code + printf("# BEGIN execution\n"); + err = uc_emu_start(handle, CODE_SECTION, CODE_SECTION + CODE_SIZE, 0, 100); + if (err != UC_ERR_OK) { + printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); + return 5; + } + else { + printf("ok %d - uc_emu_start complete\n", log_num++); + } + printf("# END execution\n"); + + //read from the remapped memory + testval = 0x42424242; + for (addr = 0x200000; addr <= 0x400000; addr += 0x100000) { + uint32_t val; + if (uc_mem_read(handle, addr, (uint8_t*)&val, sizeof(val)) != UC_ERR_OK) { + printf("not ok %d - Failed uc_mem_read for address 0x%x\n", log_num++, addr); + } + else { + printf("ok %d - Good uc_mem_read from 0x%x\n", log_num++, addr); + } + if (val != testval) { + printf("not ok %d - Read 0x%x, expected 0x%x\n", log_num++, val, testval); + } + else { + printf("ok %d - Correct value retrieved\n", log_num++); + } + testval += 0x02020202; + } + + //make sure that random blocks didn't get nuked + // fill in sections that shouldn't get touched + if (uc_mem_read(handle, 0x3ff000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++); + } + else { + printf("ok %d - Random buffer 1 read from memory\n", log_num++); + if (memcmp(buf1, readbuf, 4096)) { + printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++); + } + else { + printf("ok %d - Random buffer 1 contents are correct\n", log_num++); + } + } + + if (uc_mem_read(handle, 0x401000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); + } + else { + printf("ok %d - Random buffer 2 read from memory\n", log_num++); + if (memcmp(buf2, readbuf, 4096)) { + printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++); + } + else { + printf("ok %d - Random buffer 2 contents are correct\n", log_num++); + } + } + + if (uc_close(&handle) == UC_ERR_OK) { + printf("ok %d - uc_close complete\n", log_num++); + } + else { + printf("not ok %d - uc_close complete\n", log_num++); + } + + return 0; +} diff --git a/uc.c b/uc.c index 6dc2786d..13b395cf 100644 --- a/uc.c +++ b/uc.c @@ -638,7 +638,7 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms) return UC_ERR_MAP; // check for only valid permissions - if ((perms & ~(UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC)) != 0) + if ((perms & ~UC_PROT_ALL) != 0) return UC_ERR_MAP; if ((uc->mapped_block_count & (MEM_BLOCK_INCR - 1)) == 0) { //time to grow @@ -782,7 +782,7 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) return UC_ERR_MAP; // check for only valid permissions - if ((perms & ~(UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC)) != 0) + if ((perms & ~UC_PROT_ALL) != 0) return UC_ERR_MAP; //check that user's entire requested block is mapped @@ -790,50 +790,32 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) return UC_ERR_MAP; //Now we know entire region is mapped, so change permissions - //check trivial case first + //If request exactly matches a region we don't need to split mr = memory_mapping(uc, address); - if (address == mr->addr && size == int128_get64(mr->size)) { - //regions exactly matches an existing region just change perms - mr->perms = perms; - uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0); - } - else { + if (address != mr->addr || size != int128_get64(mr->size)) { //ouch, we are going to need to subdivide blocks -/* - address = start; - size = block_size; - while (size > 0) { - MemoryRegion *mr = memory_mapping(uc, address); - uint64_t region_size = int128_get64(mr->size); - if (address > mr->addr) { - //in case start address is not aligned with start of region - region_size -= address - mr->addr; - //TODO Learn how to split regions - //In this case some proper subset of the region is having it's permissions changed - //need to split region and add new portions into uc->mapped_blocks list - //In this case, there is a portion of the region with original perms: mr->addr..start - //and a portion getting new perms: start..start+block_size - - //split the block and stay in the loop - } - if (size < int128_get64(mr->size)) { - //TODO Learn how to split regions - //In this case some proper subset of the region is having it's permissions changed - //need to split region and add new portions into uc->mapped_blocks list - //In this case, there is a portion of the region with new perms: start..start+block_size - //and a portion getting new perms: mr->addr+size..mr->addr+mr->size - - //split the block and break - break; - } - size -= int128_get64(mr->size); - address += int128_get64(mr->size); - mr->perms = perms; - uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0); + uint64_t addr = address; + size_t count = 0, len; + while(count < size) { + MemoryRegion *mr = memory_mapping(uc, addr); + len = MIN(size - count, mr->end - addr); + if (!split_region(handle, mr, addr, len, false)) + return UC_ERR_MAP; + count += len; + addr += len; } -*/ - } - return UC_ERR_OK; + //Grab a pointer to the newly split MemoryRegion + mr = memory_mapping(uc, address); + if (mr == NULL) { + //this should never happern if splitting succeeded + return UC_ERR_MAP; + } + } + //regions exactly matches an existing region just change perms + mr->perms = perms; + uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0); + + return UC_ERR_OK; } UNICORN_EXPORT @@ -842,7 +824,6 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) MemoryRegion *mr; unsigned int i; struct uc_struct* uc = (struct uc_struct *)handle; - size_t count, len; if (handle == 0) // invalid handle @@ -882,7 +863,7 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) } else { //ouch, we are going to need to subdivide blocks - count = 0; + size_t count = 0, len; while(count < size) { MemoryRegion *mr = memory_mapping(uc, address); len = MIN(size - count, mr->end - address); From 05b645abd5922f3fe54ab92e8e66735d0e472b4a Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sun, 30 Aug 2015 14:01:46 -0700 Subject: [PATCH 28/64] fix perms --- samples/mem_protect.c | 0 samples/mem_unmap.c | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 samples/mem_protect.c mode change 100755 => 100644 samples/mem_unmap.c diff --git a/samples/mem_protect.c b/samples/mem_protect.c old mode 100755 new mode 100644 diff --git a/samples/mem_unmap.c b/samples/mem_unmap.c old mode 100755 new mode 100644 From 9e4e96ff47b540583a9869ad54b794316698985a Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sun, 30 Aug 2015 19:50:18 -0700 Subject: [PATCH 29/64] final updates for uc_mem_unmap, uc_mem_protect, and support ro UC_PROT_EXEC permission --- qemu/cputlb.c | 5 + samples/Makefile | 4 +- samples/mem_exec.c | 296 ++++++++++++++++++++++++++++++++++++++++++ samples/mem_protect.c | 18 +-- samples/mem_unmap.c | 18 +-- 5 files changed, 322 insertions(+), 19 deletions(-) create mode 100644 samples/mem_exec.c diff --git a/qemu/cputlb.c b/qemu/cputlb.c index cde8e30e..ed120082 100644 --- a/qemu/cputlb.c +++ b/qemu/cputlb.c @@ -299,6 +299,11 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr) if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code != (addr & TARGET_PAGE_MASK))) { cpu_ldub_code(env1, addr); + //check for NX related error from softmmu + if (env1->invalid_error == UC_ERR_MEM_READ) { + env1->invalid_error = UC_ERR_CODE_INVALID; + return -1; + } } pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK; mr = iotlb_to_region(cpu->as, pd); diff --git a/samples/Makefile b/samples/Makefile index 72d1ca45..f6345ae8 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -99,6 +99,7 @@ SOURCES += sample_x86.c SOURCES += shellcode.c SOURCES += mem_unmap.c SOURCES += mem_protect.c +SOURCES += mem_exec.c endif ifneq (,$(findstring m68k,$(UNICORN_ARCHS))) SOURCES += sample_m68k.c @@ -113,7 +114,8 @@ all: $(BINARY) clean: rm -rf *.o $(OBJS_ELF) $(BINARY) $(SAMPLEDIR)/*.exe $(SAMPLEDIR)/*.static $(OBJDIR)/lib$(LIBNAME)* $(OBJDIR)/$(LIBNAME)* rm -rf libunicorn*.so libunicorn*.lib libunicorn*.dylib unicorn*.dll unicorn*.lib - rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k shellcode mem_unmap mem_protect + rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k \ + shellcode mem_unmap mem_protect mem_exec $(BINARY): $(OBJS) diff --git a/samples/mem_exec.c b/samples/mem_exec.c new file mode 100644 index 00000000..b83ea7d0 --- /dev/null +++ b/samples/mem_exec.c @@ -0,0 +1,296 @@ +/* + +Executable memory regions demo / unit test + +Copyright(c) 2015 Chris Eagle + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#define __STDC_FORMAT_MACROS +#include +#include +#include +#include +#include +#include + +#include + +unsigned char PROGRAM[] = + "\xeb\x45\x5e\x81\xe6\x00\xf0\xff\xff\x40\x40\x40\x40\x40\x40\x40" + "\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40" + "\x40\x40\x40\x40\x40\x40\x40\x89\xf7\x81\xc7\x00\x00\x10\x00\xb9" + "\x4c\x00\x00\x00\x81\xff\x00\x00\x40\x00\x75\x01\xf4\xf3\xa4\x81" + "\xe7\x00\xf0\xff\xff\xff\xe7\xe8\xb6\xff\xff\xff"; +// total size: 76 bytes + +/* +bits 32 + +; assumes r-x section at 0x100000 +; assumes rw- section at 0x200000 +; assumes r-- section at 0x300000 +; also needs an initialized stack + +start: + jmp bottom +top: + pop esi + and esi, ~0xfff + times 30 inc eax + mov edi, esi + add edi, 0x100000 + mov ecx, end - start + rep movsb + and edi, ~0xfff + cmp edi, 0x400000 + jnz next_block + hlt +next_block: + jmp edi +bottom: + call top +end: +*/ + +int test_num = 0; +uint32_t tests[] = { + 0x41414141, + 0x43434343, + 0x45454545 +}; + +static int log_num = 1; + +#define CODE_SECTION 0x100000 +#define CODE_SIZE 0x1000 + +// callback for tracing instruction +static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) +{ + uint8_t opcode; + if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } +// printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr); + switch (opcode) { + case 0xf4: //hlt + printf("# Handling HLT\n"); + if (uc_emu_stop(handle) != UC_ERR_OK) { + printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + _exit(-1); + } + else { + printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++); + } + break; + default: //all others +// printf("# Handling OTHER\n"); + break; + } +} + +// callback for tracing memory access (READ or WRITE) +static void hook_mem_write(uch handle, uc_mem_type type, + uint64_t addr, int size, int64_t value, void *user_data) +{ + printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); +} + +// callback for tracing invalid memory access (READ or WRITE) +static bool hook_mem_invalid(uch handle, uc_mem_type type, + uint64_t addr, int size, int64_t value, void *user_data) +{ + switch(type) { + default: + printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); + return false; + case UC_MEM_NX: + printf("# Fetch from non-executable memory at 0x%"PRIx64 "\n", addr); + + //make page executable + if (uc_mem_protect(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_EXEC) != UC_ERR_OK) { + printf("not ok %d - uc_mem_protect fail for address: 0x%" PRIx64 "\n", log_num++, addr); + } + else { + printf("ok %d - uc_mem_protect success at 0x%" PRIx64 "\n", log_num++, addr); + } + return true; + case UC_MEM_WRITE_NW: + printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); + + if (uc_mem_protect(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { + printf("not ok %d - uc_mem_protect fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } + else { + printf("ok %d - uc_mem_protect success\n", log_num++); + } + return true; + } +} + +int main(int argc, char **argv, char **envp) +{ + uch handle, trace1, trace2; + uc_err err; + uint32_t esp, eip; + int32_t buf1[1024], buf2[1024], readbuf[1024]; + int i; + + //don't really care about quality of randomness + srand(time(NULL)); + for (i = 0; i < 1024; i++) { + buf1[i] = rand(); + buf2[i] = rand(); + } + + printf("# Memory protect test\n"); + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + if (err) { + printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err); + return 1; + } + else { + printf("ok %d - uc_open() success\n", log_num++); + } + + uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_READ | UC_PROT_EXEC); + uc_mem_map(handle, 0x1ff000, 0x2000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(handle, 0x300000, 0x2000, UC_PROT_READ); + uc_mem_map(handle, 0xf00000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + + esp = 0xf00000 + 0x1000; + + // Setup stack pointer + if (uc_reg_write(handle, UC_X86_REG_ESP, &esp)) { + printf("not ok %d - Failed to set esp. quit!\n", log_num++); + return 2; + } + else { + printf("ok %d - ESP set\n", log_num++); + } + + // fill in sections that shouldn't get touched + if (uc_mem_write(handle, 0x1ff000, (uint8_t*)buf1, 4096)) { + printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); + return 3; + } + else { + printf("ok %d - Random buffer 1 written to memory\n", log_num++); + } + + if (uc_mem_write(handle, 0x301000, (uint8_t*)buf2, 4096)) { + printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); + return 4; + } + else { + printf("ok %d - Random buffer 2 written to memory\n", log_num++); + } + + // write machine code to be emulated to memory + if (uc_mem_write(handle, 0x100000, PROGRAM, sizeof(PROGRAM))) { + printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); + return 5; + } + else { + printf("ok %d - Program written to memory\n", log_num++); + } + + if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); + return 6; + } + else { + printf("ok %d - UC_HOOK_CODE installed\n", log_num++); + } + + // intercept memory write events + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); + return 7; + } + else { + printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); + } + + // intercept invalid memory events + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID handler\n", log_num++); + return 8; + } + else { + printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); + } + + // emulate machine code until told to stop by hook_code + printf("# BEGIN execution\n"); + err = uc_emu_start(handle, 0x100000, 0x400000, 0, 0); + if (err != UC_ERR_OK) { + printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); + return 9; + } + else { + printf("ok %d - uc_emu_start complete\n", log_num++); + } + printf("# END execution\n"); + + // get ending EIP + if (uc_reg_read(handle, UC_X86_REG_EIP, &eip)) { + printf("not ok %d - Failed to read eip.\n", log_num++); + } + else { + printf("ok %d - Ending EIP 0x%x\n", log_num++, eip); + } + + //make sure that random blocks didn't get nuked + // fill in sections that shouldn't get touched + if (uc_mem_read(handle, 0x1ff000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++); + } + else { + printf("ok %d - Random buffer 1 read from memory\n", log_num++); + if (memcmp(buf1, readbuf, 4096)) { + printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++); + } + else { + printf("ok %d - Random buffer 1 contents are correct\n", log_num++); + } + } + + if (uc_mem_read(handle, 0x301000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); + } + else { + printf("ok %d - Random buffer 2 read from memory\n", log_num++); + if (memcmp(buf2, readbuf, 4096)) { + printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++); + } + else { + printf("ok %d - Random buffer 2 contents are correct\n", log_num++); + } + } + + if (uc_close(&handle) == UC_ERR_OK) { + printf("ok %d - uc_close complete\n", log_num++); + } + else { + printf("not ok %d - uc_close complete\n", log_num++); + } + + return 0; +} diff --git a/samples/mem_protect.c b/samples/mem_protect.c index 4afb88c1..025f9953 100644 --- a/samples/mem_protect.c +++ b/samples/mem_protect.c @@ -117,7 +117,7 @@ static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) printf("# Handling HLT\n"); if (uc_emu_stop(handle) != UC_ERR_OK) { printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); - _exit(1); + _exit(-1); } else { printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++); @@ -155,7 +155,7 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, printf("ok %d - uc_mem_read success after mem_protect at test %d\n", log_num++, test_num - 1); } - if (uc_mem_protect(handle, addr & ~0xfff, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { + if (uc_mem_protect(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { printf("not ok %d - uc_mem_protect fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); } else { @@ -208,7 +208,7 @@ int main(int argc, char **argv, char **envp) if (uc_mem_write(handle, 0x401000, (uint8_t*)buf2, 4096)) { printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); - return 2; + return 3; } else { printf("ok %d - Random buffer 2 written to memory\n", log_num++); @@ -217,7 +217,7 @@ int main(int argc, char **argv, char **envp) // write machine code to be emulated to memory if (uc_mem_write(handle, CODE_SECTION, PROGRAM, sizeof(PROGRAM))) { printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); - return 2; + return 4; } else { printf("ok %d - Program written to memory\n", log_num++); @@ -225,7 +225,7 @@ int main(int argc, char **argv, char **envp) if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); - return 3; + return 5; } else { printf("ok %d - UC_HOOK_CODE installed\n", log_num++); @@ -234,7 +234,7 @@ int main(int argc, char **argv, char **envp) // intercept memory write events if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); - return 4; + return 6; } else { printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); @@ -243,7 +243,7 @@ int main(int argc, char **argv, char **envp) // intercept invalid memory events if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID handler\n", log_num++); - return 4; + return 7; } else { printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); @@ -251,10 +251,10 @@ int main(int argc, char **argv, char **envp) // emulate machine code until told to stop by hook_code printf("# BEGIN execution\n"); - err = uc_emu_start(handle, CODE_SECTION, CODE_SECTION + CODE_SIZE, 0, 100); + err = uc_emu_start(handle, CODE_SECTION, CODE_SECTION + CODE_SIZE, 0, 0); if (err != UC_ERR_OK) { printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); - return 5; + return 8; } else { printf("ok %d - uc_emu_start complete\n", log_num++); diff --git a/samples/mem_unmap.c b/samples/mem_unmap.c index 60f3039a..6f93673d 100644 --- a/samples/mem_unmap.c +++ b/samples/mem_unmap.c @@ -111,7 +111,7 @@ static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) printf("# Handling HLT\n"); if (uc_emu_stop(handle) != UC_ERR_OK) { printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); - _exit(1); + _exit(-1); } else { printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++); @@ -149,7 +149,7 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, printf("not ok %d - uc_mem_read success after unmap at test %d\n", log_num++, test_num - 1); } - if (uc_mem_map(handle, addr & ~0xfff, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { + if (uc_mem_map(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { printf("not ok %d - uc_mem_map fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); } else { @@ -202,7 +202,7 @@ int main(int argc, char **argv, char **envp) if (uc_mem_write(handle, 0x401000, (uint8_t*)buf2, 4096)) { printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); - return 2; + return 3; } else { printf("ok %d - Random buffer 2 written to memory\n", log_num++); @@ -211,7 +211,7 @@ int main(int argc, char **argv, char **envp) // write machine code to be emulated to memory if (uc_mem_write(handle, CODE_SECTION, PROGRAM, sizeof(PROGRAM))) { printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); - return 2; + return 4; } else { printf("ok %d - Program written to memory\n", log_num++); @@ -219,7 +219,7 @@ int main(int argc, char **argv, char **envp) if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); - return 3; + return 5; } else { printf("ok %d - UC_HOOK_CODE installed\n", log_num++); @@ -228,7 +228,7 @@ int main(int argc, char **argv, char **envp) // intercept memory write events if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); - return 4; + return 6; } else { printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); @@ -237,7 +237,7 @@ int main(int argc, char **argv, char **envp) // intercept invalid memory events if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID handler\n", log_num++); - return 4; + return 7; } else { printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); @@ -245,10 +245,10 @@ int main(int argc, char **argv, char **envp) // emulate machine code until told to stop by hook_code printf("# BEGIN execution\n"); - err = uc_emu_start(handle, CODE_SECTION, CODE_SECTION + CODE_SIZE, 0, 100); + err = uc_emu_start(handle, CODE_SECTION, CODE_SECTION + CODE_SIZE, 0, 0); if (err != UC_ERR_OK) { printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); - return 5; + return 8; } else { printf("ok %d - uc_emu_start complete\n", log_num++); From 24dde77ec2392223a81ab02ece87188f8ee4ade5 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sun, 30 Aug 2015 20:38:38 -0700 Subject: [PATCH 30/64] fix uc_mem_type comments --- include/unicorn/unicorn.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index fee75297..e4b5e359 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -149,9 +149,9 @@ typedef enum uc_mem_type { UC_MEM_READ = 16, // Memory is read from UC_MEM_WRITE, // Memory is written to UC_MEM_READ_WRITE, // Memory is accessed (either READ or WRITE) - UC_MEM_WRITE_NW, // write to non-writable - UC_MEM_READ_NR, // read from non-readable - UC_MEM_NX, // read from non-readable + UC_MEM_WRITE_NW, // write to non-writable memory + UC_MEM_READ_NR, // read from non-readable memory + UC_MEM_NX, // fetch from non-executable memory } uc_mem_type; // All type of hooks for uc_hook_add() API. From 410e317e9265412a649b6df5f3b04a8b44f37228 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sun, 30 Aug 2015 21:24:14 -0700 Subject: [PATCH 31/64] dont use explicit page size, use TARGET_PAGE_SIZE --- qemu/memory.c | 2 +- uc.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/qemu/memory.c b/qemu/memory.c index 5e9cc9b0..f5b70f35 100644 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -49,7 +49,7 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) { target_ulong addr; //make sure all pages associated with the MemoryRegion are flushed - for (addr = mr->addr; addr < mr->end; addr += 0x1000) { + for (addr = mr->addr; addr < mr->end; addr += TARGET_PAGE_SIZE) { tlb_flush_page(uc->current_cpu, addr); } mr->enabled = false; diff --git a/uc.c b/uc.c index 13b395cf..ad2a7325 100644 --- a/uc.c +++ b/uc.c @@ -32,8 +32,8 @@ #include "qemu/include/hw/boards.h" //keep this a power of two! -#define UC_BLOCK_SIZE 0x1000 -#define UC_ALIGN_MASK (UC_BLOCK_SIZE - 1) +#define UC_PAGE_SIZE 0x1000 +#define UC_ALIGN_MASK (UC_PAGE_SIZE - 1) static uint8_t *copy_region(uch uc, MemoryRegion *mr); static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, size_t size, bool do_delete); @@ -629,11 +629,11 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms) // invalid memory mapping return UC_ERR_MAP; - // address must be aligned to UC_BLOCK_SIZE + // address must be aligned to UC_PAGE_SIZE if ((address & UC_ALIGN_MASK) != 0) return UC_ERR_MAP; - // size must be multiple of UC_BLOCK_SIZE + // size must be multiple of UC_PAGE_SIZE if ((size & UC_ALIGN_MASK) != 0) return UC_ERR_MAP; @@ -773,11 +773,11 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) // invalid memory mapping return UC_ERR_MAP; - // address must be aligned to UC_BLOCK_SIZE + // address must be aligned to UC_PAGE_SIZE if ((address & UC_ALIGN_MASK) != 0) return UC_ERR_MAP; - // size must be multiple of UC_BLOCK_SIZE + // size must be multiple of UC_PAGE_SIZE if ((size & UC_ALIGN_MASK) != 0) return UC_ERR_MAP; @@ -833,11 +833,11 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) // nothing to unmap return UC_ERR_OK; - // address must be aligned to UC_BLOCK_SIZE + // address must be aligned to UC_PAGE_SIZE if ((address & UC_ALIGN_MASK) != 0) return UC_ERR_MAP; - // size must be multiple of UC_BLOCK_SIZE + // size must be multiple of UC_PAGE_SIZE if ((size & UC_ALIGN_MASK) != 0) return UC_ERR_MAP; From b27e9879321606997851b86890e2c6b30a909da8 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Mon, 31 Aug 2015 01:00:44 -0700 Subject: [PATCH 32/64] Add target_page_size member to uc_struct to track TARGET_PAGE_SIZE --- include/uc_priv.h | 3 +++ qemu/memory.c | 2 +- qemu/unicorn_common.h | 3 +++ uc.c | 28 ++++++++++++---------------- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 695b5fc6..aff7a7d7 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -175,6 +175,9 @@ struct uc_struct { bool block_full; MemoryRegion **mapped_blocks; uint32_t mapped_block_count; + + uint32_t target_page_size; + uint32_t target_page_align; }; #include "qemu_macro.h" diff --git a/qemu/memory.c b/qemu/memory.c index f5b70f35..e04d59b7 100644 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -49,7 +49,7 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) { target_ulong addr; //make sure all pages associated with the MemoryRegion are flushed - for (addr = mr->addr; addr < mr->end; addr += TARGET_PAGE_SIZE) { + for (addr = mr->addr; addr < mr->end; addr += uc->target_page_size) { tlb_flush_page(uc->current_cpu, addr); } mr->enabled = false; diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index 23ef0acb..5ba74fac 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -76,6 +76,9 @@ static inline void uc_common_init(struct uc_struct* uc) uc->memory_unmap = memory_unmap; uc->readonly_mem = memory_region_set_readonly; + uc->target_page_size = TARGET_PAGE_SIZE; + uc->target_page_align = TARGET_PAGE_SIZE - 1; + if (!uc->release) uc->release = release_common; } diff --git a/uc.c b/uc.c index ad2a7325..2dddb39c 100644 --- a/uc.c +++ b/uc.c @@ -31,10 +31,6 @@ #include "qemu/include/hw/boards.h" -//keep this a power of two! -#define UC_PAGE_SIZE 0x1000 -#define UC_ALIGN_MASK (UC_PAGE_SIZE - 1) - static uint8_t *copy_region(uch uc, MemoryRegion *mr); static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, size_t size, bool do_delete); @@ -629,12 +625,12 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms) // invalid memory mapping return UC_ERR_MAP; - // address must be aligned to UC_PAGE_SIZE - if ((address & UC_ALIGN_MASK) != 0) + // address must be aligned to uc->target_page_size + if ((address & uc->target_page_align) != 0) return UC_ERR_MAP; - // size must be multiple of UC_PAGE_SIZE - if ((size & UC_ALIGN_MASK) != 0) + // size must be multiple of uc->target_page_size + if ((size & uc->target_page_align) != 0) return UC_ERR_MAP; // check for only valid permissions @@ -773,12 +769,12 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) // invalid memory mapping return UC_ERR_MAP; - // address must be aligned to UC_PAGE_SIZE - if ((address & UC_ALIGN_MASK) != 0) + // address must be aligned to uc->target_page_size + if ((address & uc->target_page_align) != 0) return UC_ERR_MAP; - // size must be multiple of UC_PAGE_SIZE - if ((size & UC_ALIGN_MASK) != 0) + // size must be multiple of uc->target_page_size + if ((size & uc->target_page_align) != 0) return UC_ERR_MAP; // check for only valid permissions @@ -833,12 +829,12 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) // nothing to unmap return UC_ERR_OK; - // address must be aligned to UC_PAGE_SIZE - if ((address & UC_ALIGN_MASK) != 0) + // address must be aligned to uc->target_page_size + if ((address & uc->target_page_align) != 0) return UC_ERR_MAP; - // size must be multiple of UC_PAGE_SIZE - if ((size & UC_ALIGN_MASK) != 0) + // size must be multiple of uc->target_page_size + if ((size & uc->target_page_align) != 0) return UC_ERR_MAP; //check that user's entire requested block is mapped From 658e399776954f046689c5409486437af5e9bc3d Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Mon, 31 Aug 2015 19:08:48 -0700 Subject: [PATCH 33/64] clean up mem_protect related constants --- include/unicorn/unicorn.h | 5 +++-- qemu/softmmu_template.h | 16 ++++++++-------- uc.c | 10 ++++++---- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index e4b5e359..962598a8 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -116,8 +116,9 @@ typedef enum uc_err { UC_ERR_HOOK, // Invalid hook type: uc_hook_add() UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start() UC_ERR_MAP, // Invalid memory mapping: uc_mem_map() - UC_ERR_MEM_WRITE_NW, // Quit emulation due to write to non-writable: uc_emu_start() - UC_ERR_MEM_READ_NR, // Quit emulation due to read from non-readable: uc_emu_start() + UC_ERR_PROT_WRITE, // Quit emulation due to UC_PROT_WRITE violation: uc_emu_start() + UC_ERR_PROT_READ, // Quit emulation due to UC_PROT_READ violation: uc_emu_start() + UC_ERR_PROT_EXEC, // Quit emulation due to UC_PROT_EXEC violation: uc_emu_start() } uc_err; diff --git a/qemu/softmmu_template.h b/qemu/softmmu_template.h index 8c181824..a448a787 100644 --- a/qemu/softmmu_template.h +++ b/qemu/softmmu_template.h @@ -191,8 +191,8 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_MEM_READ; - // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); + env->invalid_error = UC_ERR_PROT_EXEC; + // printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return 0; } @@ -233,7 +233,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_MEM_READ_NR; + env->invalid_error = UC_ERR_PROT_READ; // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return 0; @@ -350,8 +350,8 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_MEM_READ; - // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); + env->invalid_error = UC_ERR_PROT_EXEC; + // printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return 0; } @@ -392,7 +392,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_MEM_READ_NR; + env->invalid_error = UC_ERR_PROT_READ; // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return 0; @@ -571,7 +571,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_MEM_WRITE_NW; + env->invalid_error = UC_ERR_PROT_WRITE; // printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return; @@ -705,7 +705,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_MEM_WRITE_NW; + env->invalid_error = UC_ERR_PROT_WRITE; // printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return; diff --git a/uc.c b/uc.c index 2dddb39c..85624a36 100644 --- a/uc.c +++ b/uc.c @@ -92,10 +92,12 @@ const char *uc_strerror(uc_err code) return "Invalid hook type (UC_ERR_HOOK)"; case UC_ERR_MAP: return "Invalid memory mapping (UC_ERR_MAP)"; - case UC_ERR_MEM_WRITE_NW: - return "Write to non-writable (UC_ERR_MEM_WRITE_NW)"; - case UC_ERR_MEM_READ_NR: - return "Read from non-readable (UC_ERR_MEM_READ_NR)"; + case UC_ERR_PROT_WRITE: + return "Write to non-writable memory (UC_ERR_PROT_WRITE)"; + case UC_ERR_PROT_READ: + return "Read from non-readable memory (UC_ERR_PROT_READ)"; + case UC_ERR_PROT_EXEC: + return "Fetch from non-executable memory (UC_ERR_PROT_EXEC)"; } } From 95059407ee50e4c705918814be002b42605ffe4c Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Mon, 31 Aug 2015 23:52:22 -0700 Subject: [PATCH 34/64] add regression for callbacks generated during movsb --- regress/rep_movsb.c | 183 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 regress/rep_movsb.c diff --git a/regress/rep_movsb.c b/regress/rep_movsb.c new file mode 100644 index 00000000..ab49175b --- /dev/null +++ b/regress/rep_movsb.c @@ -0,0 +1,183 @@ +/* + +rep movsb regression + +Copyright(c) 2015 Chris Eagle + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#define __STDC_FORMAT_MACROS +#include +#include +#include +#include +#include +#include + +#include + +unsigned char PROGRAM[] = + "\xbe\x00\x00\x20\x00\xbf\x00\x10\x20\x00\xb9\x14\x00\x00\x00\xf3" + "\xa4\xf4"; +// total size: 18 bytes + +/* +bits 32 + +; assumes code section at 0x100000 r-x +; assumes data section at 0x200000-0x202000, rw- + +mov esi, 0x200000 +mov edi, 0x201000 +mov ecx, 20 +rep movsb +hlt +*/ + +static int log_num = 1; + +// callback for tracing instruction +static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) +{ + uint8_t opcode; + if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + _exit(-1); + } + switch (opcode) { + case 0xf4: //hlt + printf("# Handling HLT\n"); + if (uc_emu_stop(handle) != UC_ERR_OK) { + printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + _exit(-1); + } + else { + printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++); + } + break; + default: //all others + break; + } +} + +// callback for tracing memory access (READ or WRITE) +static void hook_mem_write(uch handle, uc_mem_type type, + uint64_t addr, int size, int64_t value, void *user_data) +{ + printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); + if (addr < 0x201000L) { + //this is actually a read, we don't write in this range + printf("not ok %d - write hook called for read of 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", log_num++, addr, size, value); + } + else { + printf("ok %d - write hook called for write of 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", log_num++, addr, size, value); + } +} + +int main(int argc, char **argv, char **envp) +{ + uch handle, trace1, trace2; + uc_err err; + uint8_t buf1[100], readbuf[100]; + + printf("# rep movsb test\n"); + + memset(buf1, 'A', 20); + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + if (err) { + printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err); + return 1; + } + else { + printf("ok %d - uc_open() success\n", log_num++); + } + + uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_READ); + uc_mem_map(handle, 0x200000, 0x2000, UC_PROT_READ | UC_PROT_WRITE); + + // fill in the data that we want to copy + if (uc_mem_write(handle, 0x200000, (uint8_t*)buf1, 20)) { + printf("not ok %d - Failed to write read buffer to memory, quit!\n", log_num++); + return 2; + } + else { + printf("ok %d - Read buffer written to memory\n", log_num++); + } + + // write machine code to be emulated to memory + if (uc_mem_write(handle, 0x100000, PROGRAM, sizeof(PROGRAM))) { + printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); + return 4; + } + else { + printf("ok %d - Program written to memory\n", log_num++); + } + + if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); + return 5; + } + else { + printf("ok %d - UC_HOOK_CODE installed\n", log_num++); + } + + // intercept memory write events only, NOT read events + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); + return 6; + } + else { + printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); + } + + // emulate machine code until told to stop by hook_code + printf("# BEGIN execution\n"); + err = uc_emu_start(handle, 0x100000, 0x101000, 0, 0); + if (err != UC_ERR_OK) { + printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); + return 8; + } + else { + printf("ok %d - uc_emu_start complete\n", log_num++); + } + printf("# END execution\n"); + + //make sure that data got copied + // fill in sections that shouldn't get touched + if (uc_mem_read(handle, 0x201000, (uint8_t*)readbuf, 20)) { + printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++); + } + else { + printf("ok %d - Random buffer 1 read from memory\n", log_num++); + if (memcmp(buf1, readbuf, 20)) { + printf("not ok %d - write buffer contents are incorrect\n", log_num++); + } + else { + printf("ok %d - write buffer contents are correct\n", log_num++); + } + } + + if (uc_close(&handle) == UC_ERR_OK) { + printf("ok %d - uc_close complete\n", log_num++); + } + else { + printf("not ok %d - uc_close complete\n", log_num++); + } + + return 0; +} From 0e13ab6c3f62e269d1b54ef36dbd5f4a4fda5f8c Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 1 Sep 2015 20:05:33 +0800 Subject: [PATCH 35/64] compile regress/rep_movsb.c --- .gitignore | 1 + regress/Makefile | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 99d9edc7..fade14b3 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,4 @@ regress/map_write regress/ro_mem_test regress/nr_mem_test regress/timeout_segfault +regress/rep_movsb diff --git a/regress/Makefile b/regress/Makefile index bbb49c2a..806db172 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -6,6 +6,7 @@ TESTS += sigill sigill2 TESTS += block_test TESTS += ro_mem_test nr_mem_test TESTS += timeout_segfault +TESTS += rep_movsb all: $(TESTS) From 4f7b91d0b738149260bab7392bfc93fa85d65606 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 1 Sep 2015 23:34:06 +0800 Subject: [PATCH 36/64] minor fix for instructions in COMPILE.TXT --- COMPILE.TXT | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/COMPILE.TXT b/COMPILE.TXT index bd0910be..5887f094 100644 --- a/COMPILE.TXT +++ b/COMPILE.TXT @@ -87,7 +87,7 @@ Unicorn requires few dependent packages as followings Users are then required to enter root password to copy Unicorn into machine system directories. - Afterwards, run ./tests/test* to see the tests disassembling sample code. + Afterwards, run ./samples/sample_all.sh to see the sample emulations. NOTE: The core framework installed by "./make.sh install" consist of From 90fc201f8d1e2f676aabb31a0bd8605e1529b243 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 2 Sep 2015 00:16:45 +0800 Subject: [PATCH 37/64] x86: enable bunch of instructions via CPUID. this fixes issue #91 --- qemu/target-i386/unicorn.c | 5 +++++ regress/pshufb.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index c6350213..b0bd2f57 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -54,6 +54,11 @@ void x86_reg_reset(uch handle) CPUArchState *env; env = first_cpu->env_ptr; + env->features[FEAT_1_EDX] = CPUID_CX8 | CPUID_CMOV | CPUID_SSE2 | CPUID_FXSR | CPUID_SSE | CPUID_CLFLUSH; + env->features[FEAT_1_ECX] = CPUID_EXT_SSSE3 | CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_AES; + env->features[FEAT_8000_0001_EDX] = CPUID_EXT2_3DNOW | CPUID_EXT2_RDTSCP; + env->features[FEAT_8000_0001_ECX] = CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_SKINIT | CPUID_EXT3_CR8LEG; + env->features[FEAT_7_0_EBX] = CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP; env->invalid_error = UC_ERR_OK; // no error memset(env->regs, 0, sizeof(env->regs)); diff --git a/regress/pshufb.py b/regress/pshufb.py index 0d01bf5e..432a2300 100755 --- a/regress/pshufb.py +++ b/regress/pshufb.py @@ -9,4 +9,4 @@ uc = Uc(UC_ARCH_X86, UC_MODE_64) uc.mem_map(0x2000, 0x1000) # pshufb xmm0, xmm1 uc.mem_write(0x2000, '660f3800c1'.decode('hex')) -uc.emu_start(0x2000, 0) +uc.emu_start(0x2000, 0x2005) From 2c4f3769d443969be07556c27f394d84fc9e2bb6 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Tue, 1 Sep 2015 12:10:09 -0700 Subject: [PATCH 38/64] clean up mem_protect related constants and error codes --- include/unicorn/unicorn.h | 12 ++++++------ qemu/softmmu_template.h | 24 ++++++++++++------------ samples/mem_exec.c | 4 ++-- samples/mem_protect.c | 2 +- uc.c | 12 ++++++------ 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 962598a8..9a39c8a6 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -116,9 +116,9 @@ typedef enum uc_err { UC_ERR_HOOK, // Invalid hook type: uc_hook_add() UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start() UC_ERR_MAP, // Invalid memory mapping: uc_mem_map() - UC_ERR_PROT_WRITE, // Quit emulation due to UC_PROT_WRITE violation: uc_emu_start() - UC_ERR_PROT_READ, // Quit emulation due to UC_PROT_READ violation: uc_emu_start() - UC_ERR_PROT_EXEC, // Quit emulation due to UC_PROT_EXEC violation: uc_emu_start() + UC_ERR_WRITE_PROT, // Quit emulation due to UC_PROT_WRITE violation: uc_emu_start() + UC_ERR_READ_PROT, // Quit emulation due to UC_PROT_READ violation: uc_emu_start() + UC_ERR_EXEC_PROT, // Quit emulation due to UC_PROT_EXEC violation: uc_emu_start() } uc_err; @@ -150,9 +150,9 @@ typedef enum uc_mem_type { UC_MEM_READ = 16, // Memory is read from UC_MEM_WRITE, // Memory is written to UC_MEM_READ_WRITE, // Memory is accessed (either READ or WRITE) - UC_MEM_WRITE_NW, // write to non-writable memory - UC_MEM_READ_NR, // read from non-readable memory - UC_MEM_NX, // fetch from non-executable memory + UC_MEM_WRITE_PROT, // write to write protected memory + UC_MEM_READ_PROT, // read from read protected memory + UC_MEM_EXEC_PROT, // fetch from non-executable memory } uc_mem_type; // All type of hooks for uc_hook_add() API. diff --git a/qemu/softmmu_template.h b/qemu/softmmu_template.h index a448a787..de47e769 100644 --- a/qemu/softmmu_template.h +++ b/qemu/softmmu_template.h @@ -185,13 +185,13 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on fetch from NX if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { //non-executable if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_NX, addr, DATA_SIZE, 0, + (uch)uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_PROT_EXEC; + env->invalid_error = UC_ERR_EXEC_PROT; // printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return 0; @@ -227,13 +227,13 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on non-readable memory if (mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_READ_NR, addr, DATA_SIZE, 0, + (uch)uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_PROT_READ; + env->invalid_error = UC_ERR_READ_PROT; // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return 0; @@ -344,13 +344,13 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on fetch from NX if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { //non-executable if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_NX, addr, DATA_SIZE, 0, + (uch)uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_PROT_EXEC; + env->invalid_error = UC_ERR_EXEC_PROT; // printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return 0; @@ -386,13 +386,13 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on non-readable memory if (mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_READ_NR, addr, DATA_SIZE, 0, + (uch)uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_PROT_READ; + env->invalid_error = UC_ERR_READ_PROT; // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return 0; @@ -565,13 +565,13 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on non-writable memory if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_WRITE_NW, addr, DATA_SIZE, (int64_t)val, + (uch)uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_PROT_WRITE; + env->invalid_error = UC_ERR_WRITE_PROT; // printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return; @@ -699,13 +699,13 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on non-writable memory if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_WRITE_NW, addr, DATA_SIZE, (int64_t)val, + (uch)uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_PROT_WRITE; + env->invalid_error = UC_ERR_WRITE_PROT; // printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return; diff --git a/samples/mem_exec.c b/samples/mem_exec.c index b83ea7d0..171022a7 100644 --- a/samples/mem_exec.c +++ b/samples/mem_exec.c @@ -118,7 +118,7 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, default: printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); return false; - case UC_MEM_NX: + case UC_MEM_EXEC_PROT: printf("# Fetch from non-executable memory at 0x%"PRIx64 "\n", addr); //make page executable @@ -129,7 +129,7 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, printf("ok %d - uc_mem_protect success at 0x%" PRIx64 "\n", log_num++, addr); } return true; - case UC_MEM_WRITE_NW: + case UC_MEM_WRITE_PROT: printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); if (uc_mem_protect(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { diff --git a/samples/mem_protect.c b/samples/mem_protect.c index 025f9953..5d852ff5 100644 --- a/samples/mem_protect.c +++ b/samples/mem_protect.c @@ -145,7 +145,7 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, default: printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); return false; - case UC_MEM_WRITE_NW: + case UC_MEM_WRITE_PROT: printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); if (uc_mem_read(handle, addr, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { diff --git a/uc.c b/uc.c index 85624a36..177c8cf3 100644 --- a/uc.c +++ b/uc.c @@ -92,12 +92,12 @@ const char *uc_strerror(uc_err code) return "Invalid hook type (UC_ERR_HOOK)"; case UC_ERR_MAP: return "Invalid memory mapping (UC_ERR_MAP)"; - case UC_ERR_PROT_WRITE: - return "Write to non-writable memory (UC_ERR_PROT_WRITE)"; - case UC_ERR_PROT_READ: - return "Read from non-readable memory (UC_ERR_PROT_READ)"; - case UC_ERR_PROT_EXEC: - return "Fetch from non-executable memory (UC_ERR_PROT_EXEC)"; + case UC_ERR_WRITE_PROT: + return "Write to write-protected memory (UC_ERR_WRITE_PROT)"; + case UC_ERR_READ_PROT: + return "Read from non-readable memory (UC_ERR_READ_PROT)"; + case UC_ERR_EXEC_PROT: + return "Fetch from non-executable memory (UC_ERR_EXEC_PROT)"; } } From ad877e6af059c77980675a914c41a0d8a4d43a21 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Tue, 1 Sep 2015 13:40:19 -0700 Subject: [PATCH 39/64] Add error value UC_ERR_INVAL and rename UC_ERR_OOM to UC_ERR_NOMEM to provide more error specificity --- include/unicorn/unicorn.h | 28 ++++++++++---------- uc.c | 54 ++++++++++++++++++++------------------- 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 9a39c8a6..cbac0506 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -104,7 +104,7 @@ typedef enum uc_mode { // These are values returned by uc_errno() typedef enum uc_err { UC_ERR_OK = 0, // No error: everything was fine - UC_ERR_OOM, // Out-Of-Memory error: uc_open(), uc_emulate() + UC_ERR_NOMEM, // Out-Of-Memory error: uc_open(), uc_emulate() UC_ERR_ARCH, // Unsupported architecture: uc_open() UC_ERR_HANDLE, // Invalid handle UC_ERR_UCH, // Invalid handle (uch) @@ -119,6 +119,7 @@ typedef enum uc_err { UC_ERR_WRITE_PROT, // Quit emulation due to UC_PROT_WRITE violation: uc_emu_start() UC_ERR_READ_PROT, // Quit emulation due to UC_PROT_READ violation: uc_emu_start() UC_ERR_EXEC_PROT, // Quit emulation due to UC_PROT_EXEC violation: uc_emu_start() + UC_ERR_INVAL, // Inavalid argument provided to uc_xxx function (See specific function API) } uc_err; @@ -405,15 +406,15 @@ typedef enum uc_prot { @handle: handle returned by uc_open() @address: starting address of the new memory region to be mapped in. - This address must be aligned to 4KB, or this will return with UC_ERR_MAP error. + This address must be aligned to 4KB, or this will return with UC_ERR_INVAL error. @size: size of the new memory region to be mapped in. - This size must be multiple of 4KB, or this will return with UC_ERR_MAP error. + This size must be multiple of 4KB, or this will return with UC_ERR_INVAL error. @perms: Permissions for the newly mapped region. This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, - or this will return with UC_ERR_MAP error. + or this will return with UC_ERR_INVAL error. - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). + @return UC_ERR_OK on success, UC_ERR_NOMEM if no memory is available to satisfy the + request, or other value on failure (refer to uc_err enum for detailed error). */ UNICORN_EXPORT uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms); @@ -424,15 +425,16 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms); @handle: handle returned by uc_open() @address: starting address of the memory region to be modified. - This address must be aligned to 4KB, or this will return with UC_ERR_MAP error. + This address must be aligned to 4KB, or this will return with UC_ERR_INVAL error. @size: size of the memory region to be modified. - This size must be multiple of 4KB, or this will return with UC_ERR_MAP error. + This size must be multiple of 4KB, or this will return with UC_ERR_INVAL error. @perms: New permissions for the mapped region. This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, - or this will return with UC_ERR_MAP error. + or this will return with UC_ERR_INVAL error. - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). + @return UC_ERR_OK on success, UC_ERR_HANDLE for an invalid handle, UC_ERR_INVAL + for invalid perms or unaligned address or size, UC_ERR_NOMEM if entire region + is not mapped. */ UNICORN_EXPORT uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms); @@ -443,9 +445,9 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) @handle: handle returned by uc_open() @address: starting address of the memory region to be unmapped. - This address must be aligned to 4KB, or this will return with UC_ERR_MAP error. + This address must be aligned to 4KB, or this will return with UC_ERR_INVAL error. @size: size of the memory region to be modified. - This size must be multiple of 4KB, or this will return with UC_ERR_MAP error. + This size must be multiple of 4KB, or this will return with UC_ERR_INVAL error. @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum for detailed error). diff --git a/uc.c b/uc.c index 177c8cf3..32a9af70 100644 --- a/uc.c +++ b/uc.c @@ -68,8 +68,8 @@ const char *uc_strerror(uc_err code) return "Unknown error code"; case UC_ERR_OK: return "OK (UC_ERR_OK)"; - case UC_ERR_OOM: - return "Out of memory (UC_ERR_OOM)"; + case UC_ERR_NOMEM: + return "No memory available or memory not present (UC_ERR_NOMEM)"; case UC_ERR_ARCH: return "Invalid/unsupported architecture(UC_ERR_ARCH)"; case UC_ERR_HANDLE: @@ -98,6 +98,8 @@ const char *uc_strerror(uc_err code) return "Read from non-readable memory (UC_ERR_READ_PROT)"; case UC_ERR_EXEC_PROT: return "Fetch from non-executable memory (UC_ERR_EXEC_PROT)"; + case UC_ERR_INVAL: + return "Invalid argumet (UC_ERR_INVAL)"; } } @@ -143,7 +145,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uch *handle) uc = calloc(1, sizeof(*uc)); if (!uc) { // memory insufficient - return UC_ERR_OOM; + return UC_ERR_NOMEM; } uc->errnum = UC_ERR_OK; @@ -590,7 +592,7 @@ static int _hook_code(uch handle, int type, uint64_t begin, uint64_t end, i = hook_add(handle, type, begin, end, callback, user_data); if (i == 0) - return UC_ERR_OOM; // FIXME + return UC_ERR_NOMEM; // FIXME *h2 = i; @@ -606,7 +608,7 @@ static uc_err _hook_mem_access(uch handle, uc_mem_type type, i = hook_add(handle, type, begin, end, callback, user_data); if (i == 0) - return UC_ERR_OOM; // FIXME + return UC_ERR_NOMEM; // FIXME *h2 = i; @@ -625,24 +627,24 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms) if (size == 0) // invalid memory mapping - return UC_ERR_MAP; + return UC_ERR_INVAL; // address must be aligned to uc->target_page_size if ((address & uc->target_page_align) != 0) - return UC_ERR_MAP; + return UC_ERR_INVAL; // size must be multiple of uc->target_page_size if ((size & uc->target_page_align) != 0) - return UC_ERR_MAP; + return UC_ERR_INVAL; // check for only valid permissions if ((perms & ~UC_PROT_ALL) != 0) - return UC_ERR_MAP; + return UC_ERR_INVAL; if ((uc->mapped_block_count & (MEM_BLOCK_INCR - 1)) == 0) { //time to grow regions = (MemoryRegion**)realloc(uc->mapped_blocks, sizeof(MemoryRegion*) * (uc->mapped_block_count + MEM_BLOCK_INCR)); if (regions == NULL) { - return UC_ERR_OOM; + return UC_ERR_NOMEM; } uc->mapped_blocks = regions; } @@ -768,24 +770,24 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) return UC_ERR_UCH; if (size == 0) - // invalid memory mapping - return UC_ERR_MAP; + // trivial case, no change + return UC_ERR_OK; // address must be aligned to uc->target_page_size if ((address & uc->target_page_align) != 0) - return UC_ERR_MAP; + return UC_ERR_INVAL; // size must be multiple of uc->target_page_size if ((size & uc->target_page_align) != 0) - return UC_ERR_MAP; + return UC_ERR_INVAL; // check for only valid permissions if ((perms & ~UC_PROT_ALL) != 0) - return UC_ERR_MAP; + return UC_ERR_INVAL; //check that user's entire requested block is mapped if (!check_mem_area(uc, address, size)) - return UC_ERR_MAP; + return UC_ERR_NOMEM; //Now we know entire region is mapped, so change permissions //If request exactly matches a region we don't need to split @@ -798,7 +800,7 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) MemoryRegion *mr = memory_mapping(uc, addr); len = MIN(size - count, mr->end - addr); if (!split_region(handle, mr, addr, len, false)) - return UC_ERR_MAP; + return UC_ERR_NOMEM; count += len; addr += len; } @@ -806,7 +808,7 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) mr = memory_mapping(uc, address); if (mr == NULL) { //this should never happern if splitting succeeded - return UC_ERR_MAP; + return UC_ERR_NOMEM; } } //regions exactly matches an existing region just change perms @@ -833,7 +835,7 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) // address must be aligned to uc->target_page_size if ((address & uc->target_page_align) != 0) - return UC_ERR_MAP; + return UC_ERR_INVAL; // size must be multiple of uc->target_page_size if ((size & uc->target_page_align) != 0) @@ -841,7 +843,7 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) //check that user's entire requested block is mapped if (!check_mem_area(uc, address, size)) - return UC_ERR_MAP; + return UC_ERR_NOMEM; //Now we know entire region is mapped, so begin the delete //check trivial case first @@ -866,7 +868,7 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) MemoryRegion *mr = memory_mapping(uc, address); len = MIN(size - count, mr->end - address); if (!split_region(handle, mr, address, len, true)) - return UC_ERR_MAP; + return UC_ERR_NOMEM; count += len; address += len; } @@ -902,7 +904,7 @@ static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_eventmem_t callback, uc->hook_mem_idx = i; return UC_ERR_OK; } else - return UC_ERR_OOM; + return UC_ERR_NOMEM; } @@ -921,7 +923,7 @@ static uc_err _hook_intr(struct uc_struct* uc, void *callback, uc->hook_intr_idx = i; return UC_ERR_OK; } else - return UC_ERR_OOM; + return UC_ERR_NOMEM; } @@ -945,7 +947,7 @@ static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callb uc->hook_out_idx = i; return UC_ERR_OK; } else - return UC_ERR_OOM; + return UC_ERR_NOMEM; case UC_X86_INS_IN: // FIXME: only one event handler at the same time i = hook_find_new(uc); @@ -956,7 +958,7 @@ static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callb uc->hook_in_idx = i; return UC_ERR_OK; } else - return UC_ERR_OOM; + return UC_ERR_NOMEM; case UC_X86_INS_SYSCALL: case UC_X86_INS_SYSENTER: // FIXME: only one event handler at the same time @@ -968,7 +970,7 @@ static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callb uc->hook_syscall_idx = i; return UC_ERR_OK; } else - return UC_ERR_OOM; + return UC_ERR_NOMEM; } break; } From db8f499fe94107a30e352cd2f3655ac36c440135 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Tue, 1 Sep 2015 18:58:02 -0700 Subject: [PATCH 40/64] fix crash on some SSE instructions --- qemu/target-i386/translate.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index a3b09fd5..137d9159 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -2944,8 +2944,8 @@ typedef void (*SSEFunc_0_epl)(TCGContext *s, TCGv_ptr env, TCGv_ptr reg, TCGv_i6 typedef void (*SSEFunc_0_epp)(TCGContext *s, TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b); typedef void (*SSEFunc_0_eppi)(TCGContext *s, TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val); -typedef void (*SSEFunc_0_ppi)(TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val); -typedef void (*SSEFunc_0_eppt)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, +typedef void (*SSEFunc_0_ppi)(TCGContext *s, TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val); +typedef void (*SSEFunc_0_eppt)(TCGContext *s, TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv val); #define SSE_SPECIAL ((void *)1) @@ -4669,7 +4669,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, tcg_gen_addi_ptr(tcg_ctx, cpu_ptr1, cpu_env, op2_offset); /* XXX: introduce a new table? */ sse_fn_ppi = (SSEFunc_0_ppi)sse_fn_epp; - sse_fn_ppi(cpu_ptr0, cpu_ptr1, tcg_const_i32(tcg_ctx, val)); + sse_fn_ppi(tcg_ctx, cpu_ptr0, cpu_ptr1, tcg_const_i32(tcg_ctx, val)); break; case 0xc2: /* compare insns */ @@ -4694,7 +4694,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, tcg_gen_addi_ptr(tcg_ctx, cpu_ptr1, cpu_env, op2_offset); /* XXX: introduce a new table? */ sse_fn_eppt = (SSEFunc_0_eppt)sse_fn_epp; - sse_fn_eppt(cpu_env, cpu_ptr0, cpu_ptr1, cpu_A0); + sse_fn_eppt(tcg_ctx, cpu_env, cpu_ptr0, cpu_ptr1, cpu_A0); break; default: tcg_gen_addi_ptr(tcg_ctx, cpu_ptr0, cpu_env, op1_offset); From 5f7a912f5db975b8e6600874ed348fc8a5fdefa8 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 2 Sep 2015 10:44:26 +0800 Subject: [PATCH 41/64] better instructions for install Msys2 on Windows --- COMPILE.TXT | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/COMPILE.TXT b/COMPILE.TXT index 5887f094..fa2b1d7c 100644 --- a/COMPILE.TXT +++ b/COMPILE.TXT @@ -178,8 +178,16 @@ Unicorn requires few dependent packages as followings [7] Compile on Windows with MinGW (MSYS2) To compile with MinGW you need to install MSYS2: https://msys2.github.io/ - Follow the install instructions and don't forget to update the system packages as written in 5 & 6 paragraphs + Follow the install instructions and don't forget to update the system packages with: + + $ pacman --needed -Sy bash pacman pacman-mirrors msys2-runtime + + Then close MSYS2, run it again from Start menu and update the rest with: + + $ pacman -Su + Finally, compile Unicorn with the next steps: + - To compile Windows 32-bit binary with MinGW, run: $ pacman -S make $ pacman -S pkg-config From a94e31165d56573e77163aa81d39426f0d464432 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 2 Sep 2015 12:00:43 +0800 Subject: [PATCH 42/64] x86: fix issue #95 --- qemu/target-i386/translate.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index 137d9159..07c877f1 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -8175,9 +8175,15 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, // printf("\n"); if (changed_cc_op) { if (cc_op_dirty) +#if TCG_TARGET_REG_BITS == 32 + *(save_opparam_ptr + 16) = s->pc - pc_start; + else + *(save_opparam_ptr + 14) = s->pc - pc_start; +#else *(save_opparam_ptr + 12) = s->pc - pc_start; else *(save_opparam_ptr + 10) = s->pc - pc_start; +#endif } else { *(save_opparam_ptr + 1) = s->pc - pc_start; } From 8b39ec5b0c4d291a7d01df92a64778355bca8cef Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 2 Sep 2015 16:13:12 +0800 Subject: [PATCH 43/64] initial support to remove a static variable in qemu-thread-win32.c --- include/uc_priv.h | 2 ++ qemu/cpus.c | 4 ++-- qemu/include/qemu/thread.h | 7 ++++--- qemu/util/qemu-thread-posix.c | 6 +++--- qemu/util/qemu-thread-win32.c | 14 ++++++-------- uc.c | 2 +- 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 007fecea..7a51767b 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -172,6 +172,8 @@ struct uc_struct { bool block_full; MemoryRegion **mapped_blocks; uint32_t mapped_block_count; + + void *qemu_thread_data; // to support cross compile to Windows (qemu-thread-win32.c) }; #include "qemu_macro.h" diff --git a/qemu/cpus.c b/qemu/cpus.c index ecc66e83..e274fe5a 100644 --- a/qemu/cpus.c +++ b/qemu/cpus.c @@ -124,7 +124,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) struct uc_struct *uc = cpu->uc; //qemu_tcg_init_cpu_signals(); - qemu_thread_get_self(cpu->thread); + qemu_thread_get_self(uc, cpu->thread); qemu_mutex_lock(&uc->qemu_global_mutex); CPU_FOREACH(cpu) { @@ -185,7 +185,7 @@ static void qemu_tcg_init_vcpu(CPUState *cpu) uc->tcg_halt_cond = cpu->halt_cond; snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG", cpu->cpu_index); - qemu_thread_create(cpu->thread, thread_name, qemu_tcg_cpu_thread_fn, + qemu_thread_create(uc, cpu->thread, thread_name, qemu_tcg_cpu_thread_fn, cpu, QEMU_THREAD_JOINABLE); #ifdef _WIN32 cpu->hThread = qemu_thread_get_handle(cpu->thread); diff --git a/qemu/include/qemu/thread.h b/qemu/include/qemu/thread.h index ef2f6962..de5956b2 100644 --- a/qemu/include/qemu/thread.h +++ b/qemu/include/qemu/thread.h @@ -52,12 +52,13 @@ void qemu_event_reset(QemuEvent *ev); void qemu_event_wait(QemuEvent *ev); void qemu_event_destroy(QemuEvent *ev); -void qemu_thread_create(QemuThread *thread, const char *name, +struct uc_struct; +void qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *name, void *(*start_routine)(void *), void *arg, int mode); void *qemu_thread_join(QemuThread *thread); -void qemu_thread_get_self(QemuThread *thread); +void qemu_thread_get_self(struct uc_struct *uc, QemuThread *thread); bool qemu_thread_is_self(QemuThread *thread); -void qemu_thread_exit(void *retval); +void qemu_thread_exit(struct uc_struct *uc, void *retval); #endif diff --git a/qemu/util/qemu-thread-posix.c b/qemu/util/qemu-thread-posix.c index 1e8f8304..34632bca 100644 --- a/qemu/util/qemu-thread-posix.c +++ b/qemu/util/qemu-thread-posix.c @@ -389,7 +389,7 @@ void qemu_event_wait(QemuEvent *ev) } } -void qemu_thread_create(QemuThread *thread, const char *name, +void qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *name, void *(*start_routine)(void*), void *arg, int mode) { @@ -426,7 +426,7 @@ void qemu_thread_create(QemuThread *thread, const char *name, pthread_attr_destroy(&attr); } -void qemu_thread_get_self(QemuThread *thread) +void qemu_thread_get_self(struct uc_struct *uc, QemuThread *thread) { thread->thread = pthread_self(); } @@ -436,7 +436,7 @@ bool qemu_thread_is_self(QemuThread *thread) return pthread_equal(pthread_self(), thread->thread); } -void qemu_thread_exit(void *retval) +void qemu_thread_exit(struct uc_struct *uc, void *retval) { pthread_exit(retval); } diff --git a/qemu/util/qemu-thread-win32.c b/qemu/util/qemu-thread-win32.c index 004f17bf..51ca88f8 100644 --- a/qemu/util/qemu-thread-win32.c +++ b/qemu/util/qemu-thread-win32.c @@ -266,8 +266,6 @@ struct QemuThreadData { CRITICAL_SECTION cs; }; -static __thread QemuThreadData *qemu_thread_data; - static unsigned __stdcall win32_start_routine(void *arg) { QemuThreadData *data = (QemuThreadData *) arg; @@ -278,14 +276,13 @@ static unsigned __stdcall win32_start_routine(void *arg) g_free(data); data = NULL; } - qemu_thread_data = data; qemu_thread_exit(start_routine(thread_arg)); abort(); } -void qemu_thread_exit(void *arg) +void qemu_thread_exit(struct uc_struct *uc, void *arg) { - QemuThreadData *data = qemu_thread_data; + QemuThreadData *data = uc->qemu_thread_data; if (data) { assert(data->mode != QEMU_THREAD_DETACHED); @@ -326,7 +323,7 @@ void *qemu_thread_join(QemuThread *thread) return ret; } -void qemu_thread_create(QemuThread *thread, const char *name, +void qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *name, void *(*start_routine)(void *), void *arg, int mode) { @@ -338,6 +335,7 @@ void qemu_thread_create(QemuThread *thread, const char *name, data->arg = arg; data->mode = mode; data->exited = false; + uc->qemu_thread_data = data; if (data->mode != QEMU_THREAD_DETACHED) { InitializeCriticalSection(&data->cs); @@ -352,9 +350,9 @@ void qemu_thread_create(QemuThread *thread, const char *name, thread->data = (mode == QEMU_THREAD_DETACHED) ? NULL : data; } -void qemu_thread_get_self(QemuThread *thread) +void qemu_thread_get_self(struct uc_struct *uc, QemuThread *thread) { - thread->data = qemu_thread_data; + thread->data = uc->qemu_thread_data; thread->tid = GetCurrentThreadId(); } diff --git a/uc.c b/uc.c index 6d93d0e7..d1584b4f 100644 --- a/uc.c +++ b/uc.c @@ -465,7 +465,7 @@ static void enable_emu_timer(uch handle, uint64_t timeout) struct uc_struct *uc = (struct uc_struct *)handle; uc->timeout = timeout; - qemu_thread_create(&uc->timer, "timeout", _timeout_fn, + qemu_thread_create(uc, &uc->timer, "timeout", _timeout_fn, uc, QEMU_THREAD_JOINABLE); } From 2d9db36a2b79afe995c39d07de4db5378deb0e7b Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 2 Sep 2015 01:34:23 -0700 Subject: [PATCH 44/64] fix some errors introduced by the last commit on qemu-thread-win32.c --- qemu/util/qemu-thread-win32.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/qemu/util/qemu-thread-win32.c b/qemu/util/qemu-thread-win32.c index 51ca88f8..3f7f7015 100644 --- a/qemu/util/qemu-thread-win32.c +++ b/qemu/util/qemu-thread-win32.c @@ -16,6 +16,8 @@ #include #include +#include "uc_priv.h" + static void error_exit(int err, const char *msg) { @@ -264,6 +266,7 @@ struct QemuThreadData { bool exited; void *ret; CRITICAL_SECTION cs; + struct uc_struct *uc; }; static unsigned __stdcall win32_start_routine(void *arg) @@ -276,7 +279,7 @@ static unsigned __stdcall win32_start_routine(void *arg) g_free(data); data = NULL; } - qemu_thread_exit(start_routine(thread_arg)); + qemu_thread_exit(data->uc, start_routine(thread_arg)); abort(); } @@ -335,6 +338,8 @@ void qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *na data->arg = arg; data->mode = mode; data->exited = false; + data->uc = uc; + uc->qemu_thread_data = data; if (data->mode != QEMU_THREAD_DETACHED) { From 4a2f23db60c786a846f4797290455a35eb334e3b Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Sep 2015 01:10:35 +0800 Subject: [PATCH 45/64] regress: fix rep_movsb.c to properly use uc_hook_add() API --- regress/rep_movsb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/regress/rep_movsb.c b/regress/rep_movsb.c index ab49175b..c9fb6f15 100644 --- a/regress/rep_movsb.c +++ b/regress/rep_movsb.c @@ -128,7 +128,7 @@ int main(int argc, char **argv, char **envp) printf("ok %d - Program written to memory\n", log_num++); } - if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { + if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); return 5; } @@ -137,7 +137,7 @@ int main(int argc, char **argv, char **envp) } // intercept memory write events only, NOT read events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); return 6; } From be659d201d0fdcd9509241763af2b56abbd0afd2 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Sep 2015 01:12:49 +0800 Subject: [PATCH 46/64] fix confusion betweet UC_MEM_xxx & UC_HOOK_MEM_xxx. fix issue #93 --- hook.c | 21 +++++++++++---------- qemu/softmmu_template.h | 8 ++++---- uc.c | 7 ++++--- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/hook.c b/hook.c index 6a26d70d..f4690506 100644 --- a/hook.c +++ b/hook.c @@ -67,17 +67,17 @@ size_t hook_add(uch handle, int type, uint64_t begin, uint64_t end, void *callba if (begin > end) uc->hook_insn_idx = i; break; - case UC_MEM_READ: + case UC_HOOK_MEM_READ: uc->hook_mem_read = true; if (begin > end) uc->hook_read_idx = i; break; - case UC_MEM_WRITE: + case UC_HOOK_MEM_WRITE: uc->hook_mem_write = true; if (begin > end) uc->hook_write_idx = i; break; - case UC_MEM_READ_WRITE: + case UC_HOOK_MEM_READ_WRITE: uc->hook_mem_read = true; uc->hook_mem_write = true; if (begin > end) { @@ -162,12 +162,13 @@ static struct hook_struct *_hook_find(struct uc_struct *uc, int type, uint64_t a if (uc->hook_insn_idx) return &uc->hook_callbacks[uc->hook_insn_idx]; break; - case UC_MEM_READ: + case UC_HOOK_MEM_READ: // already hooked all memory read? - if (uc->hook_read_idx) + if (uc->hook_read_idx) { return &uc->hook_callbacks[uc->hook_read_idx]; + } break; - case UC_MEM_WRITE: + case UC_HOOK_MEM_WRITE: // already hooked all memory write? if (uc->hook_write_idx) return &uc->hook_callbacks[uc->hook_write_idx]; @@ -185,14 +186,14 @@ static struct hook_struct *_hook_find(struct uc_struct *uc, int type, uint64_t a return &uc->hook_callbacks[i]; } break; - case UC_MEM_READ: - if (uc->hook_callbacks[i].hook_type == UC_MEM_READ || uc->hook_callbacks[i].hook_type == UC_MEM_READ_WRITE) { + case UC_HOOK_MEM_READ: + if (uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_READ || uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_READ_WRITE) { if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end) return &uc->hook_callbacks[i]; } break; - case UC_MEM_WRITE: - if (uc->hook_callbacks[i].hook_type == UC_MEM_WRITE || uc->hook_callbacks[i].hook_type == UC_MEM_READ_WRITE) { + case UC_HOOK_MEM_WRITE: + if (uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_WRITE || uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_READ_WRITE) { if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end) return &uc->hook_callbacks[i]; } diff --git a/qemu/softmmu_template.h b/qemu/softmmu_template.h index 56f657a4..3def3e76 100644 --- a/qemu/softmmu_template.h +++ b/qemu/softmmu_template.h @@ -183,7 +183,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on memory read if (env->uc->hook_mem_read && READ_ACCESS_TYPE == MMU_DATA_LOAD) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_MEM_READ, addr); + struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_MEM_READ, addr); if (trace) { ((uc_cb_hookmem_t)trace->callback)((uch)env->uc, UC_MEM_READ, (uint64_t)addr, (int)DATA_SIZE, (int64_t)0, trace->user_data); @@ -328,7 +328,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on memory read if (env->uc->hook_mem_read && READ_ACCESS_TYPE == MMU_DATA_LOAD) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_MEM_READ, addr); + struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_MEM_READ, addr); if (trace) { ((uc_cb_hookmem_t)trace->callback)((uch)env->uc, UC_MEM_READ, (uint64_t)addr, (int)DATA_SIZE, (int64_t)0, trace->user_data); @@ -511,7 +511,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on memory write if (uc->hook_mem_write) { - struct hook_struct *trace = hook_find((uch)uc, UC_MEM_WRITE, addr); + struct hook_struct *trace = hook_find((uch)uc, UC_HOOK_MEM_WRITE, addr); if (trace) { ((uc_cb_hookmem_t)trace->callback)((uch)uc, UC_MEM_WRITE, (uint64_t)addr, (int)DATA_SIZE, (int64_t)val, trace->user_data); @@ -649,7 +649,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on memory write if (uc->hook_mem_write) { - struct hook_struct *trace = hook_find((uch)uc, UC_MEM_WRITE, addr); + struct hook_struct *trace = hook_find((uch)uc, UC_HOOK_MEM_WRITE, addr); if (trace) { ((uc_cb_hookmem_t)trace->callback)((uch)uc, UC_MEM_WRITE, (uint64_t)addr, (int)DATA_SIZE, (int64_t)val, trace->user_data); diff --git a/uc.c b/uc.c index d1584b4f..c42123e0 100644 --- a/uc.c +++ b/uc.c @@ -791,16 +791,17 @@ uc_err uc_hook_add(uch handle, uch *h2, uc_hook_t type, void *callback, void *us case UC_HOOK_MEM_READ: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_mem_access(handle, UC_MEM_READ, begin, end, callback, user_data, h2); + ret = _hook_mem_access(handle, UC_HOOK_MEM_READ, begin, end, callback, user_data, h2); break; case UC_HOOK_MEM_WRITE: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_mem_access(handle, UC_MEM_WRITE, begin, end, callback, user_data, h2); + ret = _hook_mem_access(handle, UC_HOOK_MEM_WRITE, begin, end, callback, user_data, h2); + break; case UC_HOOK_MEM_READ_WRITE: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_mem_access(handle, UC_MEM_READ_WRITE, begin, end, callback, user_data, h2); + ret = _hook_mem_access(handle, UC_HOOK_MEM_READ_WRITE, begin, end, callback, user_data, h2); break; } From 03683a7960314ea26f878519aa0a667b996fc3ec Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Sep 2015 01:18:41 +0800 Subject: [PATCH 47/64] fix an warning caused by _hook_mem_access() --- uc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uc.c b/uc.c index c42123e0..e0e9c655 100644 --- a/uc.c +++ b/uc.c @@ -593,7 +593,7 @@ static int _hook_code(uch handle, int type, uint64_t begin, uint64_t end, } -static uc_err _hook_mem_access(uch handle, uc_mem_type type, +static uc_err _hook_mem_access(uch handle, uc_hook_t type, uint64_t begin, uint64_t end, void *callback, void *user_data, uch *h2) { From fe51b9a9aee15e524c4576f3d71bad71eca9fb58 Mon Sep 17 00:00:00 2001 From: Sean Heelan Date: Thu, 3 Sep 2015 00:48:20 +0700 Subject: [PATCH 48/64] Regression test for issue #98 This is a problem with sign extension during uc_reg_write --- regress/reg_write_sign_extension.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 regress/reg_write_sign_extension.py diff --git a/regress/reg_write_sign_extension.py b/regress/reg_write_sign_extension.py new file mode 100644 index 00000000..69347c0f --- /dev/null +++ b/regress/reg_write_sign_extension.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +"""See https://github.com/unicorn-engine/unicorn/issues/98""" + +import unicorn +ADDR = 0xffaabbcc + +def hook_mem_invalid(mu, access, address, size, value, user_data): + print ">>> Expected value: 0x%x, actual value: 0x%x" % (ADDR, address) + assert(address == ADDR) + mu.mem_map(address & 0xfffff000, 4 * 1024) + mu.mem_write(address, b'\xcc') + return True + +mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) +mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, ADDR) + +mu.mem_map(0x10000000, 1024 * 4) +# jmp ebx +mu.mem_write(0x10000000, b'\xff\xe3') + +mu.hook_add(unicorn.UC_HOOK_MEM_INVALID, hook_mem_invalid) +mu.emu_start(0x10000000, 0x10000000 + 2, count=1) From 0feab69a6138c6202ba4845f775dd7dd578a6cee Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 2 Sep 2015 21:25:59 -0400 Subject: [PATCH 49/64] update samples to conform to uc API changes --- regress/map_write.c | 10 +++---- regress/nr_mem_test.c | 31 +++++++++++----------- regress/rep_movsb.c | 31 +++++++++++----------- regress/ro_mem_test.c | 47 +++++++++++++++++---------------- regress/timeout_segfault.c | 54 +++++++++++++++++++------------------- 5 files changed, 88 insertions(+), 85 deletions(-) diff --git a/regress/map_write.c b/regress/map_write.c index e5b94366..400b4719 100644 --- a/regress/map_write.c +++ b/regress/map_write.c @@ -8,17 +8,17 @@ int main() { - uch uh; + struct uc_struct *uc; uint8_t *buf, *buf2; int i; uc_err err; - err = uc_open (UC_ARCH_X86, UC_MODE_64, &uh); + err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc); if (err) { printf ("uc_open %d\n", err); return 1; } - err = uc_mem_map (uh, ADDR, SIZE, UC_PROT_ALL); + err = uc_mem_map (uc, ADDR, SIZE, UC_PROT_ALL); if (err) { printf ("uc_mem_map %d\n", err); return 1; @@ -29,12 +29,12 @@ int main() buf[i] = i & 0xff; } /* crash here */ - err = uc_mem_write (uh, ADDR, buf, SIZE+OVERFLOW); + err = uc_mem_write (uc, ADDR, buf, SIZE+OVERFLOW); if (err) { printf ("uc_mem_map %d\n", err); return 1; } - err = uc_mem_read (uh, ADDR+10, buf2, 4); + err = uc_mem_read (uc, ADDR+10, buf2, 4); if (err) { printf ("uc_mem_map %d\n", err); return 1; diff --git a/regress/nr_mem_test.c b/regress/nr_mem_test.c index 37c344de..1f45cb1d 100644 --- a/regress/nr_mem_test.c +++ b/regress/nr_mem_test.c @@ -36,7 +36,7 @@ bits 32 */ // callback for tracing memory access (READ or WRITE) -static bool hook_mem_invalid(uch handle, uc_mem_type type, +static bool hook_mem_invalid(struct uc_struct *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { @@ -54,42 +54,43 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, int main(int argc, char **argv, char **envp) { - uch handle, trace1, trace2; + struct uc_struct *uc; + uc_hook_h trace1, trace2; uc_err err; uint32_t eax, ebx; printf("Memory protections test\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return 1; } - uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_READ); - uc_mem_map(handle, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); - uc_mem_map(handle, 0x400000, 0x1000, UC_PROT_WRITE); + uc_mem_map(uc, 0x100000, 0x1000, UC_PROT_READ); + uc_mem_map(uc, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, 0x400000, 0x1000, UC_PROT_WRITE); // write machine code to be emulated to memory - if (uc_mem_write(handle, 0x100000, PROGRAM, sizeof(PROGRAM))) { + if (uc_mem_write(uc, 0x100000, PROGRAM, sizeof(PROGRAM))) { printf("Failed to write emulation code to memory, quit!\n"); return 2; } else { printf("Allowed to write to read only memory via uc_mem_write\n"); } - uc_mem_write(handle, 0x300000, (const uint8_t*)"\x41\x41\x41\x41", 4); - uc_mem_write(handle, 0x400000, (const uint8_t*)"\x42\x42\x42\x42", 4); + uc_mem_write(uc, 0x300000, (const uint8_t*)"\x41\x41\x41\x41", 4); + uc_mem_write(uc, 0x400000, (const uint8_t*)"\x42\x42\x42\x42", 4); - //uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); + //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); // intercept invalid memory events - uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); // emulate machine code in infinite time printf("BEGIN execution\n"); - err = uc_emu_start(handle, 0x100000, 0x100000 + sizeof(PROGRAM), 0, 2); + err = uc_emu_start(uc, 0x100000, 0x100000 + sizeof(PROGRAM), 0, 2); if (err) { printf("Expected failure on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -98,12 +99,12 @@ int main(int argc, char **argv, char **envp) } printf("END execution\n"); - uc_reg_read(handle, UC_X86_REG_EAX, &eax); + uc_reg_read(uc, UC_X86_REG_EAX, &eax); printf("Final eax = 0x%x\n", eax); - uc_reg_read(handle, UC_X86_REG_EBX, &ebx); + uc_reg_read(uc, UC_X86_REG_EBX, &ebx); printf("Final ebx = 0x%x\n", ebx); - uc_close(&handle); + uc_close(uc); return 0; } diff --git a/regress/rep_movsb.c b/regress/rep_movsb.c index c9fb6f15..0b36e07c 100644 --- a/regress/rep_movsb.c +++ b/regress/rep_movsb.c @@ -50,17 +50,17 @@ hlt static int log_num = 1; // callback for tracing instruction -static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) +static void hook_code(struct uc_struct *uc, uint64_t addr, uint32_t size, void *user_data) { uint8_t opcode; - if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) { + if (uc_mem_read(uc, addr, &opcode, 1) != UC_ERR_OK) { printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); _exit(-1); } switch (opcode) { case 0xf4: //hlt printf("# Handling HLT\n"); - if (uc_emu_stop(handle) != UC_ERR_OK) { + if (uc_emu_stop(uc) != UC_ERR_OK) { printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); _exit(-1); } @@ -74,7 +74,7 @@ static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) } // callback for tracing memory access (READ or WRITE) -static void hook_mem_write(uch handle, uc_mem_type type, +static void hook_mem_write(struct uc_struct *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) { printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); @@ -89,7 +89,8 @@ static void hook_mem_write(uch handle, uc_mem_type type, int main(int argc, char **argv, char **envp) { - uch handle, trace1, trace2; + struct uc_struct *uc; + uc_hook_h trace1, trace2; uc_err err; uint8_t buf1[100], readbuf[100]; @@ -98,7 +99,7 @@ int main(int argc, char **argv, char **envp) memset(buf1, 'A', 20); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err); return 1; @@ -107,11 +108,11 @@ int main(int argc, char **argv, char **envp) printf("ok %d - uc_open() success\n", log_num++); } - uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_READ); - uc_mem_map(handle, 0x200000, 0x2000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, 0x100000, 0x1000, UC_PROT_READ); + uc_mem_map(uc, 0x200000, 0x2000, UC_PROT_READ | UC_PROT_WRITE); // fill in the data that we want to copy - if (uc_mem_write(handle, 0x200000, (uint8_t*)buf1, 20)) { + if (uc_mem_write(uc, 0x200000, (uint8_t*)buf1, 20)) { printf("not ok %d - Failed to write read buffer to memory, quit!\n", log_num++); return 2; } @@ -120,7 +121,7 @@ int main(int argc, char **argv, char **envp) } // write machine code to be emulated to memory - if (uc_mem_write(handle, 0x100000, PROGRAM, sizeof(PROGRAM))) { + if (uc_mem_write(uc, 0x100000, PROGRAM, sizeof(PROGRAM))) { printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); return 4; } @@ -128,7 +129,7 @@ int main(int argc, char **argv, char **envp) printf("ok %d - Program written to memory\n", log_num++); } - if (uc_hook_add(handle, &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, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); return 5; } @@ -137,7 +138,7 @@ int main(int argc, char **argv, char **envp) } // intercept memory write events only, NOT read events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); return 6; } @@ -147,7 +148,7 @@ int main(int argc, char **argv, char **envp) // emulate machine code until told to stop by hook_code printf("# BEGIN execution\n"); - err = uc_emu_start(handle, 0x100000, 0x101000, 0, 0); + err = uc_emu_start(uc, 0x100000, 0x101000, 0, 0); if (err != UC_ERR_OK) { printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); return 8; @@ -159,7 +160,7 @@ int main(int argc, char **argv, char **envp) //make sure that data got copied // fill in sections that shouldn't get touched - if (uc_mem_read(handle, 0x201000, (uint8_t*)readbuf, 20)) { + if (uc_mem_read(uc, 0x201000, (uint8_t*)readbuf, 20)) { printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++); } else { @@ -172,7 +173,7 @@ int main(int argc, char **argv, char **envp) } } - if (uc_close(&handle) == UC_ERR_OK) { + if (uc_close(uc) == UC_ERR_OK) { printf("ok %d - uc_close complete\n", log_num++); } else { diff --git a/regress/ro_mem_test.c b/regress/ro_mem_test.c index 06edf068..75b0d9bf 100644 --- a/regress/ro_mem_test.c +++ b/regress/ro_mem_test.c @@ -46,22 +46,22 @@ bottom: */ // callback for tracing instruction -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { uint32_t esp; printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); - uc_reg_read(handle, UC_X86_REG_ESP, &esp); + uc_reg_read(uc, UC_X86_REG_ESP, &esp); printf(">>> --- ESP is 0x%x\n", esp); } // callback for tracing memory access (READ or WRITE) -static bool hook_mem_invalid(uch handle, uc_mem_type type, +static bool hook_mem_invalid(struct uc_struct *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { uint32_t esp; - uc_reg_read(handle, UC_X86_REG_ESP, &esp); + uc_reg_read(uc, UC_X86_REG_ESP, &esp); switch(type) { default: @@ -74,7 +74,7 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, upper = (esp + 0xfff) & ~0xfff; printf(">>> Stack appears to be missing at 0x%"PRIx64 ", allocating now\n", address); // map this memory in with 2MB in size - uc_mem_map(handle, upper - 0x8000, 0x8000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, upper - 0x8000, 0x8000, UC_PROT_READ | UC_PROT_WRITE); // return true to indicate we want to continue return true; } @@ -94,7 +94,8 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, int main(int argc, char **argv, char **envp) { - uch handle, trace1, trace2; + struct uc_struct *uc; + uc_hook_h trace1, trace2; uc_err err; uint8_t bytes[8]; uint32_t esp; @@ -108,44 +109,44 @@ int main(int argc, char **argv, char **envp) printf("Memory mapping test\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return 1; } - uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_ALL); - uc_mem_map(handle, 0x200000, 0x2000, UC_PROT_ALL); - uc_mem_map(handle, 0x300000, 0x3000, UC_PROT_ALL); - uc_mem_map(handle, 0x400000, 0x4000, UC_PROT_READ); + uc_mem_map(uc, 0x100000, 0x1000, UC_PROT_ALL); + uc_mem_map(uc, 0x200000, 0x2000, UC_PROT_ALL); + uc_mem_map(uc, 0x300000, 0x3000, UC_PROT_ALL); + uc_mem_map(uc, 0x400000, 0x4000, UC_PROT_READ); if (map_stack) { printf("Pre-mapping stack\n"); - uc_mem_map(handle, STACK, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, STACK, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE); } else { printf("Mapping stack on first invalid memory access\n"); } esp = STACK + STACK_SIZE; - uc_reg_write(handle, UC_X86_REG_ESP, &esp); + uc_reg_write(uc, UC_X86_REG_ESP, &esp); // write machine code to be emulated to memory - if (uc_mem_write(handle, 0x400000, PROGRAM, sizeof(PROGRAM))) { + if (uc_mem_write(uc, 0x400000, PROGRAM, sizeof(PROGRAM))) { printf("Failed to write emulation code to memory, quit!\n"); return 2; } else { printf("Allowed to write to read only memory via uc_mem_write\n"); } - //uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); + //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); // intercept invalid memory events - uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); // emulate machine code in infinite time printf("BEGIN execution - 1\n"); - err = uc_emu_start(handle, 0x400000, 0x400000 + sizeof(PROGRAM), 0, 10); + err = uc_emu_start(uc, 0x400000, 0x400000 + sizeof(PROGRAM), 0, 10); if (err) { printf("Expected failue on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -157,8 +158,8 @@ int main(int argc, char **argv, char **envp) // emulate machine code in infinite time printf("BEGIN execution - 2\n"); uint32_t eax = 0x40002C; - uc_reg_write(handle, UC_X86_REG_EAX, &eax); - err = uc_emu_start(handle, 0x400015, 0x400000 + sizeof(PROGRAM), 0, 2); + uc_reg_write(uc, UC_X86_REG_EAX, &eax); + err = uc_emu_start(uc, 0x400015, 0x400000 + sizeof(PROGRAM), 0, 2); if (err) { printf("Expected failure on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -168,7 +169,7 @@ int main(int argc, char **argv, char **envp) printf("END execution - 2\n"); printf("Verifying content at 0x400025 is unchanged\n"); - if (!uc_mem_read(handle, 0x400025, bytes, 4)) { + if (!uc_mem_read(uc, 0x400025, bytes, 4)) { printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)0x400025, *(uint32_t*) bytes); if (0x41414141 != *(uint32_t*) bytes) { printf("ERROR content in read only memory changed\n"); @@ -181,7 +182,7 @@ int main(int argc, char **argv, char **envp) } printf("Verifying content at 0x40002C is unchanged\n"); - if (!uc_mem_read(handle, 0x40002C, bytes, 4)) { + if (!uc_mem_read(uc, 0x40002C, bytes, 4)) { printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)0x40002C, *(uint32_t*) bytes); if (0x42424242 != *(uint32_t*) bytes) { printf("ERROR content in read only memory changed\n"); @@ -194,14 +195,14 @@ int main(int argc, char **argv, char **envp) } printf("Verifying content at bottom of stack is readable and correct\n"); - if (!uc_mem_read(handle, esp - 4, bytes, 4)) { + if (!uc_mem_read(uc, esp - 4, bytes, 4)) { printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)(esp - 4), *(uint32_t*) bytes); } else { printf(">>> Failed to read 4 bytes from [0x%x]\n", (uint32_t)(esp - 4)); return 4; } - uc_close(&handle); + uc_close(uc); return 0; } diff --git a/regress/timeout_segfault.c b/regress/timeout_segfault.c index a1378e6a..5c31483a 100644 --- a/regress/timeout_segfault.c +++ b/regress/timeout_segfault.c @@ -24,21 +24,21 @@ https://github.com/unicorn-engine/unicorn/issues/78 // number of seconds to wait before timeout #define TIMEOUT 5 -static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_block(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_arm(void) { - uch handle; + struct uc_struct *uc; uc_err err; - uch trace1, trace2; + uc_hook_h trace1, trace2; int r0 = 0x1234; // R0 register int r2 = 0x6789; // R1 register @@ -48,7 +48,7 @@ static void test_arm(void) printf("Emulate ARM code\n"); // Initialize emulator in ARM mode - err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &handle); + err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -56,25 +56,25 @@ static void test_arm(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1); // initialize machine registers - uc_reg_write(handle, UC_ARM_REG_R0, &r0); - uc_reg_write(handle, UC_ARM_REG_R2, &r2); - uc_reg_write(handle, UC_ARM_REG_R3, &r3); + uc_reg_write(uc, UC_ARM_REG_R0, &r0); + uc_reg_write(uc, UC_ARM_REG_R2, &r2); + uc_reg_write(uc, UC_ARM_REG_R3, &r3); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, UC_SECOND_SCALE * TIMEOUT, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, UC_SECOND_SCALE * TIMEOUT, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u\n", err); } @@ -82,26 +82,26 @@ static void test_arm(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_ARM_REG_R0, &r0); - uc_reg_read(handle, UC_ARM_REG_R1, &r1); + uc_reg_read(uc, UC_ARM_REG_R0, &r0); + uc_reg_read(uc, UC_ARM_REG_R1, &r1); printf(">>> R0 = 0x%x\n", r0); printf(">>> R1 = 0x%x\n", r1); - uc_close(&handle); + uc_close(uc); } static void test_thumb(void) { - uch handle; + struct uc_struct *uc; uc_err err; - uch trace1, trace2; + uc_hook_h trace1, trace2; int sp = 0x1234; // R0 register printf("Emulate THUMB code\n"); // Initialize emulator in ARM mode - err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &handle); + err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -109,23 +109,23 @@ static void test_thumb(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)THUMB_CODE, sizeof(THUMB_CODE) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)THUMB_CODE, sizeof(THUMB_CODE) - 1); // initialize machine registers - uc_reg_write(handle, UC_ARM_REG_SP, &sp); + uc_reg_write(uc, UC_ARM_REG_SP, &sp); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(THUMB_CODE) -1, UC_SECOND_SCALE * TIMEOUT, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(THUMB_CODE) -1, UC_SECOND_SCALE * TIMEOUT, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u\n", err); } @@ -133,10 +133,10 @@ static void test_thumb(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_ARM_REG_SP, &sp); + uc_reg_read(uc, UC_ARM_REG_SP, &sp); printf(">>> SP = 0x%x\n", sp); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) From 5b62d436a9dad171c495f7dac3a00b6ee26eee2e Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Wed, 2 Sep 2015 21:44:43 -0400 Subject: [PATCH 50/64] change public APIs to use `ucengine` See #52. --- include/unicorn/unicorn.h | 39 +++++++++++++++++++------------------- regress/block_test.c | 4 ++-- regress/map_crash.c | 2 +- regress/map_write.c | 2 +- regress/nr_mem_test.c | 4 ++-- regress/rep_movsb.c | 6 +++--- regress/ro_mem_test.c | 6 +++--- regress/sigill.c | 4 ++-- regress/sigill2.c | 2 +- regress/timeout_segfault.c | 8 ++++---- samples/sample_arm.c | 8 ++++---- samples/sample_arm64.c | 6 +++--- samples/sample_m68k.c | 6 +++--- samples/sample_mips.c | 8 ++++---- samples/sample_sparc.c | 6 +++--- samples/sample_x86.c | 36 +++++++++++++++++------------------ samples/shellcode.c | 6 +++--- uc.c | 36 +++++++++++++++++------------------ 18 files changed, 95 insertions(+), 94 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index e72399a7..40a32e0e 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -20,6 +20,7 @@ extern "C" { #include "platform.h" struct uc_struct; +typedef struct uc_struct ucengine; typedef size_t uc_hook_h; @@ -125,24 +126,24 @@ typedef enum uc_err { // @address: address where the code is being executed // @size: size of machine instruction(s) being executed, or 0 when size is unknown // @user_data: user data passed to tracing APIs. -typedef void (*uc_cb_hookcode_t)(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data); +typedef void (*uc_cb_hookcode_t)(ucengine *uc, uint64_t address, uint32_t size, void *user_data); // Callback function for tracing interrupts (for uc_hook_intr()) // @intno: interrupt number // @user_data: user data passed to tracing APIs. -typedef void (*uc_cb_hookintr_t)(struct uc_struct *uc, uint32_t intno, void *user_data); +typedef void (*uc_cb_hookintr_t)(ucengine *uc, uint32_t intno, void *user_data); // Callback function for tracing IN instruction of X86 // @port: port number // @size: data size (1/2/4) to be read from this port // @user_data: user data passed to tracing APIs. -typedef uint32_t (*uc_cb_insn_in_t)(struct uc_struct *uc, uint32_t port, int size, void *user_data); +typedef uint32_t (*uc_cb_insn_in_t)(ucengine *uc, uint32_t port, int size, void *user_data); // x86's handler for OUT // @port: port number // @size: data size (1/2/4) to be written to this port // @value: data value to be written to this port -typedef void (*uc_cb_insn_out_t)(struct uc_struct *uc, uint32_t port, int size, uint32_t value, void *user_data); +typedef void (*uc_cb_insn_out_t)(ucengine *uc, uint32_t port, int size, uint32_t value, void *user_data); // All type of memory accesses for UC_HOOK_MEM_* typedef enum uc_mem_type { @@ -171,7 +172,7 @@ typedef enum uc_hook_t { // @size: size of data being read or written // @value: value of data being written to memory, or irrelevant if type = READ. // @user_data: user data passed to tracing APIs -typedef void (*uc_cb_hookmem_t)(struct uc_struct *uc, uc_mem_type type, +typedef void (*uc_cb_hookmem_t)(ucengine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data); // Callback function for handling memory events (for UC_HOOK_MEM_INVALID) @@ -181,7 +182,7 @@ typedef void (*uc_cb_hookmem_t)(struct uc_struct *uc, uc_mem_type type, // @value: value of data being written to memory, or irrelevant if type = READ. // @user_data: user data passed to tracing APIs // @return: return true to continue, or false to stop program (due to invalid memory). -typedef bool (*uc_cb_eventmem_t)(struct uc_struct *uc, uc_mem_type type, +typedef bool (*uc_cb_eventmem_t)(ucengine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data); @@ -222,13 +223,13 @@ bool uc_arch_supported(uc_arch arch); @arch: architecture type (UC_ARCH_*) @mode: hardware mode. This is combined of UC_MODE_* - @uc: pointer to struct uc_struct, which will be updated at return time + @uc: pointer to ucengine, which will be updated at return time @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum for detailed error). */ UNICORN_EXPORT -uc_err uc_open(uc_arch arch, uc_mode mode, struct uc_struct **uc); +uc_err uc_open(uc_arch arch, uc_mode mode, ucengine **uc); /* Close UC instance: MUST do to release the handle when it is not used anymore. @@ -243,7 +244,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, struct uc_struct **uc); for detailed error). */ UNICORN_EXPORT -uc_err uc_close(struct uc_struct *uc); +uc_err uc_close(ucengine *uc); /* Report the last error number when some API function fail. @@ -254,7 +255,7 @@ uc_err uc_close(struct uc_struct *uc); @return: error code of uc_err enum type (UC_ERR_*, see above) */ UNICORN_EXPORT -uc_err uc_errno(struct uc_struct *uc); +uc_err uc_errno(ucengine *uc); /* Return a string describing given error code. @@ -278,7 +279,7 @@ const char *uc_strerror(uc_err code); for detailed error). */ UNICORN_EXPORT -uc_err uc_reg_write(struct uc_struct *uc, int regid, const void *value); +uc_err uc_reg_write(ucengine *uc, int regid, const void *value); /* Read register value. @@ -291,7 +292,7 @@ uc_err uc_reg_write(struct uc_struct *uc, int regid, const void *value); for detailed error). */ UNICORN_EXPORT -uc_err uc_reg_read(struct uc_struct *uc, int regid, void *value); +uc_err uc_reg_read(ucengine *uc, int regid, void *value); /* Write to a range of bytes in memory. @@ -307,7 +308,7 @@ uc_err uc_reg_read(struct uc_struct *uc, int regid, void *value); for detailed error). */ UNICORN_EXPORT -uc_err uc_mem_write(struct uc_struct *uc, uint64_t address, const uint8_t *bytes, size_t size); +uc_err uc_mem_write(ucengine *uc, uint64_t address, const uint8_t *bytes, size_t size); /* Read a range of bytes in memory. @@ -323,7 +324,7 @@ uc_err uc_mem_write(struct uc_struct *uc, uint64_t address, const uint8_t *bytes for detailed error). */ UNICORN_EXPORT -uc_err uc_mem_read(struct uc_struct *uc, uint64_t address, uint8_t *bytes, size_t size); +uc_err uc_mem_read(ucengine *uc, uint64_t address, uint8_t *bytes, size_t size); /* Emulate machine code in a specific duration of time. @@ -340,7 +341,7 @@ uc_err uc_mem_read(struct uc_struct *uc, uint64_t address, uint8_t *bytes, size_ for detailed error). */ UNICORN_EXPORT -uc_err uc_emu_start(struct uc_struct *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count); +uc_err uc_emu_start(ucengine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count); /* Stop emulation (which was started by uc_emu_start() API. @@ -353,7 +354,7 @@ uc_err uc_emu_start(struct uc_struct *uc, uint64_t begin, uint64_t until, uint64 for detailed error). */ UNICORN_EXPORT -uc_err uc_emu_stop(struct uc_struct *uc); +uc_err uc_emu_stop(ucengine *uc); /* Register callback for a hook event. @@ -371,7 +372,7 @@ uc_err uc_emu_stop(struct uc_struct *uc); for detailed error). */ UNICORN_EXPORT -uc_err uc_hook_add(struct uc_struct *uc, uc_hook_h *hh, uc_hook_t type, void *callback, void *user_data, ...); +uc_err uc_hook_add(ucengine *uc, uc_hook_h *hh, uc_hook_t type, void *callback, void *user_data, ...); /* Unregister (remove) a hook callback. @@ -386,7 +387,7 @@ uc_err uc_hook_add(struct uc_struct *uc, uc_hook_h *hh, uc_hook_t type, void *ca for detailed error). */ UNICORN_EXPORT -uc_err uc_hook_del(struct uc_struct *uc, uc_hook_h hh); +uc_err uc_hook_del(ucengine *uc, uc_hook_h hh); typedef enum uc_prot { UC_PROT_NONE = 0, @@ -412,7 +413,7 @@ typedef enum uc_prot { for detailed error). */ UNICORN_EXPORT -uc_err uc_mem_map(struct uc_struct *uc, uint64_t address, size_t size, uint32_t perms); +uc_err uc_mem_map(ucengine *uc, uint64_t address, size_t size, uint32_t perms); #ifdef __cplusplus } diff --git a/regress/block_test.c b/regress/block_test.c index 0d1ddf9f..06a0fa21 100644 --- a/regress/block_test.c +++ b/regress/block_test.c @@ -12,7 +12,7 @@ static int count = 1; // @address: address where the code is being executed // @size: size of machine instruction being executed // @user_data: user data passed to tracing APIs. -void cb_hookblock(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { +void cb_hookblock(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { fprintf(stderr, "# >>> Tracing basic block at 0x%llx, block size = 0x%x\n", address, size); if (address != 0x1000000 && address != 0x1000200) { fprintf(stderr, "not ok %d - address != 0x1000000 && address != 0x1000200\n", count++); @@ -27,7 +27,7 @@ void cb_hookblock(struct uc_struct *uc, uint64_t address, uint32_t size, void *u } int main() { - struct uc_struct *uc; + ucengine *uc; fprintf(stderr, "# basic block callback test\n"); fprintf(stderr, "# there are only two basic blocks 0x1000000-0x10001ff and 0x1000200-0x10003ff\n"); diff --git a/regress/map_crash.c b/regress/map_crash.c index b25c2b00..e7fbf38c 100644 --- a/regress/map_crash.c +++ b/regress/map_crash.c @@ -10,7 +10,7 @@ int main() { int size; uint8_t *buf; - struct uc_struct *uc; + ucengine *uc; uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc); if (err) { fprintf (stderr, "Cannot initialize unicorn\n"); diff --git a/regress/map_write.c b/regress/map_write.c index 400b4719..40fada8d 100644 --- a/regress/map_write.c +++ b/regress/map_write.c @@ -8,7 +8,7 @@ int main() { - struct uc_struct *uc; + ucengine *uc; uint8_t *buf, *buf2; int i; uc_err err; diff --git a/regress/nr_mem_test.c b/regress/nr_mem_test.c index 1f45cb1d..0e70829b 100644 --- a/regress/nr_mem_test.c +++ b/regress/nr_mem_test.c @@ -36,7 +36,7 @@ bits 32 */ // callback for tracing memory access (READ or WRITE) -static bool hook_mem_invalid(struct uc_struct *uc, uc_mem_type type, +static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { @@ -54,7 +54,7 @@ static bool hook_mem_invalid(struct uc_struct *uc, uc_mem_type type, int main(int argc, char **argv, char **envp) { - struct uc_struct *uc; + ucengine *uc; uc_hook_h trace1, trace2; uc_err err; uint32_t eax, ebx; diff --git a/regress/rep_movsb.c b/regress/rep_movsb.c index 0b36e07c..97b00c15 100644 --- a/regress/rep_movsb.c +++ b/regress/rep_movsb.c @@ -50,7 +50,7 @@ hlt static int log_num = 1; // callback for tracing instruction -static void hook_code(struct uc_struct *uc, uint64_t addr, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t addr, uint32_t size, void *user_data) { uint8_t opcode; if (uc_mem_read(uc, addr, &opcode, 1) != UC_ERR_OK) { @@ -74,7 +74,7 @@ static void hook_code(struct uc_struct *uc, uint64_t addr, uint32_t size, void * } // callback for tracing memory access (READ or WRITE) -static void hook_mem_write(struct uc_struct *uc, uc_mem_type type, +static void hook_mem_write(ucengine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) { printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); @@ -89,7 +89,7 @@ static void hook_mem_write(struct uc_struct *uc, uc_mem_type type, int main(int argc, char **argv, char **envp) { - struct uc_struct *uc; + ucengine *uc; uc_hook_h trace1, trace2; uc_err err; uint8_t buf1[100], readbuf[100]; diff --git a/regress/ro_mem_test.c b/regress/ro_mem_test.c index 75b0d9bf..51b94b2f 100644 --- a/regress/ro_mem_test.c +++ b/regress/ro_mem_test.c @@ -46,7 +46,7 @@ bottom: */ // callback for tracing instruction -static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { uint32_t esp; printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); @@ -57,7 +57,7 @@ static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, voi } // callback for tracing memory access (READ or WRITE) -static bool hook_mem_invalid(struct uc_struct *uc, uc_mem_type type, +static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { uint32_t esp; @@ -94,7 +94,7 @@ static bool hook_mem_invalid(struct uc_struct *uc, uc_mem_type type, int main(int argc, char **argv, char **envp) { - struct uc_struct *uc; + ucengine *uc; uc_hook_h trace1, trace2; uc_err err; uint8_t bytes[8]; diff --git a/regress/sigill.c b/regress/sigill.c index 72e3be49..ad7af47f 100644 --- a/regress/sigill.c +++ b/regress/sigill.c @@ -8,7 +8,7 @@ int got_sigill = 0; -void _interrupt(struct uc_struct *uc, uint32_t intno, void *user_data) +void _interrupt(ucengine *uc, uint32_t intno, void *user_data) { if (intno == 6) { uc_emu_stop(uc); @@ -20,7 +20,7 @@ int main() { int size; uint8_t *buf; - struct uc_struct *uc; + ucengine *uc; uc_hook_h uh_trap; uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc); if (err) { diff --git a/regress/sigill2.c b/regress/sigill2.c index 406dd750..1d955144 100644 --- a/regress/sigill2.c +++ b/regress/sigill2.c @@ -10,7 +10,7 @@ int main() { int size; uint8_t *buf; - struct uc_struct *uc; + ucengine *uc; uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc); if (err) { diff --git a/regress/timeout_segfault.c b/regress/timeout_segfault.c index 5c31483a..2632a51f 100644 --- a/regress/timeout_segfault.c +++ b/regress/timeout_segfault.c @@ -24,19 +24,19 @@ https://github.com/unicorn-engine/unicorn/issues/78 // number of seconds to wait before timeout #define TIMEOUT 5 -static void hook_block(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_block(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_arm(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2; @@ -92,7 +92,7 @@ static void test_arm(void) static void test_thumb(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2; diff --git a/samples/sample_arm.c b/samples/sample_arm.c index 1da06fc8..38e8590a 100644 --- a/samples/sample_arm.c +++ b/samples/sample_arm.c @@ -15,19 +15,19 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_block(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_arm(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2; @@ -83,7 +83,7 @@ static void test_arm(void) static void test_thumb(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2; diff --git a/samples/sample_arm64.c b/samples/sample_arm64.c index de24ab37..61a58f20 100644 --- a/samples/sample_arm64.c +++ b/samples/sample_arm64.c @@ -14,19 +14,19 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_block(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_arm64(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2; diff --git a/samples/sample_m68k.c b/samples/sample_m68k.c index a640da72..049041cb 100644 --- a/samples/sample_m68k.c +++ b/samples/sample_m68k.c @@ -12,19 +12,19 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_block(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_m68k(void) { - struct uc_struct *uc; + ucengine *uc; uc_hook_h trace1, trace2; uc_err err; diff --git a/samples/sample_mips.c b/samples/sample_mips.c index 6fc13229..0806f60e 100644 --- a/samples/sample_mips.c +++ b/samples/sample_mips.c @@ -15,19 +15,19 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_block(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_mips_eb(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2; @@ -76,7 +76,7 @@ static void test_mips_eb(void) static void test_mips_el(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2; diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index b9c2404e..36536680 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -15,19 +15,19 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_block(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_sparc(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2; diff --git a/samples/sample_x86.c b/samples/sample_x86.c index af99075b..9bdd8232 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -32,13 +32,13 @@ #define ADDRESS 0x1000000 // callback for tracing basic blocks -static void hook_block(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_block(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } // callback for tracing instruction -static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { int eflags; printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); @@ -52,7 +52,7 @@ static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, voi } // callback for tracing instruction -static void hook_code64(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_code64(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { uint64_t rip; @@ -66,7 +66,7 @@ static void hook_code64(struct uc_struct *uc, uint64_t address, uint32_t size, v } // callback for tracing memory access (READ or WRITE) -static bool hook_mem_invalid(struct uc_struct *uc, uc_mem_type type, +static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { switch(type) { @@ -83,7 +83,7 @@ static bool hook_mem_invalid(struct uc_struct *uc, uc_mem_type type, } } -static void hook_mem64(struct uc_struct *uc, uc_mem_type type, +static void hook_mem64(ucengine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { switch(type) { @@ -101,7 +101,7 @@ static void hook_mem64(struct uc_struct *uc, uc_mem_type type, // callback for IN instruction (X86). // this returns the data read from the port -static uint32_t hook_in(struct uc_struct *uc, uint32_t port, int size, void *user_data) +static uint32_t hook_in(ucengine *uc, uint32_t port, int size, void *user_data) { uint32_t eip; @@ -126,7 +126,7 @@ static uint32_t hook_in(struct uc_struct *uc, uint32_t port, int size, void *use } // callback for OUT instruction (X86). -static void hook_out(struct uc_struct *uc, uint32_t port, int size, uint32_t value, void *user_data) +static void hook_out(ucengine *uc, uint32_t port, int size, uint32_t value, void *user_data) { uint32_t tmp; uint32_t eip; @@ -154,7 +154,7 @@ static void hook_out(struct uc_struct *uc, uint32_t port, int size, uint32_t val } // callback for SYSCALL instruction (X86). -static void hook_syscall(struct uc_struct *uc, void *user_data) +static void hook_syscall(ucengine *uc, void *user_data) { uint64_t rax; @@ -168,7 +168,7 @@ static void hook_syscall(struct uc_struct *uc, void *user_data) static void test_i386(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uint32_t tmp; uc_hook_h trace1, trace2; @@ -230,7 +230,7 @@ static void test_i386(void) static void test_i386_jump(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2; @@ -275,7 +275,7 @@ static void test_i386_jump(void) // emulate code that loop forever static void test_i386_loop(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; int r_ecx = 0x1234; // ECX register @@ -326,7 +326,7 @@ static void test_i386_loop(void) // emulate code that read invalid memory static void test_i386_invalid_mem_read(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2; @@ -383,7 +383,7 @@ static void test_i386_invalid_mem_read(void) // emulate code that read invalid memory static void test_i386_invalid_mem_write(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2, trace3; uint32_t tmp; @@ -455,7 +455,7 @@ static void test_i386_invalid_mem_write(void) // emulate code that jump to invalid memory static void test_i386_jump_invalid(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2; @@ -511,7 +511,7 @@ static void test_i386_jump_invalid(void) static void test_i386_inout(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2, trace3, trace4; @@ -572,7 +572,7 @@ static void test_i386_inout(void) static void test_x86_64(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2, trace3, trace4; @@ -688,7 +688,7 @@ static void test_x86_64(void) static void test_x86_64_syscall(void) { - struct uc_struct *uc; + ucengine *uc; uc_hook_h trace1; uc_err err; @@ -739,7 +739,7 @@ static void test_x86_64_syscall(void) static void test_x86_16(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uint8_t tmp; diff --git a/samples/shellcode.c b/samples/shellcode.c index 62fe30e5..f185db97 100644 --- a/samples/shellcode.c +++ b/samples/shellcode.c @@ -20,7 +20,7 @@ #define MIN(a, b) (a < b? a : b) // callback for tracing instruction -static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { int r_eip; char tmp[16]; @@ -43,7 +43,7 @@ static void hook_code(struct uc_struct *uc, uint64_t address, uint32_t size, voi #define MIN(a, b) (a < b? a : b) // callback for handling interrupt // ref: http://syscalls.kernelgrok.com/ -static void hook_intr(struct uc_struct *uc, uint32_t intno, void *user_data) +static void hook_intr(ucengine *uc, uint32_t intno, void *user_data) { int32_t r_eax, r_ecx, r_eip; uint32_t r_edx, size; @@ -88,7 +88,7 @@ static void hook_intr(struct uc_struct *uc, uint32_t intno, void *user_data) static void test_i386(void) { - struct uc_struct *uc; + ucengine *uc; uc_err err; uc_hook_h trace1, trace2; diff --git a/uc.c b/uc.c index efe02622..cc25918a 100644 --- a/uc.c +++ b/uc.c @@ -44,7 +44,7 @@ unsigned int uc_version(unsigned int *major, unsigned int *minor) UNICORN_EXPORT -uc_err uc_errno(struct uc_struct *uc) +uc_err uc_errno(ucengine *uc) { return uc->errnum; } @@ -121,7 +121,7 @@ bool uc_arch_supported(uc_arch arch) UNICORN_EXPORT -uc_err uc_open(uc_arch arch, uc_mode mode, struct uc_struct **result) +uc_err uc_open(uc_arch arch, uc_mode mode, ucengine **result) { struct uc_struct *uc; @@ -240,7 +240,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, struct uc_struct **result) UNICORN_EXPORT -uc_err uc_close(struct uc_struct *uc) +uc_err uc_close(ucengine *uc) { if (uc->release) uc->release(uc->tcg_ctx); @@ -280,7 +280,7 @@ uc_err uc_close(struct uc_struct *uc) UNICORN_EXPORT -uc_err uc_reg_read(struct uc_struct *uc, int regid, void *value) +uc_err uc_reg_read(ucengine *uc, int regid, void *value) { if (uc->reg_read) uc->reg_read(uc, regid, value); @@ -292,7 +292,7 @@ uc_err uc_reg_read(struct uc_struct *uc, int regid, void *value) UNICORN_EXPORT -uc_err uc_reg_write(struct uc_struct *uc, int regid, const void *value) +uc_err uc_reg_write(ucengine *uc, int regid, const void *value) { if (uc->reg_write) uc->reg_write(uc, regid, value); @@ -305,7 +305,7 @@ uc_err uc_reg_write(struct uc_struct *uc, int regid, const void *value) // check if a memory area is mapped // this is complicated because an area can overlap adjacent blocks -static bool check_mem_area(struct uc_struct *uc, uint64_t address, size_t size) +static bool check_mem_area(ucengine *uc, uint64_t address, size_t size) { size_t count = 0, len; @@ -324,7 +324,7 @@ static bool check_mem_area(struct uc_struct *uc, uint64_t address, size_t size) UNICORN_EXPORT -uc_err uc_mem_read(struct uc_struct *uc, uint64_t address, uint8_t *bytes, size_t size) +uc_err uc_mem_read(ucengine *uc, uint64_t address, uint8_t *bytes, size_t size) { if (!check_mem_area(uc, address, size)) return UC_ERR_MEM_READ; @@ -352,7 +352,7 @@ uc_err uc_mem_read(struct uc_struct *uc, uint64_t address, uint8_t *bytes, size_ } UNICORN_EXPORT -uc_err uc_mem_write(struct uc_struct *uc, uint64_t address, const uint8_t *bytes, size_t size) +uc_err uc_mem_write(ucengine *uc, uint64_t address, const uint8_t *bytes, size_t size) { if (!check_mem_area(uc, address, size)) return UC_ERR_MEM_WRITE; @@ -392,7 +392,7 @@ uc_err uc_mem_write(struct uc_struct *uc, uint64_t address, const uint8_t *bytes #define TIMEOUT_STEP 2 // microseconds static void *_timeout_fn(void *arg) { - struct uc_struct *uc = (struct uc_struct *)arg; + struct uc_struct *uc = arg; int64_t current_time = get_clock(); do { @@ -411,7 +411,7 @@ static void *_timeout_fn(void *arg) return NULL; } -static void enable_emu_timer(struct uc_struct *uc, uint64_t timeout) +static void enable_emu_timer(ucengine *uc, uint64_t timeout) { uc->timeout = timeout; qemu_thread_create(uc, &uc->timer, "timeout", _timeout_fn, @@ -419,7 +419,7 @@ static void enable_emu_timer(struct uc_struct *uc, uint64_t timeout) } UNICORN_EXPORT -uc_err uc_emu_start(struct uc_struct* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) +uc_err uc_emu_start(ucengine* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) { // reset the counter uc->emu_counter = 0; @@ -502,7 +502,7 @@ uc_err uc_emu_start(struct uc_struct* uc, uint64_t begin, uint64_t until, uint64 UNICORN_EXPORT -uc_err uc_emu_stop(struct uc_struct *uc) +uc_err uc_emu_stop(ucengine *uc) { if (uc->emulation_done) return UC_ERR_OK; @@ -515,7 +515,7 @@ uc_err uc_emu_stop(struct uc_struct *uc) } -static int _hook_code(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, +static int _hook_code(ucengine *uc, int type, uint64_t begin, uint64_t end, void *callback, void *user_data, uc_hook_h *hh) { int i; @@ -530,7 +530,7 @@ static int _hook_code(struct uc_struct *uc, int type, uint64_t begin, uint64_t e } -static uc_err _hook_mem_access(struct uc_struct *uc, uc_hook_t type, +static uc_err _hook_mem_access(ucengine *uc, uc_hook_t type, uint64_t begin, uint64_t end, void *callback, void *user_data, uc_hook_h *hh) { @@ -546,7 +546,7 @@ static uc_err _hook_mem_access(struct uc_struct *uc, uc_hook_t type, } UNICORN_EXPORT -uc_err uc_mem_map(struct uc_struct *uc, uint64_t address, size_t size, uint32_t perms) +uc_err uc_mem_map(ucengine *uc, uint64_t address, size_t size, uint32_t perms) { MemoryRegion **regions; @@ -579,7 +579,7 @@ uc_err uc_mem_map(struct uc_struct *uc, uint64_t address, size_t size, uint32_t return UC_ERR_OK; } -MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) +MemoryRegion *memory_mapping(ucengine* uc, uint64_t address) { unsigned int i; @@ -682,7 +682,7 @@ static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callb } UNICORN_EXPORT -uc_err uc_hook_add(struct uc_struct *uc, uc_hook_h *hh, uc_hook_t type, void *callback, void *user_data, ...) +uc_err uc_hook_add(ucengine *uc, uc_hook_h *hh, uc_hook_t type, void *callback, void *user_data, ...) { va_list valist; int ret = UC_ERR_OK; @@ -738,7 +738,7 @@ uc_err uc_hook_add(struct uc_struct *uc, uc_hook_h *hh, uc_hook_t type, void *ca } UNICORN_EXPORT -uc_err uc_hook_del(struct uc_struct *uc, uc_hook_h hh) +uc_err uc_hook_del(ucengine *uc, uc_hook_h hh) { return hook_del(uc, hh); } From f230de876ead025835009a371c23454fc0241e70 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Wed, 2 Sep 2015 19:07:11 -0700 Subject: [PATCH 51/64] fix go binding hook arguments --- bindings/go/unicorn/hook.c | 8 ++++++-- bindings/go/unicorn/hook.go | 25 ++++++++++++++++++++----- bindings/go/unicorn/hook.h | 3 ++- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/bindings/go/unicorn/hook.c b/bindings/go/unicorn/hook.c index a06f9901..f24dd1f1 100644 --- a/bindings/go/unicorn/hook.c +++ b/bindings/go/unicorn/hook.c @@ -1,8 +1,12 @@ #include #include "_cgo_export.h" -uc_err uc_hook_add2(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, int extra) { - return uc_hook_add(handle, h2, type, callback, user_data, extra); +uc_err uc_hook_add_i1(uch handle, uch *h2, uc_hook_t type, void *callback, void *user, int arg1) { + return uc_hook_add(handle, h2, type, callback, user, arg1); +} + +uc_err uc_hook_add_u2(uch handle, uch *h2, uc_hook_t type, void *callback, void *user, uint64_t arg1, uint64_t arg2) { + return uc_hook_add(handle, h2, type, callback, user, arg1, arg2); } void hookCode_cgo(uch handle, uint64_t addr, uint32_t size, void *user) { diff --git a/bindings/go/unicorn/hook.go b/bindings/go/unicorn/hook.go index dcab893a..e6e01617 100644 --- a/bindings/go/unicorn/hook.go +++ b/bindings/go/unicorn/hook.go @@ -60,21 +60,26 @@ func hookX86Syscall(handle C.uch, user unsafe.Pointer) { var hookRetain = make(map[C.uch]*HookData) -func (u *Uc) HookAdd(htype int, cb interface{}, insn ...int) (C.uch, error) { +func (u *Uc) HookAdd(htype int, cb interface{}, extra ...uint64) (C.uch, error) { var callback unsafe.Pointer - var extra C.int + var iarg1 C.int + var uarg1, uarg2 C.uint64_t + rangeMode := false switch htype { case UC_HOOK_BLOCK, UC_HOOK_CODE: + rangeMode = true callback = C.hookCode_cgo case UC_HOOK_MEM_INVALID: + rangeMode = true callback = C.hookMemInvalid_cgo case UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ_WRITE: + rangeMode = true callback = C.hookMemAccess_cgo case UC_HOOK_INTR: callback = C.hookInterrupt_cgo case UC_HOOK_INSN: - extra = C.int(insn[0]) - switch extra { + iarg1 = C.int(extra[0]) + switch iarg1 { case UC_X86_INS_IN: callback = C.hookX86In_cgo case UC_X86_INS_OUT: @@ -89,7 +94,17 @@ func (u *Uc) HookAdd(htype int, cb interface{}, insn ...int) (C.uch, error) { } var h2 C.uch data := &HookData{u, cb} - C.uc_hook_add2(u.Handle, &h2, C.uc_hook_t(htype), callback, unsafe.Pointer(data), extra) + 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_t(htype), callback, unsafe.Pointer(data), uarg1, uarg2) + } else { + C.uc_hook_add_i1(u.Handle, &h2, C.uc_hook_t(htype), callback, unsafe.Pointer(data), iarg1) + } hookRetain[h2] = data return h2, nil } diff --git a/bindings/go/unicorn/hook.h b/bindings/go/unicorn/hook.h index c8c22267..b35fca27 100644 --- a/bindings/go/unicorn/hook.h +++ b/bindings/go/unicorn/hook.h @@ -1,4 +1,5 @@ -uc_err uc_hook_add2(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, int extra); +uc_err uc_hook_add_i1(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, int arg1); +uc_err uc_hook_add_u2(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, uint64_t arg1, uint64_t arg2); void hookCode_cgo(uch handle, uint64_t addr, uint32_t size, void *user); bool hookMemInvalid_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user); void hookMemAccess_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user); From 46cc510dfe95c87c63cfdad222b4121e813bdf80 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Sep 2015 18:02:25 +0800 Subject: [PATCH 52/64] chmod +x regress/reg_write_sign_extension.py --- regress/reg_write_sign_extension.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 regress/reg_write_sign_extension.py diff --git a/regress/reg_write_sign_extension.py b/regress/reg_write_sign_extension.py old mode 100644 new mode 100755 From 9f9d57e84f72e871dc96521c8d263f7474a9dc6e Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Sep 2015 18:16:49 +0800 Subject: [PATCH 53/64] cleaning & indentation --- qemu/unicorn_common.h | 2 +- regress/ro_mem_test.c | 2 +- samples/mem_exec.c | 423 +++++++++++++++++++-------------------- samples/mem_protect.c | 446 ++++++++++++++++++++---------------------- samples/mem_unmap.c | 433 +++++++++++++++++++--------------------- uc.c | 21 +- 6 files changed, 633 insertions(+), 694 deletions(-) diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index 5ba74fac..adfb5f05 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -77,7 +77,7 @@ static inline void uc_common_init(struct uc_struct* uc) uc->readonly_mem = memory_region_set_readonly; uc->target_page_size = TARGET_PAGE_SIZE; - uc->target_page_align = TARGET_PAGE_SIZE - 1; + uc->target_page_align = TARGET_PAGE_SIZE - 1; if (!uc->release) uc->release = release_common; diff --git a/regress/ro_mem_test.c b/regress/ro_mem_test.c index 52534cd4..38fd913b 100644 --- a/regress/ro_mem_test.c +++ b/regress/ro_mem_test.c @@ -160,7 +160,7 @@ int main(int argc, char **argv, char **envp) uint32_t eax = 0x40002C; uc_reg_write(handle, UC_X86_REG_EAX, &eax); //resume execution at the mov dword [eax], 0x87654321 - //to test an aligned write as well + //to test an aligned write as well err = uc_emu_start(handle, 0x400015, 0x400000 + sizeof(PROGRAM), 0, 2); if (err) { printf("Expected failure on uc_emu_start() with error returned %u: %s\n", diff --git a/samples/mem_exec.c b/samples/mem_exec.c index 171022a7..370fd1ea 100644 --- a/samples/mem_exec.c +++ b/samples/mem_exec.c @@ -1,23 +1,22 @@ /* + Executable memory regions demo / unit test -Executable memory regions demo / unit test + Copyright(c) 2015 Chris Eagle -Copyright(c) 2015 Chris Eagle + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -version 2 as published by the Free Software Foundation. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -*/ + */ #define __STDC_FORMAT_MACROS #include @@ -30,47 +29,47 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include unsigned char PROGRAM[] = - "\xeb\x45\x5e\x81\xe6\x00\xf0\xff\xff\x40\x40\x40\x40\x40\x40\x40" - "\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40" - "\x40\x40\x40\x40\x40\x40\x40\x89\xf7\x81\xc7\x00\x00\x10\x00\xb9" - "\x4c\x00\x00\x00\x81\xff\x00\x00\x40\x00\x75\x01\xf4\xf3\xa4\x81" - "\xe7\x00\xf0\xff\xff\xff\xe7\xe8\xb6\xff\xff\xff"; -// total size: 76 bytes + "\xeb\x45\x5e\x81\xe6\x00\xf0\xff\xff\x40\x40\x40\x40\x40\x40\x40" + "\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40" + "\x40\x40\x40\x40\x40\x40\x40\x89\xf7\x81\xc7\x00\x00\x10\x00\xb9" + "\x4c\x00\x00\x00\x81\xff\x00\x00\x40\x00\x75\x01\xf4\xf3\xa4\x81" + "\xe7\x00\xf0\xff\xff\xff\xe7\xe8\xb6\xff\xff\xff"; + // total size: 76 bytes /* -bits 32 + bits 32 -; assumes r-x section at 0x100000 -; assumes rw- section at 0x200000 -; assumes r-- section at 0x300000 -; also needs an initialized stack + ; assumes r-x section at 0x100000 + ; assumes rw- section at 0x200000 + ; assumes r-- section at 0x300000 + ; also needs an initialized stack start: - jmp bottom +jmp bottom top: - pop esi - and esi, ~0xfff - times 30 inc eax - mov edi, esi - add edi, 0x100000 - mov ecx, end - start - rep movsb - and edi, ~0xfff - cmp edi, 0x400000 - jnz next_block - hlt +pop esi +and esi, ~0xfff +times 30 inc eax +mov edi, esi +add edi, 0x100000 +mov ecx, end - start +rep movsb +and edi, ~0xfff +cmp edi, 0x400000 +jnz next_block +hlt next_block: - jmp edi +jmp edi bottom: - call top +call top end: -*/ + */ int test_num = 0; uint32_t tests[] = { - 0x41414141, - 0x43434343, - 0x45454545 + 0x41414141, + 0x43434343, + 0x45454545 }; static int log_num = 1; @@ -81,216 +80,200 @@ static int log_num = 1; // callback for tracing instruction static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) { - uint8_t opcode; - if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) { - printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); - } -// printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr); - switch (opcode) { - case 0xf4: //hlt - printf("# Handling HLT\n"); - if (uc_emu_stop(handle) != UC_ERR_OK) { - printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); - _exit(-1); - } - else { - printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++); - } - break; - default: //all others -// printf("# Handling OTHER\n"); - break; - } + uint8_t opcode; + + if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } + + // printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr); + switch (opcode) { + case 0xf4: //hlt + printf("# Handling HLT\n"); + if (uc_emu_stop(handle) != UC_ERR_OK) { + printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + _exit(-1); + } else { + printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++); + } + break; + default: //all others + // printf("# Handling OTHER\n"); + break; + } } // callback for tracing memory access (READ or WRITE) static void hook_mem_write(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) { - printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); + printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); } // callback for tracing invalid memory access (READ or WRITE) static bool hook_mem_invalid(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) { - switch(type) { - default: - printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); - return false; - case UC_MEM_EXEC_PROT: - printf("# Fetch from non-executable memory at 0x%"PRIx64 "\n", addr); + switch(type) { + default: + printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); + return false; + case UC_MEM_EXEC_PROT: + printf("# Fetch from non-executable memory at 0x%"PRIx64 "\n", addr); - //make page executable - if (uc_mem_protect(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_EXEC) != UC_ERR_OK) { - printf("not ok %d - uc_mem_protect fail for address: 0x%" PRIx64 "\n", log_num++, addr); - } - else { - printf("ok %d - uc_mem_protect success at 0x%" PRIx64 "\n", log_num++, addr); - } - return true; - case UC_MEM_WRITE_PROT: - printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); + //make page executable + if (uc_mem_protect(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_EXEC) != UC_ERR_OK) { + printf("not ok %d - uc_mem_protect fail for address: 0x%" PRIx64 "\n", log_num++, addr); + } else { + printf("ok %d - uc_mem_protect success at 0x%" PRIx64 "\n", log_num++, addr); + } + return true; + case UC_MEM_WRITE_PROT: + printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); - if (uc_mem_protect(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { - printf("not ok %d - uc_mem_protect fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); - } - else { - printf("ok %d - uc_mem_protect success\n", log_num++); - } - return true; - } + if (uc_mem_protect(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { + printf("not ok %d - uc_mem_protect fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } else { + printf("ok %d - uc_mem_protect success\n", log_num++); + } + return true; + } } int main(int argc, char **argv, char **envp) { - uch handle, trace1, trace2; - uc_err err; - uint32_t esp, eip; - int32_t buf1[1024], buf2[1024], readbuf[1024]; - int i; - - //don't really care about quality of randomness - srand(time(NULL)); - for (i = 0; i < 1024; i++) { - buf1[i] = rand(); - buf2[i] = rand(); - } + uch handle, trace1, trace2; + uc_err err; + uint32_t esp, eip; + int32_t buf1[1024], buf2[1024], readbuf[1024]; + int i; - printf("# Memory protect test\n"); + //don't really care about quality of randomness + srand(time(NULL)); + for (i = 0; i < 1024; i++) { + buf1[i] = rand(); + buf2[i] = rand(); + } - // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); - if (err) { - printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err); - return 1; - } - else { - printf("ok %d - uc_open() success\n", log_num++); - } + printf("# Memory protect test\n"); - uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_READ | UC_PROT_EXEC); - uc_mem_map(handle, 0x1ff000, 0x2000, UC_PROT_READ | UC_PROT_WRITE); - uc_mem_map(handle, 0x300000, 0x2000, UC_PROT_READ); - uc_mem_map(handle, 0xf00000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + if (err) { + printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err); + return 1; + } else { + printf("ok %d - uc_open() success\n", log_num++); + } - esp = 0xf00000 + 0x1000; + uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_READ | UC_PROT_EXEC); + uc_mem_map(handle, 0x1ff000, 0x2000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(handle, 0x300000, 0x2000, UC_PROT_READ); + uc_mem_map(handle, 0xf00000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); - // Setup stack pointer - if (uc_reg_write(handle, UC_X86_REG_ESP, &esp)) { - printf("not ok %d - Failed to set esp. quit!\n", log_num++); - return 2; - } - else { - printf("ok %d - ESP set\n", log_num++); - } + esp = 0xf00000 + 0x1000; - // fill in sections that shouldn't get touched - if (uc_mem_write(handle, 0x1ff000, (uint8_t*)buf1, 4096)) { - printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); - return 3; - } - else { - printf("ok %d - Random buffer 1 written to memory\n", log_num++); - } + // Setup stack pointer + if (uc_reg_write(handle, UC_X86_REG_ESP, &esp)) { + printf("not ok %d - Failed to set esp. quit!\n", log_num++); + return 2; + } else { + printf("ok %d - ESP set\n", log_num++); + } - if (uc_mem_write(handle, 0x301000, (uint8_t*)buf2, 4096)) { - printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); - return 4; - } - else { - printf("ok %d - Random buffer 2 written to memory\n", log_num++); - } + // fill in sections that shouldn't get touched + if (uc_mem_write(handle, 0x1ff000, (uint8_t*)buf1, 4096)) { + printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); + return 3; + } else { + printf("ok %d - Random buffer 1 written to memory\n", log_num++); + } - // write machine code to be emulated to memory - if (uc_mem_write(handle, 0x100000, PROGRAM, sizeof(PROGRAM))) { - printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); - return 5; - } - else { - printf("ok %d - Program written to memory\n", log_num++); - } + if (uc_mem_write(handle, 0x301000, (uint8_t*)buf2, 4096)) { + printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); + return 4; + } else { + printf("ok %d - Random buffer 2 written to memory\n", log_num++); + } - if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); - return 6; - } - else { - printf("ok %d - UC_HOOK_CODE installed\n", log_num++); - } + // write machine code to be emulated to memory + if (uc_mem_write(handle, 0x100000, PROGRAM, sizeof(PROGRAM))) { + printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); + return 5; + } else { + printf("ok %d - Program written to memory\n", log_num++); + } - // intercept memory write events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); - return 7; - } - else { - printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); - } + if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); + return 6; + } else { + printf("ok %d - UC_HOOK_CODE installed\n", log_num++); + } - // intercept invalid memory events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID handler\n", log_num++); - return 8; - } - else { - printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); - } + // intercept memory write events + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); + return 7; + } else { + printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); + } - // emulate machine code until told to stop by hook_code - printf("# BEGIN execution\n"); - err = uc_emu_start(handle, 0x100000, 0x400000, 0, 0); - if (err != UC_ERR_OK) { - printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); - return 9; - } - else { - printf("ok %d - uc_emu_start complete\n", log_num++); - } - printf("# END execution\n"); + // intercept invalid memory events + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID handler\n", log_num++); + return 8; + } else { + printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); + } - // get ending EIP - if (uc_reg_read(handle, UC_X86_REG_EIP, &eip)) { - printf("not ok %d - Failed to read eip.\n", log_num++); - } - else { - printf("ok %d - Ending EIP 0x%x\n", log_num++, eip); - } + // emulate machine code until told to stop by hook_code + printf("# BEGIN execution\n"); + err = uc_emu_start(handle, 0x100000, 0x400000, 0, 0); + if (err != UC_ERR_OK) { + printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); + return 9; + } else { + printf("ok %d - uc_emu_start complete\n", log_num++); + } + printf("# END execution\n"); - //make sure that random blocks didn't get nuked - // fill in sections that shouldn't get touched - if (uc_mem_read(handle, 0x1ff000, (uint8_t*)readbuf, 4096)) { - printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++); - } - else { - printf("ok %d - Random buffer 1 read from memory\n", log_num++); - if (memcmp(buf1, readbuf, 4096)) { - printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++); - } - else { - printf("ok %d - Random buffer 1 contents are correct\n", log_num++); - } - } + // get ending EIP + if (uc_reg_read(handle, UC_X86_REG_EIP, &eip)) { + printf("not ok %d - Failed to read eip.\n", log_num++); + } else { + printf("ok %d - Ending EIP 0x%x\n", log_num++, eip); + } - if (uc_mem_read(handle, 0x301000, (uint8_t*)readbuf, 4096)) { - printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); - } - else { - printf("ok %d - Random buffer 2 read from memory\n", log_num++); - if (memcmp(buf2, readbuf, 4096)) { - printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++); - } - else { - printf("ok %d - Random buffer 2 contents are correct\n", log_num++); - } - } + //make sure that random blocks didn't get nuked + // fill in sections that shouldn't get touched + if (uc_mem_read(handle, 0x1ff000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++); + } else { + printf("ok %d - Random buffer 1 read from memory\n", log_num++); + if (memcmp(buf1, readbuf, 4096)) { + printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++); + } else { + printf("ok %d - Random buffer 1 contents are correct\n", log_num++); + } + } - if (uc_close(&handle) == UC_ERR_OK) { - printf("ok %d - uc_close complete\n", log_num++); - } - else { - printf("not ok %d - uc_close complete\n", log_num++); - } + if (uc_mem_read(handle, 0x301000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); + } else { + printf("ok %d - Random buffer 2 read from memory\n", log_num++); + if (memcmp(buf2, readbuf, 4096)) { + printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++); + } else { + printf("ok %d - Random buffer 2 contents are correct\n", log_num++); + } + } - return 0; + if (uc_close(&handle) == UC_ERR_OK) { + printf("ok %d - uc_close complete\n", log_num++); + } else { + printf("not ok %d - uc_close complete\n", log_num++); + } + + return 0; } diff --git a/samples/mem_protect.c b/samples/mem_protect.c index 5d852ff5..5739563e 100644 --- a/samples/mem_protect.c +++ b/samples/mem_protect.c @@ -1,23 +1,22 @@ /* + uc_mem_protect demo / unit test -uc_mem_protect demo / unit test + Copyright(c) 2015 Chris Eagle -Copyright(c) 2015 Chris Eagle + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -version 2 as published by the Free Software Foundation. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -*/ + */ #define __STDC_FORMAT_MACROS #include @@ -30,23 +29,23 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include unsigned char PROGRAM[] = - "\xc7\x05\x00\x00\x20\x00\x41\x41\x41\x41\x90\xc7\x05\x00\x00\x20" - "\x00\x42\x42\x42\x42\xc7\x05\x00\x00\x30\x00\x43\x43\x43\x43\x90" - "\xc7\x05\x00\x00\x30\x00\x44\x44\x44\x44\xc7\x05\x00\x00\x40\x00" - "\x45\x45\x45\x45\x90\xc7\x05\x00\x00\x40\x00\x46\x46\x46\x46\xc7" - "\x05\x00\xf8\x3f\x00\x47\x47\x47\x47\xc7\x05\x00\x18\x40\x00\x48" - "\x48\x48\x48\xf4"; -// total size: 84 bytes + "\xc7\x05\x00\x00\x20\x00\x41\x41\x41\x41\x90\xc7\x05\x00\x00\x20" + "\x00\x42\x42\x42\x42\xc7\x05\x00\x00\x30\x00\x43\x43\x43\x43\x90" + "\xc7\x05\x00\x00\x30\x00\x44\x44\x44\x44\xc7\x05\x00\x00\x40\x00" + "\x45\x45\x45\x45\x90\xc7\x05\x00\x00\x40\x00\x46\x46\x46\x46\xc7" + "\x05\x00\xf8\x3f\x00\x47\x47\x47\x47\xc7\x05\x00\x18\x40\x00\x48" + "\x48\x48\x48\xf4"; + // total size: 84 bytes /* -bits 32 + bits 32 -; assumes code section at 0x100000 -; assumes data section at 0x200000, initially rw -; assumes data section at 0x300000, initially rw -; assumes data section at 0x400000, initially rw + ; assumes code section at 0x100000 + ; assumes data section at 0x200000, initially rw + ; assumes data section at 0x300000, initially rw + ; assumes data section at 0x400000, initially rw -; with installed hooks unmaps or maps on each nop + ; with installed hooks unmaps or maps on each nop mov dword [0x200000], 0x41414141 nop ; mark it RO @@ -63,13 +62,13 @@ bits 32 mov dword [0x401800], 0x48484848 ; make sure surrounding areas remained RW hlt ; tell hook function we are done -*/ + */ int test_num = 0; uint32_t tests[] = { - 0x41414141, - 0x43434343, - 0x45454545 + 0x41414141, + 0x43434343, + 0x45454545 }; static int log_num = 1; @@ -80,244 +79,223 @@ static int log_num = 1; // callback for tracing instruction static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) { - uint8_t opcode; - uint32_t testval; - if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) { - printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); - } - printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr); - switch (opcode) { - case 0x90: //nop - printf("# Handling NOP\n"); - if (uc_mem_read(handle, 0x200000 + test_num * 0x100000, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { - printf("not ok %d - uc_mem_read fail for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); - } - else { - printf("ok %d - good uc_mem_read for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); - printf("# uc_mem_read for test %d\n", test_num); + uint8_t opcode; + uint32_t testval; + if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } + printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr); + switch (opcode) { + case 0x90: //nop + printf("# Handling NOP\n"); + if (uc_mem_read(handle, 0x200000 + test_num * 0x100000, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + } else { + printf("ok %d - good uc_mem_read for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + printf("# uc_mem_read for test %d\n", test_num); - if (testval == tests[test_num]) { - printf("ok %d - passed test %d\n", log_num++, test_num); + if (testval == tests[test_num]) { + printf("ok %d - passed test %d\n", log_num++, test_num); + } else { + printf("not ok %d - failed test %d\n", log_num++, test_num); + printf("# Expected: 0x%x\n",tests[test_num]); + printf("# Received: 0x%x\n", testval); + } } - else { - printf("not ok %d - failed test %d\n", log_num++, test_num); - printf("# Expected: 0x%x\n",tests[test_num]); - printf("# Received: 0x%x\n", testval); + if (uc_mem_protect(handle, 0x200000 + test_num * 0x100000, 0x1000, UC_PROT_READ) != UC_ERR_OK) { + printf("not ok %d - uc_mem_protect fail during hook_code callback, addr: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + } else { + printf("ok %d - uc_mem_protect success\n", log_num++); } - } - if (uc_mem_protect(handle, 0x200000 + test_num * 0x100000, 0x1000, UC_PROT_READ) != UC_ERR_OK) { - printf("not ok %d - uc_mem_protect fail during hook_code callback, addr: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); - } - else { - printf("ok %d - uc_mem_protect success\n", log_num++); - } - test_num++; - break; - case 0xf4: //hlt - printf("# Handling HLT\n"); - if (uc_emu_stop(handle) != UC_ERR_OK) { - printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); - _exit(-1); - } - else { - printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++); - } - break; - default: //all others - printf("# Handling OTHER\n"); - break; - } + test_num++; + break; + case 0xf4: //hlt + printf("# Handling HLT\n"); + if (uc_emu_stop(handle) != UC_ERR_OK) { + printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + _exit(-1); + } else { + printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++); + } + break; + default: //all others + printf("# Handling OTHER\n"); + break; + } } // callback for tracing memory access (READ or WRITE) static void hook_mem_write(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) { - printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); + printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); } // callback for tracing invalid memory access (READ or WRITE) static bool hook_mem_invalid(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) { - uint32_t testval; - switch(type) { - default: - printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); - return false; - case UC_MEM_WRITE_PROT: - printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); + uint32_t testval; + switch(type) { + default: + printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); + return false; + case UC_MEM_WRITE_PROT: + printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); - if (uc_mem_read(handle, addr, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { - printf("not ok %d - uc_mem_read fail for address: 0x%" PRIx64 "\n", log_num++, addr); - } - else { - printf("ok %d - uc_mem_read success after mem_protect at test %d\n", log_num++, test_num - 1); - } + if (uc_mem_read(handle, addr, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail for address: 0x%" PRIx64 "\n", log_num++, addr); + } else { + printf("ok %d - uc_mem_read success after mem_protect at test %d\n", log_num++, test_num - 1); + } - if (uc_mem_protect(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { - printf("not ok %d - uc_mem_protect fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); - } - else { - printf("ok %d - uc_mem_protect success\n", log_num++); - } - return true; - } + if (uc_mem_protect(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { + printf("not ok %d - uc_mem_protect fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } else { + printf("ok %d - uc_mem_protect success\n", log_num++); + } + return true; + } } int main(int argc, char **argv, char **envp) { - uch handle, trace1, trace2; - uc_err err; - uint32_t addr, testval; - int32_t buf1[1024], buf2[1024], readbuf[1024]; - int i; - - //don't really care about quality of randomness - srand(time(NULL)); - for (i = 0; i < 1024; i++) { - buf1[i] = rand(); - buf2[i] = rand(); - } + uch handle, trace1, trace2; + uc_err err; + uint32_t addr, testval; + int32_t buf1[1024], buf2[1024], readbuf[1024]; + int i; - printf("# Memory protect test\n"); + //don't really care about quality of randomness + srand(time(NULL)); + for (i = 0; i < 1024; i++) { + buf1[i] = rand(); + buf2[i] = rand(); + } - // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); - if (err) { - printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err); - return 1; - } - else { - printf("ok %d - uc_open() success\n", log_num++); - } + printf("# Memory protect test\n"); - uc_mem_map(handle, CODE_SECTION, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC); - uc_mem_map(handle, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); - uc_mem_map(handle, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); - uc_mem_map(handle, 0x3ff000, 0x3000, UC_PROT_READ | UC_PROT_WRITE); + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + if (err) { + printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err); + return 1; + } else { + printf("ok %d - uc_open() success\n", log_num++); + } - // fill in sections that shouldn't get touched - if (uc_mem_write(handle, 0x3ff000, (uint8_t*)buf1, 4096)) { - printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); - return 2; - } - else { - printf("ok %d - Random buffer 1 written to memory\n", log_num++); - } + uc_mem_map(handle, CODE_SECTION, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC); + uc_mem_map(handle, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(handle, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(handle, 0x3ff000, 0x3000, UC_PROT_READ | UC_PROT_WRITE); - if (uc_mem_write(handle, 0x401000, (uint8_t*)buf2, 4096)) { - printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); - return 3; - } - else { - printf("ok %d - Random buffer 2 written to memory\n", log_num++); - } + // fill in sections that shouldn't get touched + if (uc_mem_write(handle, 0x3ff000, (uint8_t*)buf1, 4096)) { + printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); + return 2; + } else { + printf("ok %d - Random buffer 1 written to memory\n", log_num++); + } - // write machine code to be emulated to memory - if (uc_mem_write(handle, CODE_SECTION, PROGRAM, sizeof(PROGRAM))) { - printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); - return 4; - } - else { - printf("ok %d - Program written to memory\n", log_num++); - } + if (uc_mem_write(handle, 0x401000, (uint8_t*)buf2, 4096)) { + printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); + return 3; + } else { + printf("ok %d - Random buffer 2 written to memory\n", log_num++); + } - if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); - return 5; - } - else { - printf("ok %d - UC_HOOK_CODE installed\n", log_num++); - } + // write machine code to be emulated to memory + if (uc_mem_write(handle, CODE_SECTION, PROGRAM, sizeof(PROGRAM))) { + printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); + return 4; + } else { + printf("ok %d - Program written to memory\n", log_num++); + } - // intercept memory write events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); - return 6; - } - else { - printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); - } + if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); + return 5; + } else { + printf("ok %d - UC_HOOK_CODE installed\n", log_num++); + } - // intercept invalid memory events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID handler\n", log_num++); - return 7; - } - else { - printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); - } + // intercept memory write events + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); + return 6; + } else { + printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); + } - // emulate machine code until told to stop by hook_code - printf("# BEGIN execution\n"); - err = uc_emu_start(handle, CODE_SECTION, CODE_SECTION + CODE_SIZE, 0, 0); - if (err != UC_ERR_OK) { - printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); - return 8; - } - else { - printf("ok %d - uc_emu_start complete\n", log_num++); - } - printf("# END execution\n"); + // intercept invalid memory events + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID handler\n", log_num++); + return 7; + } else { + printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); + } - //read from the remapped memory - testval = 0x42424242; - for (addr = 0x200000; addr <= 0x400000; addr += 0x100000) { - uint32_t val; - if (uc_mem_read(handle, addr, (uint8_t*)&val, sizeof(val)) != UC_ERR_OK) { - printf("not ok %d - Failed uc_mem_read for address 0x%x\n", log_num++, addr); - } - else { - printf("ok %d - Good uc_mem_read from 0x%x\n", log_num++, addr); - } - if (val != testval) { - printf("not ok %d - Read 0x%x, expected 0x%x\n", log_num++, val, testval); - } - else { - printf("ok %d - Correct value retrieved\n", log_num++); - } - testval += 0x02020202; - } + // emulate machine code until told to stop by hook_code + printf("# BEGIN execution\n"); + err = uc_emu_start(handle, CODE_SECTION, CODE_SECTION + CODE_SIZE, 0, 0); + if (err != UC_ERR_OK) { + printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); + return 8; + } else { + printf("ok %d - uc_emu_start complete\n", log_num++); + } + printf("# END execution\n"); - //account for the two mods made by the machine code - buf1[512] = 0x47474747; - buf2[512] = 0x48484848; + //read from the remapped memory + testval = 0x42424242; + for (addr = 0x200000; addr <= 0x400000; addr += 0x100000) { + uint32_t val; + if (uc_mem_read(handle, addr, (uint8_t*)&val, sizeof(val)) != UC_ERR_OK) { + printf("not ok %d - Failed uc_mem_read for address 0x%x\n", log_num++, addr); + } else { + printf("ok %d - Good uc_mem_read from 0x%x\n", log_num++, addr); + } + if (val != testval) { + printf("not ok %d - Read 0x%x, expected 0x%x\n", log_num++, val, testval); + } else { + printf("ok %d - Correct value retrieved\n", log_num++); + } + testval += 0x02020202; + } - //make sure that random blocks didn't get nuked - // fill in sections that shouldn't get touched - if (uc_mem_read(handle, 0x3ff000, (uint8_t*)readbuf, 4096)) { - printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++); - } - else { - printf("ok %d - Random buffer 1 read from memory\n", log_num++); - if (memcmp(buf1, readbuf, 4096)) { - printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++); - } - else { - printf("ok %d - Random buffer 1 contents are correct\n", log_num++); - } - } + //account for the two mods made by the machine code + buf1[512] = 0x47474747; + buf2[512] = 0x48484848; - if (uc_mem_read(handle, 0x401000, (uint8_t*)readbuf, 4096)) { - printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); - } - else { - printf("ok %d - Random buffer 2 read from memory\n", log_num++); - if (memcmp(buf2, readbuf, 4096)) { - printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++); - } - else { - printf("ok %d - Random buffer 2 contents are correct\n", log_num++); - } - } + //make sure that random blocks didn't get nuked + // fill in sections that shouldn't get touched + if (uc_mem_read(handle, 0x3ff000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++); + } else { + printf("ok %d - Random buffer 1 read from memory\n", log_num++); + if (memcmp(buf1, readbuf, 4096)) { + printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++); + } else { + printf("ok %d - Random buffer 1 contents are correct\n", log_num++); + } + } - if (uc_close(&handle) == UC_ERR_OK) { - printf("ok %d - uc_close complete\n", log_num++); - } - else { - printf("not ok %d - uc_close complete\n", log_num++); - } + if (uc_mem_read(handle, 0x401000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); + } else { + printf("ok %d - Random buffer 2 read from memory\n", log_num++); + if (memcmp(buf2, readbuf, 4096)) { + printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++); + } else { + printf("ok %d - Random buffer 2 contents are correct\n", log_num++); + } + } - return 0; + if (uc_close(&handle) == UC_ERR_OK) { + printf("ok %d - uc_close complete\n", log_num++); + } else { + printf("not ok %d - uc_close complete\n", log_num++); + } + + return 0; } diff --git a/samples/mem_unmap.c b/samples/mem_unmap.c index 6f93673d..b31bf220 100644 --- a/samples/mem_unmap.c +++ b/samples/mem_unmap.c @@ -1,23 +1,23 @@ /* -uc_mem_unmap demo / unit test + uc_mem_unmap demo / unit test -Copyright(c) 2015 Chris Eagle + Copyright(c) 2015 Chris Eagle -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -version 2 as published by the Free Software Foundation. + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ + */ #define __STDC_FORMAT_MACROS #include @@ -30,19 +30,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include unsigned char PROGRAM[] = - "\xc7\x05\x00\x00\x20\x00\x41\x41\x41\x41\x90\xc7\x05\x00\x00\x20" - "\x00\x42\x42\x42\x42\xc7\x05\x00\x00\x30\x00\x43\x43\x43\x43\x90" - "\xc7\x05\x00\x00\x30\x00\x44\x44\x44\x44\xc7\x05\x00\x00\x40\x00" - "\x45\x45\x45\x45\x90\xc7\x05\x00\x00\x40\x00\x46\x46\x46\x46\xf4"; -// total size: 64 bytes + "\xc7\x05\x00\x00\x20\x00\x41\x41\x41\x41\x90\xc7\x05\x00\x00\x20" + "\x00\x42\x42\x42\x42\xc7\x05\x00\x00\x30\x00\x43\x43\x43\x43\x90" + "\xc7\x05\x00\x00\x30\x00\x44\x44\x44\x44\xc7\x05\x00\x00\x40\x00" + "\x45\x45\x45\x45\x90\xc7\x05\x00\x00\x40\x00\x46\x46\x46\x46\xf4"; + // total size: 64 bytes /* -; assumes code section at 0x100000 -; assumes data section at 0x200000, initially rw -; assumes data section at 0x300000, initially rw -; assumes data section at 0x400000, initially rw + ; assumes code section at 0x100000 + ; assumes data section at 0x200000, initially rw + ; assumes data section at 0x300000, initially rw + ; assumes data section at 0x400000, initially rw -; with installed hooks unmaps or maps on each nop + ; with installed hooks unmaps or maps on each nop mov dword [0x200000], 0x41414141 nop ; unmap it @@ -57,13 +57,13 @@ unsigned char PROGRAM[] = mov dword [0x400000], 0x46464646 hlt ; tell hook function we are done -*/ + */ int test_num = 0; uint32_t tests[] = { - 0x41414141, - 0x43434343, - 0x45454545 + 0x41414141, + 0x43434343, + 0x45454545 }; static int log_num = 1; @@ -74,240 +74,219 @@ static int log_num = 1; // callback for tracing instruction static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) { - uint8_t opcode; - uint32_t testval; - if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) { - printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); - } - printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr); - switch (opcode) { - case 0x90: //nop - printf("# Handling NOP\n"); - if (uc_mem_read(handle, 0x200000 + test_num * 0x100000, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { - printf("not ok %d - uc_mem_read fail for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); - } - else { - printf("ok %d - good uc_mem_read for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); - printf("# uc_mem_read for test %d\n", test_num); + uint8_t opcode; + uint32_t testval; + if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } + printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr); + switch (opcode) { + case 0x90: //nop + printf("# Handling NOP\n"); + if (uc_mem_read(handle, 0x200000 + test_num * 0x100000, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + } else { + printf("ok %d - good uc_mem_read for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + printf("# uc_mem_read for test %d\n", test_num); - if (testval == tests[test_num]) { - printf("ok %d - passed test %d\n", log_num++, test_num); + if (testval == tests[test_num]) { + printf("ok %d - passed test %d\n", log_num++, test_num); + } else { + printf("not ok %d - failed test %d\n", log_num++, test_num); + printf("# Expected: 0x%x\n",tests[test_num]); + printf("# Received: 0x%x\n", testval); + } } - else { - printf("not ok %d - failed test %d\n", log_num++, test_num); - printf("# Expected: 0x%x\n",tests[test_num]); - printf("# Received: 0x%x\n", testval); + if (uc_mem_unmap(handle, 0x200000 + test_num * 0x100000, 0x1000) != UC_ERR_OK) { + printf("not ok %d - uc_mem_unmap fail during hook_code callback, addr: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + } else { + printf("ok %d - uc_mem_unmap success\n", log_num++); } - } - if (uc_mem_unmap(handle, 0x200000 + test_num * 0x100000, 0x1000) != UC_ERR_OK) { - printf("not ok %d - uc_mem_unmap fail during hook_code callback, addr: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); - } - else { - printf("ok %d - uc_mem_unmap success\n", log_num++); - } - test_num++; - break; - case 0xf4: //hlt - printf("# Handling HLT\n"); - if (uc_emu_stop(handle) != UC_ERR_OK) { - printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); - _exit(-1); - } - else { - printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++); - } - break; - default: //all others - printf("# Handling OTHER\n"); - break; - } + test_num++; + break; + case 0xf4: //hlt + printf("# Handling HLT\n"); + if (uc_emu_stop(handle) != UC_ERR_OK) { + printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + _exit(-1); + } else { + printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++); + } + break; + default: //all others + printf("# Handling OTHER\n"); + break; + } } // callback for tracing memory access (READ or WRITE) static void hook_mem_write(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) { - printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); + printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); } // callback for tracing invalid memory access (READ or WRITE) static bool hook_mem_invalid(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) { - uint32_t testval; - switch(type) { - default: - printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); - return false; - case UC_MEM_WRITE: - printf("# write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); + uint32_t testval; + switch(type) { + default: + printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); + return false; + case UC_MEM_WRITE: + printf("# write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); - if (uc_mem_read(handle, addr, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { - printf("ok %d - uc_mem_read fail for address: 0x%" PRIx64 "\n", log_num++, addr); - } - else { - printf("not ok %d - uc_mem_read success after unmap at test %d\n", log_num++, test_num - 1); - } + if (uc_mem_read(handle, addr, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + printf("ok %d - uc_mem_read fail for address: 0x%" PRIx64 "\n", log_num++, addr); + } else { + printf("not ok %d - uc_mem_read success after unmap at test %d\n", log_num++, test_num - 1); + } - if (uc_mem_map(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { - printf("not ok %d - uc_mem_map fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); - } - else { - printf("ok %d - uc_mem_map success\n", log_num++); - } - return true; - } + if (uc_mem_map(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { + printf("not ok %d - uc_mem_map fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } else { + printf("ok %d - uc_mem_map success\n", log_num++); + } + return true; + } } int main(int argc, char **argv, char **envp) { - uch handle, trace1, trace2; - uc_err err; - uint32_t addr, testval; - int32_t buf1[1024], buf2[1024], readbuf[1024]; - int i; - - //don't really care about quality of randomness - srand(time(NULL)); - for (i = 0; i < 1024; i++) { - buf1[i] = rand(); - buf2[i] = rand(); - } + uch handle, trace1, trace2; + uc_err err; + uint32_t addr, testval; + int32_t buf1[1024], buf2[1024], readbuf[1024]; + int i; - printf("# Memory unmapping test\n"); + //don't really care about quality of randomness + srand(time(NULL)); + for (i = 0; i < 1024; i++) { + buf1[i] = rand(); + buf2[i] = rand(); + } - // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); - if (err) { - printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err); - return 1; - } - else { - printf("ok %d - uc_open() success\n", log_num++); - } + printf("# Memory unmapping test\n"); - uc_mem_map(handle, CODE_SECTION, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC); - uc_mem_map(handle, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); - uc_mem_map(handle, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); - uc_mem_map(handle, 0x3ff000, 0x3000, UC_PROT_READ | UC_PROT_WRITE); + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + if (err) { + printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err); + return 1; + } else { + printf("ok %d - uc_open() success\n", log_num++); + } - // fill in sections that shouldn't get touched - if (uc_mem_write(handle, 0x3ff000, (uint8_t*)buf1, 4096)) { - printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); - return 2; - } - else { - printf("ok %d - Random buffer 1 written to memory\n", log_num++); - } + uc_mem_map(handle, CODE_SECTION, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC); + uc_mem_map(handle, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(handle, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(handle, 0x3ff000, 0x3000, UC_PROT_READ | UC_PROT_WRITE); - if (uc_mem_write(handle, 0x401000, (uint8_t*)buf2, 4096)) { - printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); - return 3; - } - else { - printf("ok %d - Random buffer 2 written to memory\n", log_num++); - } + // fill in sections that shouldn't get touched + if (uc_mem_write(handle, 0x3ff000, (uint8_t*)buf1, 4096)) { + printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); + return 2; + } else { + printf("ok %d - Random buffer 1 written to memory\n", log_num++); + } - // write machine code to be emulated to memory - if (uc_mem_write(handle, CODE_SECTION, PROGRAM, sizeof(PROGRAM))) { - printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); - return 4; - } - else { - printf("ok %d - Program written to memory\n", log_num++); - } + if (uc_mem_write(handle, 0x401000, (uint8_t*)buf2, 4096)) { + printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); + return 3; + } else { + printf("ok %d - Random buffer 2 written to memory\n", log_num++); + } - if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); - return 5; - } - else { - printf("ok %d - UC_HOOK_CODE installed\n", log_num++); - } + // write machine code to be emulated to memory + if (uc_mem_write(handle, CODE_SECTION, PROGRAM, sizeof(PROGRAM))) { + printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); + return 4; + } else { + printf("ok %d - Program written to memory\n", log_num++); + } - // intercept memory write events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); - return 6; - } - else { - printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); - } + if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); + return 5; + } else { + printf("ok %d - UC_HOOK_CODE installed\n", log_num++); + } - // intercept invalid memory events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID handler\n", log_num++); - return 7; - } - else { - printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); - } + // intercept memory write events + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); + return 6; + } else { + printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); + } - // emulate machine code until told to stop by hook_code - printf("# BEGIN execution\n"); - err = uc_emu_start(handle, CODE_SECTION, CODE_SECTION + CODE_SIZE, 0, 0); - if (err != UC_ERR_OK) { - printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); - return 8; - } - else { - printf("ok %d - uc_emu_start complete\n", log_num++); - } - printf("# END execution\n"); + // intercept invalid memory events + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID handler\n", log_num++); + return 7; + } else { + printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); + } - //read from the remapped memory - testval = 0x42424242; - for (addr = 0x200000; addr <= 0x400000; addr += 0x100000) { - uint32_t val; - if (uc_mem_read(handle, addr, (uint8_t*)&val, sizeof(val)) != UC_ERR_OK) { - printf("not ok %d - Failed uc_mem_read for address 0x%x\n", log_num++, addr); - } - else { - printf("ok %d - Good uc_mem_read from 0x%x\n", log_num++, addr); - } - if (val != testval) { - printf("not ok %d - Read 0x%x, expected 0x%x\n", log_num++, val, testval); - } - else { - printf("ok %d - Correct value retrieved\n", log_num++); - } - testval += 0x02020202; - } + // emulate machine code until told to stop by hook_code + printf("# BEGIN execution\n"); + err = uc_emu_start(handle, CODE_SECTION, CODE_SECTION + CODE_SIZE, 0, 0); + if (err != UC_ERR_OK) { + printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); + return 8; + } else { + printf("ok %d - uc_emu_start complete\n", log_num++); + } + printf("# END execution\n"); - //make sure that random blocks didn't get nuked - // fill in sections that shouldn't get touched - if (uc_mem_read(handle, 0x3ff000, (uint8_t*)readbuf, 4096)) { - printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++); - } - else { - printf("ok %d - Random buffer 1 read from memory\n", log_num++); - if (memcmp(buf1, readbuf, 4096)) { - printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++); - } - else { - printf("ok %d - Random buffer 1 contents are correct\n", log_num++); - } - } + //read from the remapped memory + testval = 0x42424242; + for (addr = 0x200000; addr <= 0x400000; addr += 0x100000) { + uint32_t val; + if (uc_mem_read(handle, addr, (uint8_t*)&val, sizeof(val)) != UC_ERR_OK) { + printf("not ok %d - Failed uc_mem_read for address 0x%x\n", log_num++, addr); + } else { + printf("ok %d - Good uc_mem_read from 0x%x\n", log_num++, addr); + } + if (val != testval) { + printf("not ok %d - Read 0x%x, expected 0x%x\n", log_num++, val, testval); + } else { + printf("ok %d - Correct value retrieved\n", log_num++); + } + testval += 0x02020202; + } - if (uc_mem_read(handle, 0x401000, (uint8_t*)readbuf, 4096)) { - printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); - } - else { - printf("ok %d - Random buffer 2 read from memory\n", log_num++); - if (memcmp(buf2, readbuf, 4096)) { - printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++); - } - else { - printf("ok %d - Random buffer 2 contents are correct\n", log_num++); - } - } + //make sure that random blocks didn't get nuked + // fill in sections that shouldn't get touched + if (uc_mem_read(handle, 0x3ff000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++); + } else { + printf("ok %d - Random buffer 1 read from memory\n", log_num++); + if (memcmp(buf1, readbuf, 4096)) { + printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++); + } else { + printf("ok %d - Random buffer 1 contents are correct\n", log_num++); + } + } - if (uc_close(&handle) == UC_ERR_OK) { - printf("ok %d - uc_close complete\n", log_num++); - } - else { - printf("not ok %d - uc_close complete\n", log_num++); - } + if (uc_mem_read(handle, 0x401000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); + } else { + printf("ok %d - Random buffer 2 read from memory\n", log_num++); + if (memcmp(buf2, readbuf, 4096)) { + printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++); + } else { + printf("ok %d - Random buffer 2 contents are correct\n", log_num++); + } + } - return 0; + if (uc_close(&handle) == UC_ERR_OK) { + printf("ok %d - uc_close complete\n", log_num++); + } else { + printf("not ok %d - uc_close complete\n", log_num++); + } + + return 0; } diff --git a/uc.c b/uc.c index 622de423..3db40db3 100644 --- a/uc.c +++ b/uc.c @@ -670,14 +670,14 @@ static uint8_t *copy_region(uch handle, MemoryRegion *mr) } /* -Split the given MemoryRegion at the indicated address for the indicated size -this may result in the create of up to 3 spanning sections. If the delete -parameter is true, the no new section will be created to replace the indicate -range. This functions exists to support uc_mem_protect and uc_mem_unmap. + Split the given MemoryRegion at the indicated address for the indicated size + this may result in the create of up to 3 spanning sections. If the delete + parameter is true, the no new section will be created to replace the indicate + range. This functions exists to support uc_mem_protect and uc_mem_unmap. -This is a static function and callers have already done some preliminary -parameter validation. -*/ + This is a static function and callers have already done some preliminary + parameter validation. + */ //TODO: investigate whether qemu region manipulation functions already offer this capability static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, size_t size, bool do_delete) { @@ -709,7 +709,7 @@ static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, size_t perms = mr->perms; begin = mr->addr; end = mr->end; - + if (uc_mem_unmap(handle, mr->addr, int128_get64(mr->size)) != UC_ERR_OK) goto error; @@ -784,7 +784,7 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) // check for only valid permissions if ((perms & ~UC_PROT_ALL) != 0) return UC_ERR_INVAL; - + //check that user's entire requested block is mapped if (!check_mem_area(uc, address, size)) return UC_ERR_NOMEM; @@ -860,8 +860,7 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) break; } } - } - else { + } else { //ouch, we are going to need to subdivide blocks size_t count = 0, len; while(count < size) { From 8a6fe6dc9d8791f166e404c992b974849d30ce0f Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Sep 2015 18:43:29 +0800 Subject: [PATCH 54/64] update .gitignore --- .gitignore | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.gitignore b/.gitignore index fade14b3..f4d49d9e 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,16 @@ shellcode.static sample_m68k sample_m68k.exe sample_m68k.static +mem_exec +mem_exec.exe +mem_exec.static +mem_protect +mem_protect.exe +mem_protect.static +mem_unmap +mem_unmap.exe +mem_unmap.static + libunicorn*.dll libunicorn*.so From 6ca85a72ed6d131b40d22dac1c2ff69d41158a98 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 4 Sep 2015 01:02:38 +0800 Subject: [PATCH 55/64] simplify uc_mem_protect() & uc_mem_unmap() --- include/unicorn/unicorn.h | 39 +++++++------ qemu/softmmu_template.h | 9 +-- uc.c | 115 ++++++++++++++++++++------------------ 3 files changed, 84 insertions(+), 79 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index cbac0506..e9136f14 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -401,8 +401,7 @@ typedef enum uc_prot { /* Map memory in for emulation. - This API adds a memory region that can be used by emulation. The region is mapped - with permissions UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC. + This API adds a memory region that can be used by emulation. @handle: handle returned by uc_open() @address: starting address of the new memory region to be mapped in. @@ -413,12 +412,28 @@ typedef enum uc_prot { This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, or this will return with UC_ERR_INVAL error. - @return UC_ERR_OK on success, UC_ERR_NOMEM if no memory is available to satisfy the - request, or other value on failure (refer to uc_err enum for detailed error). + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). */ UNICORN_EXPORT uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms); +/* + Unmap a region of emulation memory. + This API deletes a memory mapping from the emulation memory space. + + @handle: handle returned by uc_open() + @address: starting address of the memory region to be unmapped. + This address must be aligned to 4KB, or this will return with UC_ERR_INVAL error. + @size: size of the memory region to be modified. + This size must be multiple of 4KB, or this will return with UC_ERR_INVAL error. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size); + /* Set memory permissions for emulation memory. This API changes permissions on an existing memory region. @@ -439,22 +454,6 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms); UNICORN_EXPORT uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms); -/* - Unmap a region of emulation memory. - This API deletes a memory mapping from the emulation memory space. - - @handle: handle returned by uc_open() - @address: starting address of the memory region to be unmapped. - This address must be aligned to 4KB, or this will return with UC_ERR_INVAL error. - @size: size of the memory region to be modified. - This size must be multiple of 4KB, or this will return with UC_ERR_INVAL error. - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size); - #ifdef __cplusplus } #endif diff --git a/qemu/softmmu_template.h b/qemu/softmmu_template.h index 3695c64e..de169bee 100644 --- a/qemu/softmmu_template.h +++ b/qemu/softmmu_template.h @@ -188,8 +188,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, (uch)uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; - } - else { + } else { env->invalid_addr = addr; env->invalid_error = UC_ERR_EXEC_PROT; // printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr); @@ -347,8 +346,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, (uch)uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; - } - else { + } else { env->invalid_addr = addr; env->invalid_error = UC_ERR_EXEC_PROT; // printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr); @@ -389,8 +387,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, (uch)uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; - } - else { + } else { env->invalid_addr = addr; env->invalid_error = UC_ERR_READ_PROT; // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); diff --git a/uc.c b/uc.c index 3db40db3..099af362 100644 --- a/uc.c +++ b/uc.c @@ -32,7 +32,7 @@ #include "qemu/include/hw/boards.h" static uint8_t *copy_region(uch uc, MemoryRegion *mr); -static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, size_t size, bool do_delete); +static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, size_t size); UNICORN_EXPORT unsigned int uc_version(unsigned int *major, unsigned int *minor) @@ -654,8 +654,8 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms) return UC_ERR_OK; } -//create a backup copy of the indicated MemoryRegion -//generally used in prepartion for splitting a MemoryRegion +// Create a backup copy of the indicated MemoryRegion. +// Generally used in prepartion for splitting a MemoryRegion. static uint8_t *copy_region(uch handle, MemoryRegion *mr) { uint8_t *block = (uint8_t *)malloc(int128_get64(mr->size)); @@ -666,6 +666,7 @@ static uint8_t *copy_region(uch handle, MemoryRegion *mr) block = NULL; } } + return block; } @@ -678,18 +679,18 @@ static uint8_t *copy_region(uch handle, MemoryRegion *mr) This is a static function and callers have already done some preliminary parameter validation. */ -//TODO: investigate whether qemu region manipulation functions already offer this capability -static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, size_t size, bool do_delete) +// TODO: investigate whether qemu region manipulation functions already offered +// this capability +static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, + size_t size) { uint8_t *backup; uint32_t perms; uint64_t begin, end, chunk_end; size_t l_size, m_size, r_size; + chunk_end = address + size; if (address <= mr->addr && chunk_end >= mr->end) { - //trivial case, if we are deleting, just unmap - if (do_delete) - return uc_mem_unmap(handle, mr->addr, int128_get64(mr->size)) == UC_ERR_OK; return true; } @@ -731,17 +732,17 @@ static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, size_t r_size = (size_t)(end - chunk_end); m_size = (size_t)(chunk_end - address); - //If there are error in any of the below operations, things are too far gone - //at that point to recover. Could try to remap orignal region, but these smaller - //allocation just failed so no guarantee that we can recover the original - //allocation at this point + // If there are error in any of the below operations, things are too far gone + // at that point to recover. Could try to remap orignal region, but these smaller + // allocation just failed so no guarantee that we can recover the original + // allocation at this point if (l_size > 0) { if (uc_mem_map(handle, begin, l_size, perms) != UC_ERR_OK) goto error; if (uc_mem_write(handle, begin, backup, l_size) != UC_ERR_OK) goto error; } - if (m_size > 0 && !do_delete) { + if (m_size > 0) { if (uc_mem_map(handle, address, m_size, perms) != UC_ERR_OK) goto error; if (uc_mem_write(handle, address, backup + l_size, m_size) != UC_ERR_OK) @@ -764,6 +765,8 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) { struct uc_struct* uc = (struct uc_struct *)handle; MemoryRegion *mr; + uint64_t addr = address; + size_t count, len; if (handle == 0) // invalid handle @@ -789,31 +792,30 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) if (!check_mem_area(uc, address, size)) return UC_ERR_NOMEM; - //Now we know entire region is mapped, so change permissions - //If request exactly matches a region we don't need to split - mr = memory_mapping(uc, address); - if (address != mr->addr || size != int128_get64(mr->size)) { - //ouch, we are going to need to subdivide blocks - uint64_t addr = address; - size_t count = 0, len; - while(count < size) { - MemoryRegion *mr = memory_mapping(uc, addr); - len = MIN(size - count, mr->end - addr); - if (!split_region(handle, mr, addr, len, false)) - return UC_ERR_NOMEM; - count += len; - addr += len; - } - //Grab a pointer to the newly split MemoryRegion - mr = memory_mapping(uc, address); - if (mr == NULL) { - //this should never happern if splitting succeeded + // Now we know entire region is mapped, so change permissions + // We may need to split regions if this area spans adjacent regions + addr = address; + count = 0; + while(count < size) { + mr = memory_mapping(uc, addr); + len = MIN(size - count, mr->end - addr); + if (!split_region(handle, mr, addr, len)) return UC_ERR_NOMEM; - } + count += len; + addr += len; + } + + // Now iterate all the regions to set permission + addr = address; + count = 0; + while(count < size) { + mr = memory_mapping(uc, addr); + len = MIN(size - count, mr->end - addr); + mr->perms = perms; + uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0); + count += len; + addr += len; } - //regions exactly matches an existing region just change perms - mr->perms = perms; - uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0); return UC_ERR_OK; } @@ -824,6 +826,8 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) MemoryRegion *mr; unsigned int i; struct uc_struct* uc = (struct uc_struct *)handle; + uint64_t addr; + size_t count, len; if (handle == 0) // invalid handle @@ -845,12 +849,25 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) if (!check_mem_area(uc, address, size)) return UC_ERR_NOMEM; - //Now we know entire region is mapped, so begin the delete - //check trivial case first - mr = memory_mapping(uc, address); - if (address == mr->addr && size == int128_get64(mr->size)) { - //regions exactly matches an existing region just unmap it - //this termiantes a possible recursion between this function and split_region + // Now we know entire region is mapped, so change permissions + // We may need to split regions if this area spans adjacent regions + addr = address; + count = 0; + while(count < size) { + mr = memory_mapping(uc, addr); + len = MIN(size - count, mr->end - addr); + if (!split_region(handle, mr, addr, len)) + return UC_ERR_NOMEM; + count += len; + addr += len; + } + + // Now iterate all the regions to set permission + addr = address; + count = 0; + while(count < size) { + mr = memory_mapping(uc, addr); + len = MIN(size - count, mr->end - addr); uc->memory_unmap(uc, mr); for (i = 0; i < uc->mapped_block_count; i++) { if (uc->mapped_blocks[i] == mr) { @@ -860,18 +877,10 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) break; } } - } else { - //ouch, we are going to need to subdivide blocks - size_t count = 0, len; - while(count < size) { - MemoryRegion *mr = memory_mapping(uc, address); - len = MIN(size - count, mr->end - address); - if (!split_region(handle, mr, address, len, true)) - return UC_ERR_NOMEM; - count += len; - address += len; - } + count += len; + addr += len; } + return UC_ERR_OK; } From 2da46caef72905ae4c3b5beaf7f21ca76ad543e6 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 3 Sep 2015 12:26:36 -0700 Subject: [PATCH 56/64] smooth out split_region related code --- qemu/memory.c | 11 +++++++++ samples/mem_exec.c | 4 +-- samples/mem_protect.c | 4 +-- samples/mem_unmap.c | 4 +-- uc.c | 57 ++++++++++++++----------------------------- 5 files changed, 35 insertions(+), 45 deletions(-) diff --git a/qemu/memory.c b/qemu/memory.c index e04d59b7..be7933d5 100644 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -47,6 +47,7 @@ MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, ui void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) { + int i; target_ulong addr; //make sure all pages associated with the MemoryRegion are flushed for (addr = mr->addr; addr < mr->end; addr += uc->target_page_size) { @@ -54,6 +55,16 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) } mr->enabled = false; memory_region_del_subregion(get_system_memory(uc), mr); + + for (i = 0; i < uc->mapped_block_count; i++) { + if (uc->mapped_blocks[i] == mr) { + uc->mapped_block_count--; + //shift remainder of array down over deleted pointer + memcpy(&uc->mapped_blocks[i], &uc->mapped_blocks[i + 1], sizeof(MemoryRegion*) * (uc->mapped_block_count - i)); + break; + } + } + g_free(mr); } diff --git a/samples/mem_exec.c b/samples/mem_exec.c index 370fd1ea..19153b46 100644 --- a/samples/mem_exec.c +++ b/samples/mem_exec.c @@ -204,7 +204,7 @@ int main(int argc, char **argv, char **envp) printf("ok %d - Program written to memory\n", log_num++); } - if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { + if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); return 6; } else { @@ -212,7 +212,7 @@ int main(int argc, char **argv, char **envp) } // intercept memory write events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); return 7; } else { diff --git a/samples/mem_protect.c b/samples/mem_protect.c index 5739563e..d9644d51 100644 --- a/samples/mem_protect.c +++ b/samples/mem_protect.c @@ -212,7 +212,7 @@ int main(int argc, char **argv, char **envp) printf("ok %d - Program written to memory\n", log_num++); } - if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { + if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); return 5; } else { @@ -220,7 +220,7 @@ int main(int argc, char **argv, char **envp) } // intercept memory write events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); return 6; } else { diff --git a/samples/mem_unmap.c b/samples/mem_unmap.c index b31bf220..e35b95ba 100644 --- a/samples/mem_unmap.c +++ b/samples/mem_unmap.c @@ -207,7 +207,7 @@ int main(int argc, char **argv, char **envp) printf("ok %d - Program written to memory\n", log_num++); } - if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { + if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); return 5; } else { @@ -215,7 +215,7 @@ int main(int argc, char **argv, char **envp) } // intercept memory write events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) { + if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); return 6; } else { diff --git a/uc.c b/uc.c index 099af362..eaf1219a 100644 --- a/uc.c +++ b/uc.c @@ -32,7 +32,7 @@ #include "qemu/include/hw/boards.h" static uint8_t *copy_region(uch uc, MemoryRegion *mr); -static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, size_t size); +static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, size_t size, bool do_delete); UNICORN_EXPORT unsigned int uc_version(unsigned int *major, unsigned int *minor) @@ -678,11 +678,15 @@ static uint8_t *copy_region(uch handle, MemoryRegion *mr) This is a static function and callers have already done some preliminary parameter validation. + + The do_delete argument indicates that we are being called to support + uc_mem_unmap. In this case we save some time by choosing NOT to remap + the areas that are intended to get unmapped */ // TODO: investigate whether qemu region manipulation functions already offered // this capability static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, - size_t size) + size_t size, bool do_delete) { uint8_t *backup; uint32_t perms; @@ -690,9 +694,8 @@ static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, size_t l_size, m_size, r_size; chunk_end = address + size; - if (address <= mr->addr && chunk_end >= mr->end) { + if (address <= mr->addr && chunk_end >= mr->end) return true; - } if (size == 0) //trivial case @@ -742,7 +745,7 @@ static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, if (uc_mem_write(handle, begin, backup, l_size) != UC_ERR_OK) goto error; } - if (m_size > 0) { + if (m_size > 0 && !do_delete) { if (uc_mem_map(handle, address, m_size, perms) != UC_ERR_OK) goto error; if (uc_mem_write(handle, address, backup + l_size, m_size) != UC_ERR_OK) @@ -788,7 +791,7 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) if ((perms & ~UC_PROT_ALL) != 0) return UC_ERR_INVAL; - //check that user's entire requested block is mapped + // check that user's entire requested block is mapped if (!check_mem_area(uc, address, size)) return UC_ERR_NOMEM; @@ -799,24 +802,16 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) while(count < size) { mr = memory_mapping(uc, addr); len = MIN(size - count, mr->end - addr); - if (!split_region(handle, mr, addr, len)) + if (!split_region(handle, mr, addr, len, false)) return UC_ERR_NOMEM; - count += len; - addr += len; - } - // Now iterate all the regions to set permission - addr = address; - count = 0; - while(count < size) { mr = memory_mapping(uc, addr); - len = MIN(size - count, mr->end - addr); mr->perms = perms; uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0); + count += len; addr += len; } - return UC_ERR_OK; } @@ -824,7 +819,6 @@ UNICORN_EXPORT uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) { MemoryRegion *mr; - unsigned int i; struct uc_struct* uc = (struct uc_struct *)handle; uint64_t addr; size_t count, len; @@ -845,42 +839,27 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) if ((size & uc->target_page_align) != 0) return UC_ERR_MAP; - //check that user's entire requested block is mapped + // check that user's entire requested block is mapped if (!check_mem_area(uc, address, size)) return UC_ERR_NOMEM; - // Now we know entire region is mapped, so change permissions + // Now we know entire region is mapped, so do the unmap // We may need to split regions if this area spans adjacent regions addr = address; count = 0; while(count < size) { mr = memory_mapping(uc, addr); len = MIN(size - count, mr->end - addr); - if (!split_region(handle, mr, addr, len)) + if (!split_region(handle, mr, addr, len, true)) return UC_ERR_NOMEM; - count += len; - addr += len; - } - - // Now iterate all the regions to set permission - addr = address; - count = 0; - while(count < size) { + // if we can retieve the mapping, then no splitting took place + // so unmap here mr = memory_mapping(uc, addr); - len = MIN(size - count, mr->end - addr); - uc->memory_unmap(uc, mr); - for (i = 0; i < uc->mapped_block_count; i++) { - if (uc->mapped_blocks[i] == mr) { - uc->mapped_block_count--; - //shift remainder of array down over deleted pointer - memcpy(&uc->mapped_blocks[i], &uc->mapped_blocks[i + 1], sizeof(MemoryRegion*) * (uc->mapped_block_count - i)); - break; - } - } + if (mr != NULL) + uc->memory_unmap(uc, mr); count += len; addr += len; } - return UC_ERR_OK; } From e54519c09ff37011b043214713882398e7cb1c54 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 4 Sep 2015 09:20:13 +0800 Subject: [PATCH 57/64] cleanup --- uc.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/uc.c b/uc.c index eaf1219a..f9bbf846 100644 --- a/uc.c +++ b/uc.c @@ -642,7 +642,8 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms) return UC_ERR_INVAL; if ((uc->mapped_block_count & (MEM_BLOCK_INCR - 1)) == 0) { //time to grow - regions = (MemoryRegion**)realloc(uc->mapped_blocks, sizeof(MemoryRegion*) * (uc->mapped_block_count + MEM_BLOCK_INCR)); + regions = (MemoryRegion**)realloc(uc->mapped_blocks, + sizeof(MemoryRegion*) * (uc->mapped_block_count + MEM_BLOCK_INCR)); if (regions == NULL) { return UC_ERR_NOMEM; } @@ -694,26 +695,30 @@ static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, size_t l_size, m_size, r_size; chunk_end = address + size; + + // if this region belongs to area [address, address+size], + // then there is no work to do. if (address <= mr->addr && chunk_end >= mr->end) return true; if (size == 0) - //trivial case + // trivial case return true; if (address >= mr->end || chunk_end <= mr->addr) - //impossible case + // impossible case return false; backup = copy_region(handle, mr); if (backup == NULL) return false; - //save the essential information required for the split before mr gets deleted + // save the essential information required for the split before mr gets deleted perms = mr->perms; begin = mr->addr; end = mr->end; + // unmap this region first, then do split it later if (uc_mem_unmap(handle, mr->addr, int128_get64(mr->size)) != UC_ERR_OK) goto error; @@ -724,13 +729,13 @@ static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, * case 3 |---size--| */ - //adjust some things + // adjust some things if (address < begin) address = begin; if (chunk_end > end) chunk_end = end; - //compute sub region sizes + // compute sub region sizes l_size = (size_t)(address - begin); r_size = (size_t)(end - chunk_end); m_size = (size_t)(chunk_end - address); @@ -745,19 +750,23 @@ static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, if (uc_mem_write(handle, begin, backup, l_size) != UC_ERR_OK) goto error; } + if (m_size > 0 && !do_delete) { if (uc_mem_map(handle, address, m_size, perms) != UC_ERR_OK) goto error; if (uc_mem_write(handle, address, backup + l_size, m_size) != UC_ERR_OK) goto error; } + if (r_size > 0) { if (uc_mem_map(handle, chunk_end, r_size, perms) != UC_ERR_OK) goto error; if (uc_mem_write(handle, chunk_end, backup + l_size + m_size, r_size) != UC_ERR_OK) goto error; } + return true; + error: free(backup); return false; @@ -852,7 +861,7 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) len = MIN(size - count, mr->end - addr); if (!split_region(handle, mr, addr, len, true)) return UC_ERR_NOMEM; - // if we can retieve the mapping, then no splitting took place + // if we can retrieve the mapping, then no splitting took place // so unmap here mr = memory_mapping(uc, addr); if (mr != NULL) From 0962c4822b99bfa6215a3381ef68f4943ca71663 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 4 Sep 2015 09:43:31 +0800 Subject: [PATCH 58/64] cleanup & update bindings' constants --- bindings/go/unicorn/unicorn_const.go | 16 ++++++++++------ bindings/python/unicorn/unicorn_const.py | 16 ++++++++++------ include/unicorn/unicorn.h | 5 ++--- samples/sample_sparc.c | 2 +- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 427b34cd..e5ab6863 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -34,7 +34,7 @@ const ( UC_MODE_MIPS64 = 8 UC_ERR_OK = 0 - UC_ERR_OOM = 1 + UC_ERR_NOMEM = 1 UC_ERR_ARCH = 2 UC_ERR_HANDLE = 3 UC_ERR_UCH = 4 @@ -46,13 +46,16 @@ const ( UC_ERR_HOOK = 10 UC_ERR_INSN_INVALID = 11 UC_ERR_MAP = 12 - UC_ERR_MEM_WRITE_NW = 13 - UC_ERR_MEM_READ_NR = 14 + UC_ERR_WRITE_PROT = 13 + UC_ERR_READ_PROT = 14 + UC_ERR_EXEC_PROT = 15 + UC_ERR_INVAL = 16 UC_MEM_READ = 16 UC_MEM_WRITE = 17 UC_MEM_READ_WRITE = 18 - UC_MEM_WRITE_NW = 19 - UC_MEM_READ_NR = 20 + UC_MEM_WRITE_PROT = 19 + UC_MEM_READ_PROT = 20 + UC_MEM_EXEC_PROT = 21 UC_HOOK_INTR = 32 UC_HOOK_INSN = 33 UC_HOOK_CODE = 34 @@ -65,5 +68,6 @@ const ( UC_PROT_NONE = 0 UC_PROT_READ = 1 UC_PROT_WRITE = 2 - UC_PROT_ALL = 3 + UC_PROT_EXEC = 4 + UC_PROT_ALL = 7 ) \ No newline at end of file diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index f2c8f0db..0f2bf718 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -32,7 +32,7 @@ UC_MODE_MIPS32 = 4 UC_MODE_MIPS64 = 8 UC_ERR_OK = 0 -UC_ERR_OOM = 1 +UC_ERR_NOMEM = 1 UC_ERR_ARCH = 2 UC_ERR_HANDLE = 3 UC_ERR_UCH = 4 @@ -44,13 +44,16 @@ UC_ERR_CODE_INVALID = 9 UC_ERR_HOOK = 10 UC_ERR_INSN_INVALID = 11 UC_ERR_MAP = 12 -UC_ERR_MEM_WRITE_NW = 13 -UC_ERR_MEM_READ_NR = 14 +UC_ERR_WRITE_PROT = 13 +UC_ERR_READ_PROT = 14 +UC_ERR_EXEC_PROT = 15 +UC_ERR_INVAL = 16 UC_MEM_READ = 16 UC_MEM_WRITE = 17 UC_MEM_READ_WRITE = 18 -UC_MEM_WRITE_NW = 19 -UC_MEM_READ_NR = 20 +UC_MEM_WRITE_PROT = 19 +UC_MEM_READ_PROT = 20 +UC_MEM_EXEC_PROT = 21 UC_HOOK_INTR = 32 UC_HOOK_INSN = 33 UC_HOOK_CODE = 34 @@ -63,4 +66,5 @@ UC_HOOK_MEM_READ_WRITE = 39 UC_PROT_NONE = 0 UC_PROT_READ = 1 UC_PROT_WRITE = 2 -UC_PROT_ALL = 3 +UC_PROT_EXEC = 4 +UC_PROT_ALL = 7 diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index e9136f14..c6e5015c 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -447,9 +447,8 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size); This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, or this will return with UC_ERR_INVAL error. - @return UC_ERR_OK on success, UC_ERR_HANDLE for an invalid handle, UC_ERR_INVAL - for invalid perms or unaligned address or size, UC_ERR_NOMEM if entire region - is not mapped. + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). */ UNICORN_EXPORT uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms); diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index c7f2971a..ee81aad9 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -64,7 +64,7 @@ static void test_sparc(void) // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(SPARC_CODE) -1, 0, 0); + err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(SPARC_CODE) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err)); From da46071c7d5528deb6832d0d82e6237688ebd4ec Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Thu, 3 Sep 2015 22:15:49 -0400 Subject: [PATCH 59/64] bring new code and samples up-to-date with API changes --- include/unicorn/unicorn.h | 4 +-- qemu/softmmu_template.h | 4 +-- samples/mem_exec.c | 57 ++++++++++++++++++------------------- samples/mem_protect.c | 59 ++++++++++++++++++++------------------- samples/mem_unmap.c | 59 ++++++++++++++++++++------------------- uc.c | 42 ++++++++++------------------ 6 files changed, 108 insertions(+), 117 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index ad373ab2..f3b4c1f2 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -433,7 +433,7 @@ uc_err uc_mem_map(ucengine *uc, uint64_t address, size_t size, uint32_t perms); for detailed error). */ UNICORN_EXPORT -uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size); +uc_err uc_mem_unmap(ucengine *uc, uint64_t address, size_t size); /* Set memory permissions for emulation memory. @@ -452,7 +452,7 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size); for detailed error). */ UNICORN_EXPORT -uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms); +uc_err uc_mem_protect(ucengine *uc, uint64_t address, size_t size, uint32_t perms); #ifdef __cplusplus } diff --git a/qemu/softmmu_template.h b/qemu/softmmu_template.h index ade85c85..3c851686 100644 --- a/qemu/softmmu_template.h +++ b/qemu/softmmu_template.h @@ -185,7 +185,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on fetch from NX if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { //non-executable if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, + uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { @@ -343,7 +343,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on fetch from NX if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { //non-executable if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, + uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { diff --git a/samples/mem_exec.c b/samples/mem_exec.c index 19153b46..075a5a4b 100644 --- a/samples/mem_exec.c +++ b/samples/mem_exec.c @@ -78,11 +78,11 @@ static int log_num = 1; #define CODE_SIZE 0x1000 // callback for tracing instruction -static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t addr, uint32_t size, void *user_data) { uint8_t opcode; - if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) { + if (uc_mem_read(uc, addr, &opcode, 1) != UC_ERR_OK) { printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); } @@ -90,7 +90,7 @@ static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) switch (opcode) { case 0xf4: //hlt printf("# Handling HLT\n"); - if (uc_emu_stop(handle) != UC_ERR_OK) { + if (uc_emu_stop(uc) != UC_ERR_OK) { printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); _exit(-1); } else { @@ -104,14 +104,14 @@ static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) } // callback for tracing memory access (READ or WRITE) -static void hook_mem_write(uch handle, uc_mem_type type, +static void hook_mem_write(ucengine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) { printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); } // callback for tracing invalid memory access (READ or WRITE) -static bool hook_mem_invalid(uch handle, uc_mem_type type, +static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) { switch(type) { @@ -122,7 +122,7 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, printf("# Fetch from non-executable memory at 0x%"PRIx64 "\n", addr); //make page executable - if (uc_mem_protect(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_EXEC) != UC_ERR_OK) { + if (uc_mem_protect(uc, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_EXEC) != UC_ERR_OK) { printf("not ok %d - uc_mem_protect fail for address: 0x%" PRIx64 "\n", log_num++, addr); } else { printf("ok %d - uc_mem_protect success at 0x%" PRIx64 "\n", log_num++, addr); @@ -131,7 +131,7 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, case UC_MEM_WRITE_PROT: printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); - if (uc_mem_protect(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { + if (uc_mem_protect(uc, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { printf("not ok %d - uc_mem_protect fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); } else { printf("ok %d - uc_mem_protect success\n", log_num++); @@ -142,7 +142,8 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, int main(int argc, char **argv, char **envp) { - uch handle, trace1, trace2; + ucengine *uc; + uc_hook_h trace1, trace2; uc_err err; uint32_t esp, eip; int32_t buf1[1024], buf2[1024], readbuf[1024]; @@ -158,7 +159,7 @@ int main(int argc, char **argv, char **envp) printf("# Memory protect test\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err); return 1; @@ -166,15 +167,15 @@ int main(int argc, char **argv, char **envp) printf("ok %d - uc_open() success\n", log_num++); } - uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_READ | UC_PROT_EXEC); - uc_mem_map(handle, 0x1ff000, 0x2000, UC_PROT_READ | UC_PROT_WRITE); - uc_mem_map(handle, 0x300000, 0x2000, UC_PROT_READ); - uc_mem_map(handle, 0xf00000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, 0x100000, 0x1000, UC_PROT_READ | UC_PROT_EXEC); + uc_mem_map(uc, 0x1ff000, 0x2000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, 0x300000, 0x2000, UC_PROT_READ); + uc_mem_map(uc, 0xf00000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); esp = 0xf00000 + 0x1000; // Setup stack pointer - if (uc_reg_write(handle, UC_X86_REG_ESP, &esp)) { + if (uc_reg_write(uc, UC_X86_REG_ESP, &esp)) { printf("not ok %d - Failed to set esp. quit!\n", log_num++); return 2; } else { @@ -182,14 +183,14 @@ int main(int argc, char **argv, char **envp) } // fill in sections that shouldn't get touched - if (uc_mem_write(handle, 0x1ff000, (uint8_t*)buf1, 4096)) { + if (uc_mem_write(uc, 0x1ff000, (uint8_t*)buf1, 4096)) { printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); return 3; } else { printf("ok %d - Random buffer 1 written to memory\n", log_num++); } - if (uc_mem_write(handle, 0x301000, (uint8_t*)buf2, 4096)) { + if (uc_mem_write(uc, 0x301000, (uint8_t*)buf2, 4096)) { printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); return 4; } else { @@ -197,31 +198,31 @@ int main(int argc, char **argv, char **envp) } // write machine code to be emulated to memory - if (uc_mem_write(handle, 0x100000, PROGRAM, sizeof(PROGRAM))) { + if (uc_mem_write(uc, 0x100000, PROGRAM, sizeof(PROGRAM))) { printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); return 5; } else { printf("ok %d - Program written to memory\n", log_num++); } - if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); + if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++); return 6; } else { printf("ok %d - UC_HOOK_CODE installed\n", log_num++); } // intercept memory write events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++); return 7; } else { printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); } // intercept invalid memory events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID handler\n", log_num++); + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++); return 8; } else { printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); @@ -229,7 +230,7 @@ int main(int argc, char **argv, char **envp) // emulate machine code until told to stop by hook_code printf("# BEGIN execution\n"); - err = uc_emu_start(handle, 0x100000, 0x400000, 0, 0); + err = uc_emu_start(uc, 0x100000, 0x400000, 0, 0); if (err != UC_ERR_OK) { printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); return 9; @@ -239,7 +240,7 @@ int main(int argc, char **argv, char **envp) printf("# END execution\n"); // get ending EIP - if (uc_reg_read(handle, UC_X86_REG_EIP, &eip)) { + if (uc_reg_read(uc, UC_X86_REG_EIP, &eip)) { printf("not ok %d - Failed to read eip.\n", log_num++); } else { printf("ok %d - Ending EIP 0x%x\n", log_num++, eip); @@ -247,7 +248,7 @@ int main(int argc, char **argv, char **envp) //make sure that random blocks didn't get nuked // fill in sections that shouldn't get touched - if (uc_mem_read(handle, 0x1ff000, (uint8_t*)readbuf, 4096)) { + if (uc_mem_read(uc, 0x1ff000, (uint8_t*)readbuf, 4096)) { printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++); } else { printf("ok %d - Random buffer 1 read from memory\n", log_num++); @@ -258,7 +259,7 @@ int main(int argc, char **argv, char **envp) } } - if (uc_mem_read(handle, 0x301000, (uint8_t*)readbuf, 4096)) { + if (uc_mem_read(uc, 0x301000, (uint8_t*)readbuf, 4096)) { printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); } else { printf("ok %d - Random buffer 2 read from memory\n", log_num++); @@ -269,7 +270,7 @@ int main(int argc, char **argv, char **envp) } } - if (uc_close(&handle) == UC_ERR_OK) { + if (uc_close(uc) == UC_ERR_OK) { printf("ok %d - uc_close complete\n", log_num++); } else { printf("not ok %d - uc_close complete\n", log_num++); diff --git a/samples/mem_protect.c b/samples/mem_protect.c index d9644d51..f1476593 100644 --- a/samples/mem_protect.c +++ b/samples/mem_protect.c @@ -77,18 +77,18 @@ static int log_num = 1; #define CODE_SIZE 0x1000 // callback for tracing instruction -static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t addr, uint32_t size, void *user_data) { uint8_t opcode; uint32_t testval; - if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) { + if (uc_mem_read(uc, addr, &opcode, 1) != UC_ERR_OK) { printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); } printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr); switch (opcode) { case 0x90: //nop printf("# Handling NOP\n"); - if (uc_mem_read(handle, 0x200000 + test_num * 0x100000, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + if (uc_mem_read(uc, 0x200000 + test_num * 0x100000, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { printf("not ok %d - uc_mem_read fail for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); } else { printf("ok %d - good uc_mem_read for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); @@ -102,7 +102,7 @@ static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) printf("# Received: 0x%x\n", testval); } } - if (uc_mem_protect(handle, 0x200000 + test_num * 0x100000, 0x1000, UC_PROT_READ) != UC_ERR_OK) { + if (uc_mem_protect(uc, 0x200000 + test_num * 0x100000, 0x1000, UC_PROT_READ) != UC_ERR_OK) { printf("not ok %d - uc_mem_protect fail during hook_code callback, addr: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); } else { printf("ok %d - uc_mem_protect success\n", log_num++); @@ -111,7 +111,7 @@ static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) break; case 0xf4: //hlt printf("# Handling HLT\n"); - if (uc_emu_stop(handle) != UC_ERR_OK) { + if (uc_emu_stop(uc) != UC_ERR_OK) { printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); _exit(-1); } else { @@ -125,14 +125,14 @@ static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) } // callback for tracing memory access (READ or WRITE) -static void hook_mem_write(uch handle, uc_mem_type type, +static void hook_mem_write(ucengine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) { printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); } // callback for tracing invalid memory access (READ or WRITE) -static bool hook_mem_invalid(uch handle, uc_mem_type type, +static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) { uint32_t testval; @@ -143,13 +143,13 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, case UC_MEM_WRITE_PROT: printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); - if (uc_mem_read(handle, addr, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + if (uc_mem_read(uc, addr, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { printf("not ok %d - uc_mem_read fail for address: 0x%" PRIx64 "\n", log_num++, addr); } else { printf("ok %d - uc_mem_read success after mem_protect at test %d\n", log_num++, test_num - 1); } - if (uc_mem_protect(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { + if (uc_mem_protect(uc, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { printf("not ok %d - uc_mem_protect fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); } else { printf("ok %d - uc_mem_protect success\n", log_num++); @@ -160,7 +160,8 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, int main(int argc, char **argv, char **envp) { - uch handle, trace1, trace2; + ucengine *uc; + uc_hook_h trace1, trace2; uc_err err; uint32_t addr, testval; int32_t buf1[1024], buf2[1024], readbuf[1024]; @@ -176,7 +177,7 @@ int main(int argc, char **argv, char **envp) printf("# Memory protect test\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err); return 1; @@ -184,20 +185,20 @@ int main(int argc, char **argv, char **envp) printf("ok %d - uc_open() success\n", log_num++); } - uc_mem_map(handle, CODE_SECTION, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC); - uc_mem_map(handle, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); - uc_mem_map(handle, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); - uc_mem_map(handle, 0x3ff000, 0x3000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, CODE_SECTION, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC); + uc_mem_map(uc, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, 0x3ff000, 0x3000, UC_PROT_READ | UC_PROT_WRITE); // fill in sections that shouldn't get touched - if (uc_mem_write(handle, 0x3ff000, (uint8_t*)buf1, 4096)) { + if (uc_mem_write(uc, 0x3ff000, (uint8_t*)buf1, 4096)) { printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); return 2; } else { printf("ok %d - Random buffer 1 written to memory\n", log_num++); } - if (uc_mem_write(handle, 0x401000, (uint8_t*)buf2, 4096)) { + if (uc_mem_write(uc, 0x401000, (uint8_t*)buf2, 4096)) { printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); return 3; } else { @@ -205,31 +206,31 @@ int main(int argc, char **argv, char **envp) } // write machine code to be emulated to memory - if (uc_mem_write(handle, CODE_SECTION, PROGRAM, sizeof(PROGRAM))) { + if (uc_mem_write(uc, CODE_SECTION, PROGRAM, sizeof(PROGRAM))) { printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); return 4; } else { printf("ok %d - Program written to memory\n", log_num++); } - if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); + if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++); return 5; } else { printf("ok %d - UC_HOOK_CODE installed\n", log_num++); } // intercept memory write events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++); return 6; } else { printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); } // intercept invalid memory events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID handler\n", log_num++); + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++); return 7; } else { printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); @@ -237,7 +238,7 @@ int main(int argc, char **argv, char **envp) // emulate machine code until told to stop by hook_code printf("# BEGIN execution\n"); - err = uc_emu_start(handle, CODE_SECTION, CODE_SECTION + CODE_SIZE, 0, 0); + err = uc_emu_start(uc, CODE_SECTION, CODE_SECTION + CODE_SIZE, 0, 0); if (err != UC_ERR_OK) { printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); return 8; @@ -250,7 +251,7 @@ int main(int argc, char **argv, char **envp) testval = 0x42424242; for (addr = 0x200000; addr <= 0x400000; addr += 0x100000) { uint32_t val; - if (uc_mem_read(handle, addr, (uint8_t*)&val, sizeof(val)) != UC_ERR_OK) { + if (uc_mem_read(uc, addr, (uint8_t*)&val, sizeof(val)) != UC_ERR_OK) { printf("not ok %d - Failed uc_mem_read for address 0x%x\n", log_num++, addr); } else { printf("ok %d - Good uc_mem_read from 0x%x\n", log_num++, addr); @@ -269,7 +270,7 @@ int main(int argc, char **argv, char **envp) //make sure that random blocks didn't get nuked // fill in sections that shouldn't get touched - if (uc_mem_read(handle, 0x3ff000, (uint8_t*)readbuf, 4096)) { + if (uc_mem_read(uc, 0x3ff000, (uint8_t*)readbuf, 4096)) { printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++); } else { printf("ok %d - Random buffer 1 read from memory\n", log_num++); @@ -280,7 +281,7 @@ int main(int argc, char **argv, char **envp) } } - if (uc_mem_read(handle, 0x401000, (uint8_t*)readbuf, 4096)) { + if (uc_mem_read(uc, 0x401000, (uint8_t*)readbuf, 4096)) { printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); } else { printf("ok %d - Random buffer 2 read from memory\n", log_num++); @@ -291,7 +292,7 @@ int main(int argc, char **argv, char **envp) } } - if (uc_close(&handle) == UC_ERR_OK) { + if (uc_close(uc) == UC_ERR_OK) { printf("ok %d - uc_close complete\n", log_num++); } else { printf("not ok %d - uc_close complete\n", log_num++); diff --git a/samples/mem_unmap.c b/samples/mem_unmap.c index e35b95ba..44866536 100644 --- a/samples/mem_unmap.c +++ b/samples/mem_unmap.c @@ -72,18 +72,18 @@ static int log_num = 1; #define CODE_SIZE 0x1000 // callback for tracing instruction -static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t addr, uint32_t size, void *user_data) { uint8_t opcode; uint32_t testval; - if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) { + if (uc_mem_read(uc, addr, &opcode, 1) != UC_ERR_OK) { printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); } printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr); switch (opcode) { case 0x90: //nop printf("# Handling NOP\n"); - if (uc_mem_read(handle, 0x200000 + test_num * 0x100000, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + if (uc_mem_read(uc, 0x200000 + test_num * 0x100000, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { printf("not ok %d - uc_mem_read fail for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); } else { printf("ok %d - good uc_mem_read for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); @@ -97,7 +97,7 @@ static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) printf("# Received: 0x%x\n", testval); } } - if (uc_mem_unmap(handle, 0x200000 + test_num * 0x100000, 0x1000) != UC_ERR_OK) { + if (uc_mem_unmap(uc, 0x200000 + test_num * 0x100000, 0x1000) != UC_ERR_OK) { printf("not ok %d - uc_mem_unmap fail during hook_code callback, addr: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); } else { printf("ok %d - uc_mem_unmap success\n", log_num++); @@ -106,7 +106,7 @@ static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) break; case 0xf4: //hlt printf("# Handling HLT\n"); - if (uc_emu_stop(handle) != UC_ERR_OK) { + if (uc_emu_stop(uc) != UC_ERR_OK) { printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr); _exit(-1); } else { @@ -120,14 +120,14 @@ static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data) } // callback for tracing memory access (READ or WRITE) -static void hook_mem_write(uch handle, uc_mem_type type, +static void hook_mem_write(ucengine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) { printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); } // callback for tracing invalid memory access (READ or WRITE) -static bool hook_mem_invalid(uch handle, uc_mem_type type, +static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) { uint32_t testval; @@ -138,13 +138,13 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, case UC_MEM_WRITE: printf("# write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); - if (uc_mem_read(handle, addr, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + if (uc_mem_read(uc, addr, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { printf("ok %d - uc_mem_read fail for address: 0x%" PRIx64 "\n", log_num++, addr); } else { printf("not ok %d - uc_mem_read success after unmap at test %d\n", log_num++, test_num - 1); } - if (uc_mem_map(handle, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { + if (uc_mem_map(uc, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { printf("not ok %d - uc_mem_map fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); } else { printf("ok %d - uc_mem_map success\n", log_num++); @@ -155,7 +155,8 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, int main(int argc, char **argv, char **envp) { - uch handle, trace1, trace2; + ucengine *uc; + uc_hook_h trace1, trace2; uc_err err; uint32_t addr, testval; int32_t buf1[1024], buf2[1024], readbuf[1024]; @@ -171,7 +172,7 @@ int main(int argc, char **argv, char **envp) printf("# Memory unmapping test\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err); return 1; @@ -179,20 +180,20 @@ int main(int argc, char **argv, char **envp) printf("ok %d - uc_open() success\n", log_num++); } - uc_mem_map(handle, CODE_SECTION, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC); - uc_mem_map(handle, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); - uc_mem_map(handle, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); - uc_mem_map(handle, 0x3ff000, 0x3000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, CODE_SECTION, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC); + uc_mem_map(uc, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, 0x3ff000, 0x3000, UC_PROT_READ | UC_PROT_WRITE); // fill in sections that shouldn't get touched - if (uc_mem_write(handle, 0x3ff000, (uint8_t*)buf1, 4096)) { + if (uc_mem_write(uc, 0x3ff000, (uint8_t*)buf1, 4096)) { printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); return 2; } else { printf("ok %d - Random buffer 1 written to memory\n", log_num++); } - if (uc_mem_write(handle, 0x401000, (uint8_t*)buf2, 4096)) { + if (uc_mem_write(uc, 0x401000, (uint8_t*)buf2, 4096)) { printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); return 3; } else { @@ -200,31 +201,31 @@ int main(int argc, char **argv, char **envp) } // write machine code to be emulated to memory - if (uc_mem_write(handle, CODE_SECTION, PROGRAM, sizeof(PROGRAM))) { + if (uc_mem_write(uc, CODE_SECTION, PROGRAM, sizeof(PROGRAM))) { printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); return 4; } else { printf("ok %d - Program written to memory\n", log_num++); } - if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); + if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++); return 5; } else { printf("ok %d - UC_HOOK_CODE installed\n", log_num++); } // intercept memory write events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++); return 6; } else { printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); } // intercept invalid memory events - if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { - printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID handler\n", log_num++); + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++); return 7; } else { printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); @@ -232,7 +233,7 @@ int main(int argc, char **argv, char **envp) // emulate machine code until told to stop by hook_code printf("# BEGIN execution\n"); - err = uc_emu_start(handle, CODE_SECTION, CODE_SECTION + CODE_SIZE, 0, 0); + err = uc_emu_start(uc, CODE_SECTION, CODE_SECTION + CODE_SIZE, 0, 0); if (err != UC_ERR_OK) { printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err)); return 8; @@ -245,7 +246,7 @@ int main(int argc, char **argv, char **envp) testval = 0x42424242; for (addr = 0x200000; addr <= 0x400000; addr += 0x100000) { uint32_t val; - if (uc_mem_read(handle, addr, (uint8_t*)&val, sizeof(val)) != UC_ERR_OK) { + if (uc_mem_read(uc, addr, (uint8_t*)&val, sizeof(val)) != UC_ERR_OK) { printf("not ok %d - Failed uc_mem_read for address 0x%x\n", log_num++, addr); } else { printf("ok %d - Good uc_mem_read from 0x%x\n", log_num++, addr); @@ -260,7 +261,7 @@ int main(int argc, char **argv, char **envp) //make sure that random blocks didn't get nuked // fill in sections that shouldn't get touched - if (uc_mem_read(handle, 0x3ff000, (uint8_t*)readbuf, 4096)) { + if (uc_mem_read(uc, 0x3ff000, (uint8_t*)readbuf, 4096)) { printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++); } else { printf("ok %d - Random buffer 1 read from memory\n", log_num++); @@ -271,7 +272,7 @@ int main(int argc, char **argv, char **envp) } } - if (uc_mem_read(handle, 0x401000, (uint8_t*)readbuf, 4096)) { + if (uc_mem_read(uc, 0x401000, (uint8_t*)readbuf, 4096)) { printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); } else { printf("ok %d - Random buffer 2 read from memory\n", log_num++); @@ -282,7 +283,7 @@ int main(int argc, char **argv, char **envp) } } - if (uc_close(&handle) == UC_ERR_OK) { + if (uc_close(uc) == UC_ERR_OK) { printf("ok %d - uc_close complete\n", log_num++); } else { printf("not ok %d - uc_close complete\n", log_num++); diff --git a/uc.c b/uc.c index 49d29cfd..6001e61f 100644 --- a/uc.c +++ b/uc.c @@ -31,8 +31,6 @@ #include "qemu/include/hw/boards.h" -static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr); -static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t address, size_t size, bool do_delete); UNICORN_EXPORT unsigned int uc_version(unsigned int *major, unsigned int *minor) @@ -589,11 +587,11 @@ uc_err uc_mem_map(ucengine *uc, uint64_t address, size_t size, uint32_t perms) // Create a backup copy of the indicated MemoryRegion. // Generally used in prepartion for splitting a MemoryRegion. -static uint8_t *copy_region(uch handle, MemoryRegion *mr) +static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr) { uint8_t *block = (uint8_t *)malloc(int128_get64(mr->size)); if (block != NULL) { - uc_err err = uc_mem_read(handle, mr->addr, block, int128_get64(mr->size)); + uc_err err = uc_mem_read(uc, mr->addr, block, int128_get64(mr->size)); if (err != UC_ERR_OK) { free(block); block = NULL; @@ -618,7 +616,7 @@ static uint8_t *copy_region(uch handle, MemoryRegion *mr) */ // TODO: investigate whether qemu region manipulation functions already offered // this capability -static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, +static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t address, size_t size, bool do_delete) { uint8_t *backup; @@ -641,7 +639,7 @@ static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, // impossible case return false; - backup = copy_region(handle, mr); + backup = copy_region(uc, mr); if (backup == NULL) return false; @@ -651,7 +649,7 @@ static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, end = mr->end; // unmap this region first, then do split it later - if (uc_mem_unmap(handle, mr->addr, int128_get64(mr->size)) != UC_ERR_OK) + if (uc_mem_unmap(uc, mr->addr, int128_get64(mr->size)) != UC_ERR_OK) goto error; /* overlapping cases @@ -677,23 +675,23 @@ static bool split_region(uch handle, MemoryRegion *mr, uint64_t address, // allocation just failed so no guarantee that we can recover the original // allocation at this point if (l_size > 0) { - if (uc_mem_map(handle, begin, l_size, perms) != UC_ERR_OK) + if (uc_mem_map(uc, begin, l_size, perms) != UC_ERR_OK) goto error; - if (uc_mem_write(handle, begin, backup, l_size) != UC_ERR_OK) + if (uc_mem_write(uc, begin, backup, l_size) != UC_ERR_OK) goto error; } if (m_size > 0 && !do_delete) { - if (uc_mem_map(handle, address, m_size, perms) != UC_ERR_OK) + if (uc_mem_map(uc, address, m_size, perms) != UC_ERR_OK) goto error; - if (uc_mem_write(handle, address, backup + l_size, m_size) != UC_ERR_OK) + if (uc_mem_write(uc, address, backup + l_size, m_size) != UC_ERR_OK) goto error; } if (r_size > 0) { - if (uc_mem_map(handle, chunk_end, r_size, perms) != UC_ERR_OK) + if (uc_mem_map(uc, chunk_end, r_size, perms) != UC_ERR_OK) goto error; - if (uc_mem_write(handle, chunk_end, backup + l_size + m_size, r_size) != UC_ERR_OK) + if (uc_mem_write(uc, chunk_end, backup + l_size + m_size, r_size) != UC_ERR_OK) goto error; } @@ -705,17 +703,12 @@ error: } UNICORN_EXPORT -uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) +uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint32_t perms) { - struct uc_struct* uc = (struct uc_struct *)handle; MemoryRegion *mr; uint64_t addr = address; size_t count, len; - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - if (size == 0) // trivial case, no change return UC_ERR_OK; @@ -743,7 +736,7 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) while(count < size) { mr = memory_mapping(uc, addr); len = MIN(size - count, mr->end - addr); - if (!split_region(handle, mr, addr, len, false)) + if (!split_region(uc, mr, addr, len, false)) return UC_ERR_NOMEM; mr = memory_mapping(uc, addr); @@ -757,17 +750,12 @@ uc_err uc_mem_protect(uch handle, uint64_t address, size_t size, uint32_t perms) } UNICORN_EXPORT -uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) +uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) { MemoryRegion *mr; - struct uc_struct* uc = (struct uc_struct *)handle; uint64_t addr; size_t count, len; - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - if (size == 0) // nothing to unmap return UC_ERR_OK; @@ -791,7 +779,7 @@ uc_err uc_mem_unmap(uch handle, uint64_t address, size_t size) while(count < size) { mr = memory_mapping(uc, addr); len = MIN(size - count, mr->end - addr); - if (!split_region(handle, mr, addr, len, true)) + if (!split_region(uc, mr, addr, len, true)) return UC_ERR_NOMEM; // if we can retrieve the mapping, then no splitting took place // so unmap here From 99e34d212abc0a905abd64947ac46a4f445360e6 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Thu, 3 Sep 2015 22:34:58 -0400 Subject: [PATCH 60/64] bring python bindings up-to-date with new API --- bindings/python/unicorn/unicorn.py | 55 ++++++++++++++++-------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index ae672227..95f927dc 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -60,37 +60,41 @@ def _setup_prototype(lib, fname, restype, *argtypes): getattr(lib, fname).restype = restype getattr(lib, fname).argtypes = argtypes -_setup_prototype(_uc, "uc_version", ctypes.c_int, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) +ucerr = ctypes.c_int +ucengine = ctypes.c_void_p +uc_hook_h = ctypes.c_size_t + +_setup_prototype(_uc, "uc_version", ucerr, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) _setup_prototype(_uc, "uc_arch_supported", ctypes.c_bool, ctypes.c_int) -_setup_prototype(_uc, "uc_open", ctypes.c_int, ctypes.c_uint, ctypes.c_uint, ctypes.POINTER(ctypes.c_size_t)) -_setup_prototype(_uc, "uc_close", ctypes.c_int, ctypes.POINTER(ctypes.c_size_t)) -_setup_prototype(_uc, "uc_strerror", ctypes.c_char_p, ctypes.c_int) -_setup_prototype(_uc, "uc_errno", ctypes.c_int, ctypes.c_size_t) -_setup_prototype(_uc, "uc_reg_read", ctypes.c_int, ctypes.c_size_t, ctypes.c_int, ctypes.c_void_p) -_setup_prototype(_uc, "uc_reg_write", ctypes.c_int, ctypes.c_size_t, ctypes.c_int, ctypes.c_void_p) -_setup_prototype(_uc, "uc_mem_read", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t) -_setup_prototype(_uc, "uc_mem_write", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t) -_setup_prototype(_uc, "uc_emu_start", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_size_t) -_setup_prototype(_uc, "uc_emu_stop", ctypes.c_int, ctypes.c_size_t) -_setup_prototype(_uc, "uc_hook_del", ctypes.c_int, ctypes.c_size_t, ctypes.POINTER(ctypes.c_size_t)) -_setup_prototype(_uc, "uc_mem_map", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32) +_setup_prototype(_uc, "uc_open", ucerr, ctypes.c_uint, ctypes.c_uint, ctypes.POINTER(ucengine)) +_setup_prototype(_uc, "uc_close", ucerr, ucengine) +_setup_prototype(_uc, "uc_strerror", ctypes.c_char_p, ucerr) +_setup_prototype(_uc, "uc_errno", ucerr, ucengine) +_setup_prototype(_uc, "uc_reg_read", ucerr, ucengine, ctypes.c_int, ctypes.c_void_p) +_setup_prototype(_uc, "uc_reg_write", ucerr, ucengine, ctypes.c_int, ctypes.c_void_p) +_setup_prototype(_uc, "uc_mem_read", ucerr, ucengine, ctypes.c_uint64, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t) +_setup_prototype(_uc, "uc_mem_write", ucerr, ucengine, ctypes.c_uint64, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t) +_setup_prototype(_uc, "uc_emu_start", ucerr, ucengine, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_size_t) +_setup_prototype(_uc, "uc_emu_stop", ucerr, ucengine) +_setup_prototype(_uc, "uc_hook_del", ucerr, ucengine, uc_hook_h) +_setup_prototype(_uc, "uc_mem_map", ucerr, ucengine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32) # uc_hook_add is special due to variable number of arguments _uc.uc_hook_add = getattr(_uc, "uc_hook_add") _uc.uc_hook_add.restype = ctypes.c_int -UC_HOOK_CODE_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p) -UC_HOOK_MEM_INVALID_CB = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_size_t, ctypes.c_int, \ +UC_HOOK_CODE_CB = ctypes.CFUNCTYPE(None, ucengine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p) +UC_HOOK_MEM_INVALID_CB = ctypes.CFUNCTYPE(ctypes.c_bool, ucengine, ctypes.c_int, \ ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p) -UC_HOOK_MEM_ACCESS_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_int, \ +UC_HOOK_MEM_ACCESS_CB = ctypes.CFUNCTYPE(None, ucengine, ctypes.c_int, \ ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p) -UC_HOOK_INTR_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint32, \ +UC_HOOK_INTR_CB = ctypes.CFUNCTYPE(None, ucengine, ctypes.c_uint32, \ ctypes.c_void_p) -UC_HOOK_INSN_IN_CB = ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_size_t, ctypes.c_uint32, \ +UC_HOOK_INSN_IN_CB = ctypes.CFUNCTYPE(ctypes.c_uint32, ucengine, ctypes.c_uint32, \ ctypes.c_int, ctypes.c_void_p) -UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint32, \ +UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE(None, ucengine, ctypes.c_uint32, \ ctypes.c_int, ctypes.c_uint32, ctypes.c_void_p) -UC_HOOK_INSN_SYSCALL_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_void_p) +UC_HOOK_INSN_SYSCALL_CB = ctypes.CFUNCTYPE(None, ucengine, ctypes.c_void_p) # access to error code via @errno of UcError @@ -130,7 +134,7 @@ class Uc(object): raise UcError(UC_ERR_VERSION) self._arch, self._mode = arch, mode - self._uch = ctypes.c_size_t() + self._uch = ctypes.c_void_p() status = _uc.uc_open(arch, mode, ctypes.byref(self._uch)) if status != UC_ERR_OK: self._uch = None @@ -144,7 +148,8 @@ class Uc(object): def __del__(self): if self._uch: try: - status = _uc.uc_close(ctypes.byref(self._uch)) + status = _uc.uc_close(self._uch) + self._uch = None if status != UC_ERR_OK: raise UcError(status) except: # _uc might be pulled from under our feet @@ -251,7 +256,7 @@ class Uc(object): # add a hook def hook_add(self, htype, callback, user_data=None, arg1=1, arg2=0): - _h2 = ctypes.c_size_t() + _h2 = uc_hook_h() # save callback & user_data self._callback_count += 1 @@ -296,8 +301,8 @@ class Uc(object): # delete a hook def hook_del(self, h): - _h = ctypes.c_size_t(h) - status = _uc.uc_hook_del(self._uch, ctypes.byref(_h)) + _h = uc_hook_h(h) + status = _uc.uc_hook_del(self._uch, _h) if status != UC_ERR_OK: raise UcError(status) h = 0 From 5f32e2c1ae8162d08b1b8543a060753a04689367 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Thu, 3 Sep 2015 22:39:23 -0400 Subject: [PATCH 61/64] s/uc_hook_h/uchook/g --- hook.c | 2 +- include/hook.h | 2 +- include/unicorn/unicorn.h | 6 +++--- regress/block_test.c | 2 +- regress/nr_mem_test.c | 2 +- regress/rep_movsb.c | 2 +- regress/ro_mem_test.c | 2 +- regress/sigill.c | 2 +- regress/timeout_segfault.c | 4 ++-- samples/mem_exec.c | 2 +- samples/mem_protect.c | 2 +- samples/mem_unmap.c | 2 +- samples/sample_arm.c | 4 ++-- samples/sample_arm64.c | 2 +- samples/sample_m68k.c | 2 +- samples/sample_mips.c | 4 ++-- samples/sample_sparc.c | 2 +- samples/sample_x86.c | 16 ++++++++-------- samples/shellcode.c | 2 +- uc.c | 14 +++++++------- 20 files changed, 38 insertions(+), 38 deletions(-) diff --git a/hook.c b/hook.c index 850c9564..109a20d2 100644 --- a/hook.c +++ b/hook.c @@ -91,7 +91,7 @@ size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, vo } // return 0 on success, -1 on failure -uc_err hook_del(struct uc_struct *uc, uc_hook_h hh) +uc_err hook_del(struct uc_struct *uc, uchook hh) { if (hh == uc->hook_block_idx) { uc->hook_block_idx = 0; diff --git a/include/hook.h b/include/hook.h index 8c095b28..08e9e9b0 100644 --- a/include/hook.h +++ b/include/hook.h @@ -8,7 +8,7 @@ size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, void *callback, void *user_data); // return 0 on success, -1 on failure -uc_err hook_del(struct uc_struct *uc, uc_hook_h hh); +uc_err hook_del(struct uc_struct *uc, uchook hh); // return NULL on failure struct hook_struct *hook_find(struct uc_struct *uc, int type, uint64_t address); diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index f3b4c1f2..1aae5c11 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -22,7 +22,7 @@ extern "C" { struct uc_struct; typedef struct uc_struct ucengine; -typedef size_t uc_hook_h; +typedef size_t uchook; #include "m68k.h" #include "x86.h" @@ -375,7 +375,7 @@ uc_err uc_emu_stop(ucengine *uc); for detailed error). */ UNICORN_EXPORT -uc_err uc_hook_add(ucengine *uc, uc_hook_h *hh, uc_hook_t type, void *callback, void *user_data, ...); +uc_err uc_hook_add(ucengine *uc, uchook *hh, uc_hook_t type, void *callback, void *user_data, ...); /* Unregister (remove) a hook callback. @@ -390,7 +390,7 @@ uc_err uc_hook_add(ucengine *uc, uc_hook_h *hh, uc_hook_t type, void *callback, for detailed error). */ UNICORN_EXPORT -uc_err uc_hook_del(ucengine *uc, uc_hook_h hh); +uc_err uc_hook_del(ucengine *uc, uchook hh); typedef enum uc_prot { UC_PROT_NONE = 0, diff --git a/regress/block_test.c b/regress/block_test.c index 06a0fa21..7aaf1b93 100644 --- a/regress/block_test.c +++ b/regress/block_test.c @@ -62,7 +62,7 @@ int main() { } fprintf(stderr, "ok %d - uc_mem_write\n", count++); - uc_hook_h h1, h2; + uchook h1, h2; err = uc_hook_add(uc, &h1, UC_HOOK_BLOCK, cb_hookblock, NULL, (uint64_t)1, (uint64_t)0); if (err != UC_ERR_OK) { diff --git a/regress/nr_mem_test.c b/regress/nr_mem_test.c index 0e70829b..b804dd79 100644 --- a/regress/nr_mem_test.c +++ b/regress/nr_mem_test.c @@ -55,7 +55,7 @@ static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, int main(int argc, char **argv, char **envp) { ucengine *uc; - uc_hook_h trace1, trace2; + uchook trace1, trace2; uc_err err; uint32_t eax, ebx; diff --git a/regress/rep_movsb.c b/regress/rep_movsb.c index 97b00c15..0d91cbef 100644 --- a/regress/rep_movsb.c +++ b/regress/rep_movsb.c @@ -90,7 +90,7 @@ static void hook_mem_write(ucengine *uc, uc_mem_type type, int main(int argc, char **argv, char **envp) { ucengine *uc; - uc_hook_h trace1, trace2; + uchook trace1, trace2; uc_err err; uint8_t buf1[100], readbuf[100]; diff --git a/regress/ro_mem_test.c b/regress/ro_mem_test.c index 0c0390ff..49db748e 100644 --- a/regress/ro_mem_test.c +++ b/regress/ro_mem_test.c @@ -95,7 +95,7 @@ static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, int main(int argc, char **argv, char **envp) { ucengine *uc; - uc_hook_h trace1, trace2; + uchook trace1, trace2; uc_err err; uint8_t bytes[8]; uint32_t esp; diff --git a/regress/sigill.c b/regress/sigill.c index ad7af47f..b7317888 100644 --- a/regress/sigill.c +++ b/regress/sigill.c @@ -21,7 +21,7 @@ int main() int size; uint8_t *buf; ucengine *uc; - uc_hook_h uh_trap; + uchook uh_trap; uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc); if (err) { fprintf (stderr, "Cannot initialize unicorn\n"); diff --git a/regress/timeout_segfault.c b/regress/timeout_segfault.c index 2632a51f..73070978 100644 --- a/regress/timeout_segfault.c +++ b/regress/timeout_segfault.c @@ -38,7 +38,7 @@ static void test_arm(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2; + uchook trace1, trace2; int r0 = 0x1234; // R0 register int r2 = 0x6789; // R1 register @@ -94,7 +94,7 @@ static void test_thumb(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2; + uchook trace1, trace2; int sp = 0x1234; // R0 register diff --git a/samples/mem_exec.c b/samples/mem_exec.c index 075a5a4b..3b63012c 100644 --- a/samples/mem_exec.c +++ b/samples/mem_exec.c @@ -143,7 +143,7 @@ static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, int main(int argc, char **argv, char **envp) { ucengine *uc; - uc_hook_h trace1, trace2; + uchook trace1, trace2; uc_err err; uint32_t esp, eip; int32_t buf1[1024], buf2[1024], readbuf[1024]; diff --git a/samples/mem_protect.c b/samples/mem_protect.c index f1476593..dfabd0fb 100644 --- a/samples/mem_protect.c +++ b/samples/mem_protect.c @@ -161,7 +161,7 @@ static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, int main(int argc, char **argv, char **envp) { ucengine *uc; - uc_hook_h trace1, trace2; + uchook trace1, trace2; uc_err err; uint32_t addr, testval; int32_t buf1[1024], buf2[1024], readbuf[1024]; diff --git a/samples/mem_unmap.c b/samples/mem_unmap.c index 44866536..0bf61911 100644 --- a/samples/mem_unmap.c +++ b/samples/mem_unmap.c @@ -156,7 +156,7 @@ static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, int main(int argc, char **argv, char **envp) { ucengine *uc; - uc_hook_h trace1, trace2; + uchook trace1, trace2; uc_err err; uint32_t addr, testval; int32_t buf1[1024], buf2[1024], readbuf[1024]; diff --git a/samples/sample_arm.c b/samples/sample_arm.c index 38e8590a..81ec691b 100644 --- a/samples/sample_arm.c +++ b/samples/sample_arm.c @@ -29,7 +29,7 @@ static void test_arm(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2; + uchook trace1, trace2; int r0 = 0x1234; // R0 register int r2 = 0x6789; // R1 register @@ -85,7 +85,7 @@ static void test_thumb(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2; + uchook trace1, trace2; int sp = 0x1234; // R0 register diff --git a/samples/sample_arm64.c b/samples/sample_arm64.c index 61a58f20..3541b2f6 100644 --- a/samples/sample_arm64.c +++ b/samples/sample_arm64.c @@ -28,7 +28,7 @@ static void test_arm64(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2; + uchook trace1, trace2; int64_t x11 = 0x1234; // X11 register int64_t x13 = 0x6789; // X13 register diff --git a/samples/sample_m68k.c b/samples/sample_m68k.c index 049041cb..b8fef353 100644 --- a/samples/sample_m68k.c +++ b/samples/sample_m68k.c @@ -25,7 +25,7 @@ static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_ static void test_m68k(void) { ucengine *uc; - uc_hook_h trace1, trace2; + uchook trace1, trace2; uc_err err; int d0 = 0x0000; // d0 data register diff --git a/samples/sample_mips.c b/samples/sample_mips.c index 0806f60e..e604563c 100644 --- a/samples/sample_mips.c +++ b/samples/sample_mips.c @@ -29,7 +29,7 @@ static void test_mips_eb(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2; + uchook trace1, trace2; int r1 = 0x6789; // R1 register @@ -78,7 +78,7 @@ static void test_mips_el(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2; + uchook trace1, trace2; int r1 = 0x6789; // R1 register diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index ab9a9867..540b7d36 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -29,7 +29,7 @@ static void test_sparc(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2; + uchook trace1, trace2; int g1 = 0x1230; // G1 register int g2 = 0x6789; // G2 register diff --git a/samples/sample_x86.c b/samples/sample_x86.c index 9bdd8232..aecad6b5 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -171,7 +171,7 @@ static void test_i386(void) ucengine *uc; uc_err err; uint32_t tmp; - uc_hook_h trace1, trace2; + uchook trace1, trace2; int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register @@ -232,7 +232,7 @@ static void test_i386_jump(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2; + uchook trace1, trace2; printf("===================================\n"); printf("Emulate i386 code with jump\n"); @@ -328,7 +328,7 @@ static void test_i386_invalid_mem_read(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2; + uchook trace1, trace2; int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register @@ -385,7 +385,7 @@ static void test_i386_invalid_mem_write(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2, trace3; + uchook trace1, trace2, trace3; uint32_t tmp; int r_ecx = 0x1234; // ECX register @@ -457,7 +457,7 @@ static void test_i386_jump_invalid(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2; + uchook trace1, trace2; int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register @@ -513,7 +513,7 @@ static void test_i386_inout(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2, trace3, trace4; + uchook trace1, trace2, trace3, trace4; int r_eax = 0x1234; // EAX register int r_ecx = 0x6789; // ECX register @@ -574,7 +574,7 @@ static void test_x86_64(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2, trace3, trace4; + uchook trace1, trace2, trace3, trace4; int64_t rax = 0x71f3029efd49d41d; int64_t rbx = 0xd87b45277f133ddb; @@ -689,7 +689,7 @@ static void test_x86_64(void) static void test_x86_64_syscall(void) { ucengine *uc; - uc_hook_h trace1; + uchook trace1; uc_err err; int64_t rax = 0x100; diff --git a/samples/shellcode.c b/samples/shellcode.c index f185db97..31f72ffc 100644 --- a/samples/shellcode.c +++ b/samples/shellcode.c @@ -90,7 +90,7 @@ static void test_i386(void) { ucengine *uc; uc_err err; - uc_hook_h trace1, trace2; + uchook trace1, trace2; int r_esp = ADDRESS + 0x200000; // ESP register diff --git a/uc.c b/uc.c index 6001e61f..210616bf 100644 --- a/uc.c +++ b/uc.c @@ -521,7 +521,7 @@ uc_err uc_emu_stop(ucengine *uc) static int _hook_code(ucengine *uc, int type, uint64_t begin, uint64_t end, - void *callback, void *user_data, uc_hook_h *hh) + void *callback, void *user_data, uchook *hh) { int i; @@ -537,7 +537,7 @@ static int _hook_code(ucengine *uc, int type, uint64_t begin, uint64_t end, static uc_err _hook_mem_access(ucengine *uc, uc_hook_t type, uint64_t begin, uint64_t end, - void *callback, void *user_data, uc_hook_h *hh) + void *callback, void *user_data, uchook *hh) { int i; @@ -806,7 +806,7 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) } static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_eventmem_t callback, - void *user_data, uc_hook_h *evh) + void *user_data, uchook *evh) { size_t i; @@ -825,7 +825,7 @@ static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_eventmem_t callback, static uc_err _hook_intr(struct uc_struct* uc, void *callback, - void *user_data, uc_hook_h *evh) + void *user_data, uchook *evh) { size_t i; @@ -844,7 +844,7 @@ static uc_err _hook_intr(struct uc_struct* uc, void *callback, static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callback, - void *user_data, uc_hook_h *evh) + void *user_data, uchook *evh) { size_t i; @@ -895,7 +895,7 @@ static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callb } UNICORN_EXPORT -uc_err uc_hook_add(ucengine *uc, uc_hook_h *hh, uc_hook_t type, void *callback, void *user_data, ...) +uc_err uc_hook_add(ucengine *uc, uchook *hh, uc_hook_t type, void *callback, void *user_data, ...) { va_list valist; int ret = UC_ERR_OK; @@ -951,7 +951,7 @@ uc_err uc_hook_add(ucengine *uc, uc_hook_h *hh, uc_hook_t type, void *callback, } UNICORN_EXPORT -uc_err uc_hook_del(ucengine *uc, uc_hook_h hh) +uc_err uc_hook_del(ucengine *uc, uchook hh) { return hook_del(uc, hh); } From 291ec9867542d7963b40b0efe341dedb38d7eb7b Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Thu, 3 Sep 2015 22:46:43 -0400 Subject: [PATCH 62/64] python: fix a couple more function signatures --- bindings/python/unicorn/unicorn.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 95f927dc..ef3c03a3 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -64,7 +64,7 @@ ucerr = ctypes.c_int ucengine = ctypes.c_void_p uc_hook_h = ctypes.c_size_t -_setup_prototype(_uc, "uc_version", ucerr, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) +_setup_prototype(_uc, "uc_version", ctypes.c_uint, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) _setup_prototype(_uc, "uc_arch_supported", ctypes.c_bool, ctypes.c_int) _setup_prototype(_uc, "uc_open", ucerr, ctypes.c_uint, ctypes.c_uint, ctypes.POINTER(ucengine)) _setup_prototype(_uc, "uc_close", ucerr, ucengine) @@ -81,7 +81,7 @@ _setup_prototype(_uc, "uc_mem_map", ucerr, ucengine, ctypes.c_uint64, ctypes.c_s # uc_hook_add is special due to variable number of arguments _uc.uc_hook_add = getattr(_uc, "uc_hook_add") -_uc.uc_hook_add.restype = ctypes.c_int +_uc.uc_hook_add.restype = ucerr UC_HOOK_CODE_CB = ctypes.CFUNCTYPE(None, ucengine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p) UC_HOOK_MEM_INVALID_CB = ctypes.CFUNCTYPE(ctypes.c_bool, ucengine, ctypes.c_int, \ From 7ceb2eb0b997a6538f8286a28ea61007dfdbb0ef Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 4 Sep 2015 10:54:21 +0800 Subject: [PATCH 63/64] bindings: update constants after the recent changes in the core --- bindings/go/unicorn/unicorn_const.go | 25 ++++++++++++------------ bindings/python/unicorn/unicorn_const.py | 25 ++++++++++++------------ 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index e5ab6863..04c52639 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -37,19 +37,18 @@ const ( UC_ERR_NOMEM = 1 UC_ERR_ARCH = 2 UC_ERR_HANDLE = 3 - UC_ERR_UCH = 4 - UC_ERR_MODE = 5 - UC_ERR_VERSION = 6 - UC_ERR_MEM_READ = 7 - UC_ERR_MEM_WRITE = 8 - UC_ERR_CODE_INVALID = 9 - UC_ERR_HOOK = 10 - UC_ERR_INSN_INVALID = 11 - UC_ERR_MAP = 12 - UC_ERR_WRITE_PROT = 13 - UC_ERR_READ_PROT = 14 - UC_ERR_EXEC_PROT = 15 - UC_ERR_INVAL = 16 + UC_ERR_MODE = 4 + UC_ERR_VERSION = 5 + UC_ERR_MEM_READ = 6 + UC_ERR_MEM_WRITE = 7 + UC_ERR_CODE_INVALID = 8 + UC_ERR_HOOK = 9 + UC_ERR_INSN_INVALID = 10 + UC_ERR_MAP = 11 + UC_ERR_WRITE_PROT = 12 + UC_ERR_READ_PROT = 13 + UC_ERR_EXEC_PROT = 14 + UC_ERR_INVAL = 15 UC_MEM_READ = 16 UC_MEM_WRITE = 17 UC_MEM_READ_WRITE = 18 diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index 0f2bf718..0d667784 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -35,19 +35,18 @@ UC_ERR_OK = 0 UC_ERR_NOMEM = 1 UC_ERR_ARCH = 2 UC_ERR_HANDLE = 3 -UC_ERR_UCH = 4 -UC_ERR_MODE = 5 -UC_ERR_VERSION = 6 -UC_ERR_MEM_READ = 7 -UC_ERR_MEM_WRITE = 8 -UC_ERR_CODE_INVALID = 9 -UC_ERR_HOOK = 10 -UC_ERR_INSN_INVALID = 11 -UC_ERR_MAP = 12 -UC_ERR_WRITE_PROT = 13 -UC_ERR_READ_PROT = 14 -UC_ERR_EXEC_PROT = 15 -UC_ERR_INVAL = 16 +UC_ERR_MODE = 4 +UC_ERR_VERSION = 5 +UC_ERR_MEM_READ = 6 +UC_ERR_MEM_WRITE = 7 +UC_ERR_CODE_INVALID = 8 +UC_ERR_HOOK = 9 +UC_ERR_INSN_INVALID = 10 +UC_ERR_MAP = 11 +UC_ERR_WRITE_PROT = 12 +UC_ERR_READ_PROT = 13 +UC_ERR_EXEC_PROT = 14 +UC_ERR_INVAL = 15 UC_MEM_READ = 16 UC_MEM_WRITE = 17 UC_MEM_READ_WRITE = 18 From 2cdadf1720628d62d7c2c5f857ca90b335a908e6 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 4 Sep 2015 11:04:13 +0800 Subject: [PATCH 64/64] regress: fix nr_mem_test.c and ro_mem_test.c to use modified UC_MEM_* enum --- regress/nr_mem_test.c | 2 +- regress/ro_mem_test.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/regress/nr_mem_test.c b/regress/nr_mem_test.c index b804dd79..4aa6db9c 100644 --- a/regress/nr_mem_test.c +++ b/regress/nr_mem_test.c @@ -44,7 +44,7 @@ static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, default: // return false to indicate we want to stop emulation return false; - case UC_MEM_READ_NR: + case UC_MEM_READ_PROT: printf(">>> non-readable memory is being read at 0x%"PRIx64 ", data size = %u\n", address, size); return false; diff --git a/regress/ro_mem_test.c b/regress/ro_mem_test.c index 49db748e..330e3c49 100644 --- a/regress/ro_mem_test.c +++ b/regress/ro_mem_test.c @@ -81,7 +81,7 @@ static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, printf(">>> Missing memory is being WRITTEN at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", address, size, value); return false; - case UC_MEM_WRITE_NW: + case UC_MEM_WRITE_PROT: printf(">>> RO memory is being WRITTEN at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", address, size, value); return false;