diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 62effcc3..bd9a5c55 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -61,6 +61,9 @@ const ( UC_HOOK_MEM_READ = 37 UC_HOOK_MEM_WRITE = 38 UC_HOOK_MEM_READ_WRITE = 39 + + UC_PROT_NONE = 0 UC_PROT_READ = 1 UC_PROT_WRITE = 2 + UC_PROT_ALL = 3 ) \ No newline at end of file diff --git a/bindings/java/unicorn/Unicorn.java b/bindings/java/unicorn/Unicorn.java index fa985541..06e1e9d6 100644 --- a/bindings/java/unicorn/Unicorn.java +++ b/bindings/java/unicorn/Unicorn.java @@ -624,7 +624,7 @@ public class Unicorn implements UnicornArchs, UnicornModes, UnicornHooks, * @param address Base address of the memory range * @param size Size of the memory block. */ - public native void mem_map(long address, long size) throws UnicornException; + public native void mem_map(long address, long size, int perms) throws UnicornException; } diff --git a/bindings/java/unicorn_Unicorn.c b/bindings/java/unicorn_Unicorn.c index aa141bb2..cd0428f9 100644 --- a/bindings/java/unicorn_Unicorn.c +++ b/bindings/java/unicorn_Unicorn.c @@ -502,13 +502,13 @@ JNIEXPORT void JNICALL Java_unicorn_Unicorn_hook_1del /* * Class: unicorn_Unicorn * Method: mem_map - * Signature: (JJ)V + * Signature: (JJI)V */ JNIEXPORT void JNICALL Java_unicorn_Unicorn_mem_1map - (JNIEnv *env, jobject self, jlong address, jlong size) { + (JNIEnv *env, jobject self, jlong address, jlong size, jint perms) { uch handle = getHandle(env, self); - uc_err err = uc_mem_map(handle, (uint64_t)address, (size_t)size); + uc_err err = uc_mem_map(handle, (uint64_t)address, (size_t)size, (uint32_t)perms); if (err != UC_ERR_OK) { throwException(env, err); } diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index e207cd91..ae672227 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -73,7 +73,7 @@ _setup_prototype(_uc, "uc_mem_write", ctypes.c_int, ctypes.c_size_t, ctypes.c_ui _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) +_setup_prototype(_uc, "uc_mem_map", ctypes.c_int, ctypes.c_size_t, 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") @@ -201,8 +201,8 @@ class Uc(object): # map a range of memory - def mem_map(self, address, size): - status = _uc.uc_mem_map(self._uch, address, size) + def mem_map(self, address, size, perms=UC_PROT_ALL): + status = _uc.uc_mem_map(self._uch, address, size, perms) if status != UC_ERR_OK: raise UcError(status) diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index bbcff20c..ad07f46b 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -59,5 +59,8 @@ UC_HOOK_MEM_INVALID = 36 UC_HOOK_MEM_READ = 37 UC_HOOK_MEM_WRITE = 38 UC_HOOK_MEM_READ_WRITE = 39 + +UC_PROT_NONE = 0 UC_PROT_READ = 1 UC_PROT_WRITE = 2 +UC_PROT_ALL = 3 diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index ce887aa3..5e3d1d57 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -390,9 +390,11 @@ UNICORN_EXPORT uc_err uc_hook_del(uch handle, uch *h2); typedef enum uc_prot { + UC_PROT_NONE = 0, UC_PROT_READ = 1, UC_PROT_WRITE = 2, UC_PROT_EXEC = 4, + UC_PROT_ALL = 7, } uc_prot; /* @@ -400,22 +402,6 @@ typedef enum uc_prot { 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. - @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. - @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. - - @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); - -/* - Map memory in for emulation. - 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. This address must be aligned to 4KB, or this will return with UC_ERR_MAP error. @@ -429,7 +415,7 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size); for detailed error). */ UNICORN_EXPORT -uc_err uc_mem_map_ex(uch handle, uint64_t address, size_t size, uint32_t perms); +uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms); /* Set memory permissions for emulation memory. diff --git a/qemu/header_gen.py b/qemu/header_gen.py old mode 100755 new mode 100644 diff --git a/qemu/scripts/make_device_config.sh b/qemu/scripts/make_device_config.sh old mode 100644 new mode 100755 diff --git a/regress/block_test.c b/regress/block_test.c index cc372fed..3788f6f4 100644 --- a/regress/block_test.c +++ b/regress/block_test.c @@ -39,7 +39,7 @@ int main() { } fprintf(stderr, "ok %d - uc_open\n", count++); - err = uc_mem_map(u, 0x1000000, 4096); + err = uc_mem_map(u, 0x1000000, 4096, UC_PROT_ALL); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); diff --git a/regress/map_crash.c b/regress/map_crash.c index ca16b56b..54bcfacc 100644 --- a/regress/map_crash.c +++ b/regress/map_crash.c @@ -23,7 +23,7 @@ int main() return 1; } memset (buf, 0, size); - if (!uc_mem_map (uh, UC_BUG_WRITE_ADDR, size)) { + if (!uc_mem_map (uh, UC_BUG_WRITE_ADDR, size, UC_PROT_ALL)) { uc_mem_write (uh, UC_BUG_WRITE_ADDR, buf, size); } uc_close (&uh); diff --git a/regress/map_write.c b/regress/map_write.c index fc4343c5..e5b94366 100644 --- a/regress/map_write.c +++ b/regress/map_write.c @@ -18,7 +18,7 @@ int main() printf ("uc_open %d\n", err); return 1; } - err = uc_mem_map (uh, ADDR, SIZE); + err = uc_mem_map (uh, ADDR, SIZE, UC_PROT_ALL); if (err) { printf ("uc_mem_map %d\n", err); return 1; diff --git a/regress/memmap_segfault2.py b/regress/memmap_segfault2.py index 1c077ac6..bd3845b7 100755 --- a/regress/memmap_segfault2.py +++ b/regress/memmap_segfault2.py @@ -5,4 +5,4 @@ uc = Uc(UC_ARCH_X86, UC_MODE_32) uc.mem_map(0x0000, 0x2000) uc.mem_map(0x2000, 0x4000) uc.mem_write(0x1000, 0x1004 * ' ') -print 'Not reached on x86_64 Linux.' +print 'If not reached, then we have BUG (crash on x86_64 Linux).' diff --git a/regress/nr_mem_test.c b/regress/nr_mem_test.c old mode 100755 new mode 100644 index 546173c7..37c344de --- a/regress/nr_mem_test.c +++ b/regress/nr_mem_test.c @@ -67,9 +67,9 @@ int main(int argc, char **argv, char **envp) return 1; } - uc_mem_map_ex(handle, 0x100000, 0x1000, UC_PROT_READ); - uc_mem_map_ex(handle, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); - uc_mem_map_ex(handle, 0x400000, 0x1000, UC_PROT_WRITE); + uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_READ); + uc_mem_map(handle, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(handle, 0x400000, 0x1000, UC_PROT_WRITE); // write machine code to be emulated to memory if (uc_mem_write(handle, 0x100000, PROGRAM, sizeof(PROGRAM))) { diff --git a/regress/ro_mem_test.c b/regress/ro_mem_test.c old mode 100755 new mode 100644 index 19d66bf3..52534cd4 --- a/regress/ro_mem_test.c +++ b/regress/ro_mem_test.c @@ -74,7 +74,7 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, upper = (esp + 0xfff) & ~0xfff; printf(">>> Stack appears to be missing at 0x%"PRIx64 ", allocating now\n", address); // map this memory in with 2MB in size - uc_mem_map_ex(handle, upper - 0x8000, 0x8000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(handle, upper - 0x8000, 0x8000, UC_PROT_READ | UC_PROT_WRITE); // return true to indicate we want to continue return true; } @@ -114,14 +114,14 @@ int main(int argc, char **argv, char **envp) return 1; } - uc_mem_map(handle, 0x100000, 0x1000); - uc_mem_map(handle, 0x200000, 0x2000); - uc_mem_map(handle, 0x300000, 0x3000); - uc_mem_map_ex(handle, 0x400000, 0x4000, UC_PROT_READ); + uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_ALL); + uc_mem_map(handle, 0x200000, 0x2000, UC_PROT_ALL); + uc_mem_map(handle, 0x300000, 0x3000, UC_PROT_ALL); + uc_mem_map(handle, 0x400000, 0x4000, UC_PROT_READ); if (map_stack) { printf("Pre-mapping stack\n"); - uc_mem_map_ex(handle, STACK, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(handle, STACK, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE); } else { printf("Mapping stack on first invalid memory access\n"); } diff --git a/regress/sigill.c b/regress/sigill.c index 415a2313..c8b5517a 100644 --- a/regress/sigill.c +++ b/regress/sigill.c @@ -34,7 +34,7 @@ int main() return 1; } memset (buf, 0, size); - if (!uc_mem_map (uh, UC_BUG_WRITE_ADDR, size)) { + if (!uc_mem_map (uh, UC_BUG_WRITE_ADDR, size, UC_PROT_ALL)) { uc_mem_write (uh, UC_BUG_WRITE_ADDR, (const uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff", 8); } diff --git a/regress/sigill2.c b/regress/sigill2.c index ca13282a..a2a2d4f1 100644 --- a/regress/sigill2.c +++ b/regress/sigill2.c @@ -18,7 +18,7 @@ int main() return 1; } size = UC_BUG_WRITE_SIZE; - if (!uc_mem_map (uh, UC_BUG_WRITE_ADDR, size)) { + if (!uc_mem_map (uh, UC_BUG_WRITE_ADDR, size, UC_PROT_ALL)) { uc_mem_write (uh, UC_BUG_WRITE_ADDR, (const uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff", 8); } diff --git a/samples/sample_arm.c b/samples/sample_arm.c index cb5cc6b3..173e8167 100644 --- a/samples/sample_arm.c +++ b/samples/sample_arm.c @@ -47,7 +47,7 @@ static void test_arm(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory uc_mem_write(handle, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1); @@ -100,7 +100,7 @@ static void test_thumb(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory uc_mem_write(handle, ADDRESS, (uint8_t *)THUMB_CODE, sizeof(THUMB_CODE) - 1); diff --git a/samples/sample_arm64.c b/samples/sample_arm64.c index f1c5ffbc..b0d1608a 100644 --- a/samples/sample_arm64.c +++ b/samples/sample_arm64.c @@ -45,7 +45,7 @@ static void test_arm64(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory uc_mem_write(handle, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1); diff --git a/samples/sample_m68k.c b/samples/sample_m68k.c index 02452e5d..82b06eb6 100644 --- a/samples/sample_m68k.c +++ b/samples/sample_m68k.c @@ -60,7 +60,7 @@ static void test_m68k(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory uc_mem_write(handle, ADDRESS, (uint8_t *)M68K_CODE, sizeof(M68K_CODE) - 1); diff --git a/samples/sample_mips.c b/samples/sample_mips.c index 43d0682e..c9d00216 100644 --- a/samples/sample_mips.c +++ b/samples/sample_mips.c @@ -44,7 +44,7 @@ static void test_mips_eb(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory uc_mem_write(handle, ADDRESS, (uint8_t *)MIPS_CODE_EB, sizeof(MIPS_CODE_EB) - 1); @@ -94,7 +94,7 @@ static void test_mips_el(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory uc_mem_write(handle, ADDRESS, (uint8_t *)MIPS_CODE_EL, sizeof(MIPS_CODE_EL) - 1); diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index 52bb373d..c7f2971a 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -46,7 +46,7 @@ static void test_sparc(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory uc_mem_write(handle, ADDRESS, (uint8_t *)SPARC_CODE, sizeof(SPARC_CODE) - 1); diff --git a/samples/sample_x86.c b/samples/sample_x86.c index 32c2ce92..9133dc3a 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -77,7 +77,7 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, printf(">>> Missing memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", address, size, value); // map this memory in with 2MB in size - uc_mem_map(handle, 0xaaaa0000, 2 * 1024*1024); + uc_mem_map(handle, 0xaaaa0000, 2 * 1024*1024, UC_PROT_ALL); // return true to indicate we want to continue return true; } @@ -186,7 +186,7 @@ static void test_i386(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32, sizeof(X86_CODE32) - 1)) { @@ -245,7 +245,7 @@ static void test_i386_jump(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_JUMP, @@ -292,7 +292,7 @@ static void test_i386_loop(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_LOOP, sizeof(X86_CODE32_LOOP) - 1)) { @@ -344,7 +344,7 @@ static void test_i386_invalid_mem_read(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_MEM_READ, sizeof(X86_CODE32_MEM_READ) - 1)) { @@ -402,7 +402,7 @@ static void test_i386_invalid_mem_write(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_MEM_WRITE, sizeof(X86_CODE32_MEM_WRITE) - 1)) { @@ -473,7 +473,7 @@ static void test_i386_jump_invalid(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_JMP_INVALID, sizeof(X86_CODE32_JMP_INVALID) - 1)) { @@ -530,7 +530,7 @@ static void test_i386_inout(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_INOUT, sizeof(X86_CODE32_INOUT) - 1)) { @@ -605,7 +605,7 @@ static void test_x86_64(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE64, sizeof(X86_CODE64) - 1)) { @@ -706,7 +706,7 @@ static void test_x86_64_syscall(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE64_SYSCALL, sizeof(X86_CODE64_SYSCALL) - 1)) { @@ -758,7 +758,7 @@ static void test_x86_16(void) } // map 8KB memory for this emulation - uc_mem_map(handle, 0, 8 * 1024); + uc_mem_map(handle, 0, 8 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory if (uc_mem_write(handle, 0, (uint8_t *)X86_CODE16, sizeof(X86_CODE64) - 1)) { diff --git a/samples/shellcode.c b/samples/shellcode.c index 51dfb481..36c71ab4 100644 --- a/samples/shellcode.c +++ b/samples/shellcode.c @@ -104,7 +104,7 @@ static void test_i386(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024); + uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_SELF, sizeof(X86_CODE32_SELF) - 1)) { diff --git a/uc.c b/uc.c index cf4aeaff..3c46e689 100644 --- a/uc.c +++ b/uc.c @@ -340,6 +340,26 @@ uc_err uc_reg_write(uch handle, int regid, const void *value) } +// check if a memory area is mapped +// this is complicated because an area can overlap adjacent blocks +static bool check_mem_area(struct uc_struct *uc, uint64_t address, size_t size) +{ + size_t count = 0, len; + + while(count < size) { + MemoryRegion *mr = memory_mapping(uc, address); + if (mr) { + len = MIN(size - count, mr->end - address); + count += len; + address += len; + } else // this address is not mapped in yet + break; + } + + return (count == size); +} + + UNICORN_EXPORT uc_err uc_mem_read(uch handle, uint64_t address, uint8_t *bytes, size_t size) { @@ -349,39 +369,73 @@ uc_err uc_mem_read(uch handle, uint64_t address, uint8_t *bytes, size_t size) // invalid handle return UC_ERR_UCH; - if (uc->read_mem(&uc->as, address, bytes, size) == false) + if (!check_mem_area(uc, address, size)) return UC_ERR_MEM_READ; - return UC_ERR_OK; + size_t count = 0, len; + + // memory area can overlap adjacent memory blocks + while(count < size) { + MemoryRegion *mr = memory_mapping(uc, address); + if (mr) { + len = MIN(size - count, mr->end - address); + if (uc->read_mem(&uc->as, address, bytes, len) == false) + break; + count += len; + address += len; + bytes += len; + } else // this address is not mapped in yet + break; + } + + if (count == size) + return UC_ERR_OK; + else + return UC_ERR_MEM_READ; } UNICORN_EXPORT uc_err uc_mem_write(uch handle, uint64_t address, const uint8_t *bytes, size_t size) { struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle; - uint32_t operms; if (handle == 0) // invalid handle return UC_ERR_UCH; - MemoryRegion *mr = memory_mapping(uc, address); - if (mr == NULL) + if (!check_mem_area(uc, address, size)) return UC_ERR_MEM_WRITE; - operms = mr->perms; - if (!(operms & UC_PROT_WRITE)) //write protected - //but this is not the program accessing memory, so temporarily mark writable - uc->readonly_mem(mr, false); + size_t count = 0, len; - if (uc->write_mem(&uc->as, address, bytes, size) == false) + // memory area can overlap adjacent memory blocks + while(count < size) { + MemoryRegion *mr = memory_mapping(uc, address); + if (mr) { + uint32_t operms = mr->perms; + if (!(operms & UC_PROT_WRITE)) // write protected + // but this is not the program accessing memory, so temporarily mark writable + uc->readonly_mem(mr, false); + + len = MIN(size - count, mr->end - address); + if (uc->write_mem(&uc->as, address, bytes, len) == false) + break; + + if (!(operms & UC_PROT_WRITE)) // write protected + // now write protect it again + uc->readonly_mem(mr, true); + + count += len; + address += len; + bytes += len; + } else // this address is not mapped in yet + break; + } + + if (count == size) + return UC_ERR_OK; + else return UC_ERR_MEM_WRITE; - - if (!(operms & UC_PROT_WRITE)) //write protected - //now write protect it again - uc->readonly_mem(mr, true); - - return UC_ERR_OK; } #define TIMEOUT_STEP 2 // microseconds @@ -550,7 +604,7 @@ static uc_err _hook_mem_access(uch handle, uc_mem_type type, } UNICORN_EXPORT -uc_err uc_mem_map_ex(uch handle, uint64_t address, size_t size, uint32_t perms) +uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms) { MemoryRegion **regions; struct uc_struct* uc = (struct uc_struct *)handle; @@ -588,13 +642,6 @@ uc_err uc_mem_map_ex(uch handle, uint64_t address, size_t size, uint32_t perms) return UC_ERR_OK; } -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 | UC_PROT_EXEC); -} - UNICORN_EXPORT uc_err uc_mem_protect(uch handle, uint64_t start, size_t block_size, uint32_t perms) {