From 7f63d76908c810d6501e84a988418dbedf96fdba Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Fri, 28 Aug 2015 12:58:53 -0700 Subject: [PATCH 01/24] 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 02/24] 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 03/24] 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 04/24] 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 05/24] 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 06/24] 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 07/24] 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 08/24] 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 09/24] 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 10/24] 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 11/24] 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 12/24] 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 2c4f3769d443969be07556c27f394d84fc9e2bb6 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Tue, 1 Sep 2015 12:10:09 -0700 Subject: [PATCH 13/24] 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 14/24] 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 46cc510dfe95c87c63cfdad222b4121e813bdf80 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Sep 2015 18:02:25 +0800 Subject: [PATCH 15/24] 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 16/24] 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 17/24] 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 18/24] 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 19/24] 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 20/24] 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 21/24] 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 22/24] 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 23/24] 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 24/24] 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); }