From 9e4e96ff47b540583a9869ad54b794316698985a Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Sun, 30 Aug 2015 19:50:18 -0700 Subject: [PATCH] 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++);