static void VM_exec() { int c; uc_engine *uc; uc_err err; // Initialize emulator in X86-64bit mode err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if(err) { printf("Failed on uc_open() with error returned: %s\n", uc_strerror(err)); return; } repeat: err = uc_mem_map(uc, ADDRESS1, SIZE, UC_PROT_ALL); if(err != UC_ERR_OK) { printf("Failed to map memory %s\n", uc_strerror(err)); goto err; } err = uc_mem_map(uc, ADDRESS2, SIZE, UC_PROT_ALL); if(err != UC_ERR_OK) { printf("Failed to map memory %s\n", uc_strerror(err)); goto err; } err = uc_mem_unmap(uc, ADDRESS1, SIZE); if(err != UC_ERR_OK) { printf("Failed to unmap memory %s\n", uc_strerror(err)); goto err; } err = uc_mem_unmap(uc, ADDRESS2, SIZE); if(err != UC_ERR_OK) { printf("Failed to unmap memory %s\n", uc_strerror(err)); goto err; } for(;;) { c = getchar(); //pause here and analyse memory usage before exiting with a program like VMMap; if(c != 'e') goto repeat; else break; } err: uc_close(uc); }
static void test_strange_map(void **state) { uc_engine *uc = *state; uc_mem_map( uc, 0x0,0x3000,0); uc_mem_unmap(uc, 0x1000,0x1000); uc_mem_map( uc, 0x3000,0x1000,0); uc_mem_map( uc, 0x4000,0x1000,0); uc_mem_map( uc, 0x1000,0x1000,0); uc_mem_map( uc, 0x5000,0x1000,0); uc_mem_unmap(uc, 0x0,0x1000); }
static void test_overlap_unmap_double_map(void **state) { uc_engine *uc = *state; uc_mem_map( uc, 0x1000, 0x2000, 0); uc_mem_map( uc, 0x1000, 0x1000, 0); uc_mem_unmap(uc, 0x2000, 0x1000); }
/* Try to unmap memory that has not been mapped */ static void test_bad_unmap(void **state) { uc_engine *uc = *state; /* TODO: Which error should this return? */ uc_assert_fail(uc_mem_unmap(uc, 0x0, 0x1000)); }
int main(int argc, char **argv, char **envp) { uc_engine *uc; uc_hook trace1, trace2; uc_err err; // Initialize emulator in X86-32bit mode err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("not ok - Failed on uc_open() with error returned: %u\n", err); return -1; } uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL); if (err) { printf("not ok - Failed on uc_mem_map() with error returned: %u\n", err); return -1; } uc_mem_map(uc, 0x4000, 0x1000, UC_PROT_ALL); if (err) { printf("not ok - Failed on uc_mem_map() with error returned: %u\n", err); return -1; } err = uc_mem_unmap(uc, 0x4000, 0x1000); if (err) { printf("not ok - Failed on uc_mem_unmap() with error returned: %u\n", err); return -1; } err = uc_mem_unmap(uc, 0x4000, 0x1000); if (!err) { printf("not ok - second unmap succeeded\n"); return -1; } printf("Tests OK\n"); uc_close(uc); return 0; }
// 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; } }
// 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; } }
// TODO: investigate whether qemu region manipulation functions already offered // this capability static bool split_region(struct uc_struct *uc, 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 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 return true; if (address >= mr->end || chunk_end <= mr->addr) // impossible case return false; backup = copy_region(uc, 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; // unmap this region first, then do split it later if (uc_mem_unmap(uc, 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(uc, begin, l_size, perms) != UC_ERR_OK) goto error; if (uc_mem_write(uc, begin, backup, l_size) != UC_ERR_OK) goto error; } if (m_size > 0 && !do_delete) { if (uc_mem_map(uc, address, m_size, perms) != UC_ERR_OK) goto error; if (uc_mem_write(uc, address, backup + l_size, m_size) != UC_ERR_OK) goto error; } if (r_size > 0) { if (uc_mem_map(uc, chunk_end, r_size, perms) != UC_ERR_OK) goto error; if (uc_mem_write(uc, chunk_end, backup + l_size + m_size, r_size) != UC_ERR_OK) goto error; } return true; error: free(backup); return false; }
void unmap(uc_engine* uc, uint64_t addr, uint64_t len){ uc_mem_unmap(uc, addr, len); }
void perform_unmap_step(uc_engine *uc){ uint64_t addr = get_aligned_addr(); uint64_t len = get_aligned_len(); printf("unmap(uc,0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step); uc_mem_unmap(uc, addr, len); }