// callback for tracing invalid memory access (READ or WRITE) static bool hook_mem_invalid(uc_engine *uc, 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 - memory invalid type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); return false; case UC_MEM_WRITE_UNMAPPED: printf("# write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); if (uc_mem_read(uc, addr, &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(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++); } return true; } }
/** * A basic test showing mapping of memory, and reading/writing it */ static void test_basic(void **state) { uc_engine *uc = *state; const uint64_t mem_start = 0x1000; const uint64_t mem_len = 0x1000; const uint64_t test_addr = mem_start + 0x100; /* Map a region */ uc_assert_success(uc_mem_map(uc, mem_start, mem_len, UC_PROT_NONE)); /* Write some data to it */ uc_assert_success(uc_mem_write(uc, test_addr, "test", 4)); uint8_t buf[4]; memset(buf, 0xCC, sizeof(buf)); /* Read it back */ uc_assert_success(uc_mem_read(uc, test_addr, buf, sizeof(buf))); /* And make sure it matches what we expect */ assert_memory_equal(buf, "test", 4); /* Unmap the region */ //uc_assert_success(uc_mem_unmap(uc, mem_start, mem_len)); }
void perform_read_step(uc_engine *uc){ char buff[4096*4]; uint64_t addr = get_addr(); uint64_t len = get_len()%(4096*4); printf("read(uc,0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step); uc_mem_read(uc, addr, buff, len); }
// callback for tracing instruction static void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_data) { uint8_t opcode; uint32_t testval; 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(uc, 0x200000 + test_num * 0x100000, &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(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++); } test_num++; break; case 0xf4: //hlt printf("# Handling HLT\n"); 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 { printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++); } break; default: //all others printf("# Handling OTHER\n"); break; } }
static void test_x86_16(void) { uc_engine *uc; uc_err err; uint8_t tmp; int32_t eax = 7; int32_t ebx = 5; int32_t esi = 6; printf("Emulate x86 16-bit code\n"); // Initialize emulator in X86-16bit mode err = uc_open(UC_ARCH_X86, UC_MODE_16, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return; } // map 8KB memory for this emulation uc_mem_map(uc, 0, 8 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory if (uc_mem_write(uc, 0, X86_CODE16, sizeof(X86_CODE16) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers uc_reg_write(uc, UC_X86_REG_EAX, &eax); uc_reg_write(uc, UC_X86_REG_EBX, &ebx); uc_reg_write(uc, UC_X86_REG_ESI, &esi); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. err = uc_emu_start(uc, 0, sizeof(X86_CODE16) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); } // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); // read from memory if (!uc_mem_read(uc, 11, &tmp, 1)) printf(">>> Read 1 bytes from [0x%x] = 0x%x\n", 11, tmp); else printf(">>> Failed to read 1 bytes from [0x%x]\n", 11); uc_close(uc); }
// Create a backup copy of the indicated MemoryRegion. // Generally used in prepartion for splitting a MemoryRegion. 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(uc, mr->addr, block, int128_get64(mr->size)); if (err != UC_ERR_OK) { free(block); block = NULL; } } return block; }
static void test_bad_read(void **state) { uc_engine *uc = *state; uint8_t readbuf[0x10]; memset(readbuf, 0xCC, sizeof(readbuf)); uint8_t checkbuf[0x10]; memset(checkbuf, 0xCC, sizeof(checkbuf)); /* Reads to unmapped addresses should fail */ /* TODO: Which error? */ uc_assert_fail(uc_mem_read(uc, 0x1000, readbuf, sizeof(readbuf))); /* And our buffer should be unchanged */ assert_memory_equal(readbuf, checkbuf, sizeof(checkbuf)); }
static void dump_stack_mem(uc_engine *uc) { uint8_t tmp[256]; uint32_t size; size = sizeof(X86_CODE32_ALPHA_MIXED); if (size > 255) size = 255; if (!uc_mem_read(uc, PHY_STACK_REGION, tmp, size)) { uint32_t i; printf("Stack region dump"); for (i=0; i<size; i++) { if ((i % 16) == 0) printf("\n%x: ", PHY_STACK_REGION+i); printf("%x ", tmp[i]); } printf("\n"); } }
static void test_x86_16(void **state) { uc_engine *uc; uc_err err; uint8_t tmp; static const uint64_t address = 0; static const uint8_t code[] = { 0x00, 0x00, // add byte ptr [bx + si], al }; int32_t eax = 7; int32_t ebx = 5; int32_t esi = 6; // Initialize emulator in X86-16bit mode err = uc_open(UC_ARCH_X86, UC_MODE_16, &uc); uc_assert_success(err); // map 8KB memory for this emulation err = uc_mem_map(uc, address, 8 * 1024, UC_PROT_ALL); uc_assert_success(err); // write machine code to be emulated to memory err = uc_mem_write(uc, address, code, sizeof(code)); uc_assert_success(err); // initialize machine registers uc_assert_success(uc_reg_write(uc, UC_X86_REG_EAX, &eax)); uc_assert_success(uc_reg_write(uc, UC_X86_REG_EBX, &ebx)); uc_assert_success(uc_reg_write(uc, UC_X86_REG_ESI, &esi)); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. err = uc_emu_start(uc, address, address+sizeof(code), 0, 0); uc_assert_success(err); // read from memory uc_assert_success(uc_mem_read(uc, 11, &tmp, 1)); assert_int_equal(7, tmp); uc_assert_success(uc_close(uc)); }
/** * Verify that we can read/write across memory map region boundaries */ static void test_rw_across_boundaries(void **state) { uc_engine *uc = *state; /* Map in two adjacent regions */ uc_assert_success(uc_mem_map(uc, 0, 0x1000, 0)); /* 0x0000 - 0x1000 */ uc_assert_success(uc_mem_map(uc, 0x1000, 0x1000, 0)); /* 0x1000 - 0x2000 */ const uint64_t addr = 0x1000 - 2; /* 2 bytes before end of block */ /* Write some data across the boundary */ uc_assert_success(uc_mem_write(uc, addr, "test", 4)); uint8_t buf[4]; memset(buf, 0xCC, sizeof(buf)); /* Read the data across the boundary */ uc_assert_success(uc_mem_read(uc, addr, buf, sizeof(buf))); assert_memory_equal(buf, "test", 4); }
// callback for tracing instructions, detect HLT and terminate emulation static void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_data) { uint8_t opcode; unsigned char buf[256]; insts_executed++; if (uc_mem_read(uc, addr, buf, size) != UC_ERR_OK) { printf("not ok - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", addr); if (uc_emu_stop(uc) != UC_ERR_OK) { printf("not ok - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", addr); _exit(-1); } } opcode = buf[0]; switch (opcode) { case 0x41: // inc ecx if (uc_mem_protect(uc, 0x101000, 0x1000, UC_PROT_READ) != UC_ERR_OK) { printf("not ok - uc_mem_protect fail during hook_code callback, addr: 0x%" PRIx64 "\n", addr); _exit(-1); } break; case 0x42: // inc edx if (uc_mem_unmap(uc, 0x101000, 0x1000) != UC_ERR_OK) { printf("not ok - uc_mem_unmap fail during hook_code callback, addr: 0x%" PRIx64 "\n", addr); _exit(-1); } break; case 0xf4: // hlt if (uc_emu_stop(uc) != UC_ERR_OK) { printf("not ok - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", addr); _exit(-1); } break; default: // all others break; } }
// callback for tracing instruction static void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_data) { uint8_t opcode; 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 0xf4: //hlt printf("# Handling HLT\n"); 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 { printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++); } break; default: //all others // printf("# Handling OTHER\n"); break; } }
static void hook_code32(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { //uint8_t opcode[256]; uint8_t tmp[16]; uint32_t tmp4[1]; uint32_t ecx; printf("\nhook_code32: Address: %"PRIx64", Opcode Size: %d\n", address, size); print_registers(uc); size = MIN(sizeof(tmp), size); if (!uc_mem_read(uc, address, tmp, size)) { uint32_t i; printf("Opcode: "); for (i=0; i<size; i++) { printf("%x ", tmp[i]); } printf("\n"); } dump_stack_mem(uc); if (address == 0x60000025) { // double-check that opcode is // IMUL aex,[eax+0x41],0x10 if ((tmp[0] != 0x6b) || (tmp[1] != 0x41) || (tmp[2] != 0x41) || (tmp[3] != 0x10)) { printf("FAILED set-up of opcode\n"); exit(-1); } printf("IMUL eax,[ecx+0x41],0x10\n"); // double-check that memory operand points to 0x6000003a uc_reg_read(uc, UC_X86_REG_ECX, &ecx); if (ecx != 0x5ffffff9) { printf("FAILED EAX register not having 0x5ffffff9\n"); exit(-1); } printf("ECX = %8.8x\n", ecx); printf("%8.8x + 0x41 = %8.8x\n", 0x5ffffff9, 0x5ffffff9 + 0x41); // double-check that memory location 0x60000039 // contains 0x5151494a if (!uc_mem_read(uc, 0x6000003a, tmp4, 4)) { if (tmp4[0] != 0x5151494a) { printf("FAILED set-up\n"); exit(-1); } printf("Proved that 0x6000003a contains the proper 0x5151494a\n"); } // dump_stack_mem(uc); } // Stop after 'imul eax,[ecx+0x41],0x10 if (address == 0x60000029) { uint32_t eax; // IMUL eax,mem,Ib // mem = [ecx+0x41] // ecx = 0x5ffffff9 // [6000003A] = 0x5151494a // Stop after 'imul eax,[ecx+0x41],0x10 // This step basically shifts left 8-bit...elaborately. // multiplying 0x5151494a x 0x10 = 0x151494a0 uc_reg_read(uc, UC_X86_REG_EAX, &eax); if (eax != 0x151494a0) { fail_msg("FAIL: TB did not flush; eax is not the expected 0x151494a0\n"); print_registers(uc); //dump_stack_mem(uc); exit(-1); } printf("PASS\n"); } print_registers(uc); // dump_stack_mem(uc); return; }
int main(int argc, char **argv, char **envp) { uc_engine *uc; uc_hook trace1; uc_err err; uint8_t bytes[8]; uint32_t esp; int map_stack = 0; if (argc == 2 && strcmp(argv[1], "--map-stack") == 0) { map_stack = 1; } printf("Memory mapping test\n"); // Initialize emulator in X86-32bit mode err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return 1; } uc_mem_map(uc, 0x100000, 0x1000, UC_PROT_ALL); uc_mem_map(uc, 0x200000, 0x2000, UC_PROT_ALL); uc_mem_map(uc, 0x300000, 0x3000, UC_PROT_ALL); uc_mem_map(uc, 0x400000, 0x4000, UC_PROT_READ); if (map_stack) { printf("Pre-mapping stack\n"); uc_mem_map(uc, STACK, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE); } else { printf("Mapping stack on first invalid memory access\n"); } esp = STACK + STACK_SIZE; uc_reg_write(uc, UC_X86_REG_ESP, &esp); // write machine code to be emulated to memory if (uc_mem_write(uc, 0x400000, PROGRAM, sizeof(PROGRAM))) { printf("Failed to write emulation code to memory, quit!\n"); return 2; } else { printf("Allowed to write to read only memory via uc_mem_write\n"); } //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 0x400000, 0x400fff); // intercept invalid memory events uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL, 1, 0); // emulate machine code in infinite time printf("BEGIN execution - 1\n"); err = uc_emu_start(uc, 0x400000, 0x400000 + sizeof(PROGRAM), 0, 10); if (err) { printf("Expected failue on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); } else { printf("UNEXPECTED uc_emu_start returned UC_ERR_OK\n"); } printf("END execution - 1\n"); // 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(uc, UC_X86_REG_EAX, &eax); //resume execution at the mov dword [eax], 0x87654321 //to test an aligned write as well err = uc_emu_start(uc, 0x400015, 0x400000 + sizeof(PROGRAM), 0, 2); if (err) { printf("Expected failure on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); } else { printf("UNEXPECTED uc_emu_start returned UC_ERR_OK\n"); } printf("END execution - 2\n"); printf("Verifying content at 0x400025 is unchanged\n"); if (!uc_mem_read(uc, 0x400025, bytes, 4)) { printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)0x400025, *(uint32_t*) bytes); if (0x41414141 != *(uint32_t*) bytes) { printf("ERROR content in read only memory changed\n"); } else { printf("SUCCESS content in read only memory unchanged\n"); } } else { printf(">>> Failed to read 4 bytes from [0x%x]\n", (uint32_t)(esp - 4)); return 4; } printf("Verifying content at 0x40002C is unchanged\n"); if (!uc_mem_read(uc, 0x40002C, bytes, 4)) { printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)0x40002C, *(uint32_t*) bytes); if (0x42424242 != *(uint32_t*) bytes) { printf("ERROR content in read only memory changed\n"); } else { printf("SUCCESS content in read only memory unchanged\n"); } } else { printf(">>> Failed to read 4 bytes from [0x%x]\n", (uint32_t)(esp - 4)); return 4; } printf("Verifying content at bottom of stack is readable and correct\n"); if (!uc_mem_read(uc, esp - 4, bytes, 4)) { printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)(esp - 4), *(uint32_t*) bytes); } else { printf(">>> Failed to read 4 bytes from [0x%x]\n", (uint32_t)(esp - 4)); return 4; } uc_close(uc); return 0; }
static void test_i386_map_ptr(void) { uc_engine *uc; uc_err err; uint32_t tmp; uc_hook trace1, trace2; void *mem; int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register printf("===================================\n"); printf("Emulate i386 code - use uc_mem_map_ptr()\n"); // Initialize emulator in X86-32bit mode err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return; } // malloc 2MB memory for this emulation mem = calloc(1, 2 * 1024 * 1024); if (mem == NULL) { printf("Failed to malloc()\n"); return; } uc_mem_map_ptr(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL, mem); // write machine code to be emulated to memory if (!memcpy(mem, X86_CODE32, sizeof(X86_CODE32) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instruction by having @begin > @end uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); } // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); printf(">>> ECX = 0x%x\n", r_ecx); printf(">>> EDX = 0x%x\n", r_edx); // read from memory if (!uc_mem_read(uc, ADDRESS, &tmp, sizeof(tmp))) printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", ADDRESS, tmp); else printf(">>> Failed to read 4 bytes from [0x%x]\n", ADDRESS); uc_close(uc); }
int main(int argc, char **argv, char **envp) { uc_engine *uc; uc_hook 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, &uc); 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(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(uc, 0x3ff000, buf1, sizeof(buf1))) { 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(uc, 0x401000, buf2, sizeof(buf1))) { 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++); } // write machine code to be emulated to memory 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(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(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(uc, &trace1, UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid, NULL) != UC_ERR_OK) { printf("not ok %d - Failed to install memory invalid handler\n", log_num++); return 7; } else { printf("ok %d - memory invalid handler installed\n", log_num++); } // emulate machine code until told to stop by hook_code printf("# BEGIN execution\n"); 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; } 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(uc, addr, &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(uc, 0x3ff000, readbuf, sizeof(readbuf))) { 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(uc, 0x401000, readbuf, sizeof(readbuf))) { 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(uc) == 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; }
// emulate code that write invalid memory static void test_i386_invalid_mem_write(void) { uc_engine *uc; uc_err err; uc_hook trace1, trace2, trace3; uint32_t tmp; int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register printf("===================================\n"); printf("Emulate i386 code that write to invalid memory\n"); // Initialize emulator in X86-32bit mode err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return; } // map 2MB memory for this emulation uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory if (uc_mem_write(uc, ADDRESS, X86_CODE32_MEM_WRITE, sizeof(X86_CODE32_MEM_WRITE) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); // tracing all basic blocks with customized callback uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instruction by having @begin > @end uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // intercept invalid memory events uc_hook_add(uc, &trace3, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_WRITE) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); } // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); printf(">>> ECX = 0x%x\n", r_ecx); printf(">>> EDX = 0x%x\n", r_edx); // read from memory if (!uc_mem_read(uc, 0xaaaaaaaa, &tmp, sizeof(tmp))) printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xaaaaaaaa, tmp); else printf(">>> Failed to read 4 bytes from [0x%x]\n", 0xaaaaaaaa); if (!uc_mem_read(uc, 0xffffffaa, &tmp, sizeof(tmp))) printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xffffffaa, tmp); else printf(">>> Failed to read 4 bytes from [0x%x]\n", 0xffffffaa); uc_close(uc); }
int main(int argc, char **argv, char **envp) { uc_engine *uc; uc_hook 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, &uc); 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(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(uc, 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(uc, 0x1ff000, buf1, sizeof(buf1))) { 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(uc, 0x301000, buf2, sizeof(buf2))) { 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(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(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 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(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, 1, 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(uc, &trace1, UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_FETCH_PROT, hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install memory invalid handler\n", log_num++); return 8; } else { printf("ok %d - memory invalid handler installed\n", log_num++); } // emulate machine code until told to stop by hook_code printf("# BEGIN execution\n"); 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; } else { printf("ok %d - uc_emu_start complete\n", log_num++); } printf("# END execution\n"); // get ending 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); } //make sure that random blocks didn't get nuked // fill in sections that shouldn't get touched if (uc_mem_read(uc, 0x1ff000, readbuf, sizeof(readbuf))) { 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(uc, 0x301000, readbuf, sizeof(readbuf))) { 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(uc) == 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; }
static void test_basic_blocks(void **state) { uc_engine *uc = *state; uc_hook trace1; #define BASEADDR 0x1000000 uint64_t address = BASEADDR; const uint8_t code[] = { 0x33, 0xC0, // xor eax, eax 0x90, // nop 0x90, // nop 0xEB, 0x00, // jmp $+2 0x90, // nop 0x90, // nop 0x90, // nop }; static const struct bb blocks[] = { {BASEADDR, 6}, {BASEADDR+ 6, 3}, }; struct bbtest bbtest = { .blocks = blocks, .blocknum = 0, }; #undef BASEADDR // map 2MB memory for this emulation OK(uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL)); // write machine code to be emulated to memory OK(uc_mem_write(uc, address, code, sizeof(code))); // trace all basic blocks OK(uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, test_basic_blocks_hook, &bbtest, 1, 0)); OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0)); } /******************************************************************************/ // callback for tracing basic blocks static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { //printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } // callback for tracing instruction static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { //int eflags; //printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); //uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags); //printf(">>> --- EFLAGS is 0x%x\n", eflags); // Uncomment below code to stop the emulation using uc_emu_stop() // if (address == 0x1000009) // uc_emu_stop(uc); } static void test_i386(void **state) { uc_engine *uc; uc_err err; uint32_t tmp; uc_hook trace1, trace2; const uint8_t code[] = "\x41\x4a"; // INC ecx; DEC edx const uint64_t address = 0x1000000; int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register // Initialize emulator in X86-32bit mode err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); uc_assert_success(err); // map 2MB memory for this emulation err = uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL); uc_assert_success(err); // write machine code to be emulated to memory err = uc_mem_write(uc, address, code, sizeof(code)-1); uc_assert_success(err); // initialize machine registers err = uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); uc_assert_success(err); err = uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); uc_assert_success(err); // tracing all basic blocks with customized callback err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); uc_assert_success(err); // tracing all instruction by having @begin > @end err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); uc_assert_success(err); // emulate machine code in infinite time err = uc_emu_start(uc, address, address+sizeof(code)-1, 0, 0); uc_assert_success(err); // now print out some registers //printf(">>> Emulation done. Below is the CPU context\n"); uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); assert_int_equal(r_ecx, 0x1235); assert_int_equal(r_edx, 0x788F); // read from memory err = uc_mem_read(uc, address, (uint8_t *)&tmp, 4); uc_assert_success(err); //printf(">>> Read 4 bytes from [0x%"PRIX64"] = 0x%x\n", address, tmp); uc_close(uc); }
static void test_i386(void) { uc_engine *uc; uc_err err; uint32_t tmp; uc_hook trace1, trace2; int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register // XMM0 and XMM1 registers, low qword then high qword uint64_t r_xmm0[2] = {0x08090a0b0c0d0e0f, 0x0001020304050607}; uint64_t r_xmm1[2] = {0x8090a0b0c0d0e0f0, 0x0010203040506070}; printf("Emulate i386 code\n"); // Initialize emulator in X86-32bit mode err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return; } // map 2MB memory for this emulation uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory if (uc_mem_write(uc, ADDRESS, X86_CODE32, sizeof(X86_CODE32) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); uc_reg_write(uc, UC_X86_REG_XMM0, &r_xmm0); uc_reg_write(uc, UC_X86_REG_XMM1, &r_xmm1); // tracing all basic blocks with customized callback uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing all instruction by having @begin > @end uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); } // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); uc_reg_read(uc, UC_X86_REG_XMM0, &r_xmm0); printf(">>> ECX = 0x%x\n", r_ecx); printf(">>> EDX = 0x%x\n", r_edx); printf(">>> XMM0 = 0x%.16"PRIx64"%.16"PRIx64"\n", r_xmm0[1], r_xmm0[0]); // read from memory if (!uc_mem_read(uc, ADDRESS, &tmp, sizeof(tmp))) printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", ADDRESS, tmp); else printf(">>> Failed to read 4 bytes from [0x%x]\n", ADDRESS); uc_close(uc); }
void mem_read(uc_engine* uc, uint64_t addr, uint64_t len){ uint8_t* buff = alloca(len); uc_mem_read(uc, addr, buff, len); }