diff --git a/include/unpacker.hpp b/include/unpacker.hpp index 45a64ca..3f2739a 100644 --- a/include/unpacker.hpp +++ b/include/unpacker.hpp @@ -67,9 +67,6 @@ class unpack_t { static void invalid_mem(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, unpack_t *unpack); - static void dep_read_watch(uc_engine *uc, uc_mem_type type, uint64_t address, - int size, int64_t value, unpack_t *unpack); - std::map loaded_modules; std::map > iat_hooks = { {"LocalAlloc", {LOCAL_ALLOC_VECTOR, &local_alloc_hook}}, diff --git a/src/unpacker.cpp b/src/unpacker.cpp index 0f58067..df39a2f 100644 --- a/src/unpacker.cpp +++ b/src/unpacker.cpp @@ -347,11 +347,6 @@ void unpack_t::local_free_hook(uc_engine *uc_ctx, unpack_t *obj) { } } -void unpack_t::dep_read_watch(uc_engine *uc, uc_mem_type type, uint64_t address, - int size, int64_t value, unpack_t *unpack) { - std::printf("> reading address = %p, size = %d\n", address, size); -} - void unpack_t::load_library_hook(uc_engine *uc_ctx, unpack_t *obj) { uc_err err; std::uintptr_t rcx = 0ull; @@ -411,12 +406,6 @@ void unpack_t::load_library_hook(uc_engine *uc_ctx, unpack_t *obj) { std::printf("> failed to set rax... reason = %d\n", err); return; } - - obj->uc_hooks.push_back(new uc_hook); - uc_hook_add(uc_ctx, obj->uc_hooks.back(), UC_HOOK_MEM_READ, - (void *)&engine::unpack_t::dep_read_watch, obj, alloc_addr, - alloc_addr + image_size); - std::printf("> mapped %s to base address %p\n", buff, alloc_addr); } else { const auto alloc_addr = obj->loaded_modules[buff]; @@ -468,8 +457,9 @@ bool unpack_t::code_exec_callback(uc_engine *uc, uint64_t address, uc_reg_read(uc, UC_X86_REG_RIP, &rip); if (rax > unpack->img_base + unpack->img_size || - rax < unpack->img_base) // skip calls to kernel32.dll... + rax < unpack->img_base) // skip calls outside the packed module... { + std::printf(">>> skipping external call to addr = %p\n", rax); rip += instr.length; uc_reg_write(uc, UC_X86_REG_RIP, &rip); } diff --git a/src/vmemu_t.cpp b/src/vmemu_t.cpp index f696f55..3f52fb8 100644 --- a/src/vmemu_t.cpp +++ b/src/vmemu_t.cpp @@ -23,6 +23,40 @@ bool emu_t::init() { return false; } + if ((err = uc_mem_map(uc_ctx, IAT_VECTOR_TABLE, PAGE_4KB, UC_PROT_ALL))) { + std::printf("> uc_mem_map iat vector table err = %d\n", err); + return false; + } + + // init iat vector table full of 'ret' instructions... + auto c3_page = malloc(PAGE_4KB); + { + memset(c3_page, 0xC3, PAGE_4KB); + + if ((err = uc_mem_write(uc_ctx, IAT_VECTOR_TABLE, c3_page, PAGE_4KB))) { + std::printf("> failed to init iat vector table...\n"); + free(c3_page); + return false; + } + } + free(c3_page); + + auto win_img = reinterpret_cast *>(g_vm_ctx->module_base); + + // iat hook all imports to return... + for (auto import_dir = reinterpret_cast( + win_img->get_directory(win::directory_id::directory_entry_import) + ->rva + + g_vm_ctx->module_base); + import_dir->rva_name; ++import_dir) { + for (auto iat_thunk = reinterpret_cast *>( + import_dir->rva_first_thunk + g_vm_ctx->module_base); + iat_thunk->address; ++iat_thunk) { + if (iat_thunk->is_ordinal) continue; + iat_thunk->function = IAT_VECTOR_TABLE; + } + } + if ((err = uc_mem_map(uc_ctx, g_vm_ctx->module_base, img_size, UC_PROT_ALL))) { std::printf("> map memory failed, reason = %d\n", err); @@ -53,7 +87,7 @@ bool emu_t::init() { if ((err = uc_hook_add(uc_ctx, &invalid_mem_hook, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED | - UC_HOOK_MEM_FETCH_UNMAPPED | UC_HOOK_INSN_INVALID, + UC_HOOK_MEM_FETCH_UNMAPPED, (void *)&vm::emu_t::invalid_mem, this, true, false))) { std::printf("> uc_hook_add error, reason = %d\n", err); return false; @@ -379,23 +413,6 @@ bool emu_t::code_exec_callback(uc_engine *uc, uint64_t address, uint32_t size, return false; } - // skip calls entirely since the virtual machine will execute to make calls... - // only time calls legit happen are with the CALL handler used only by the - // packer... - if (instr.mnemonic == ZYDIS_MNEMONIC_CALL && - instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && - instr.operands[0].reg.value == ZYDIS_REGISTER_RAX) { - std::uintptr_t rax = 0u, rip = 0u; - uc_reg_read(uc, UC_X86_REG_RAX, &rax); - uc_reg_read(uc, UC_X86_REG_RIP, &rip); - - if (rax > obj->g_vm_ctx->module_base + obj->img_size || - rax < obj->g_vm_ctx->module_base) { - rip += instr.length; - uc_reg_write(uc, UC_X86_REG_RIP, &rip); - } - } - // if the native instruction is a jmp rcx/rdx... then AL will contain the vm // handler table index of the vm handler that the emulator is about to jmp // too... @@ -665,6 +682,14 @@ void emu_t::invalid_mem(uc_engine *uc, uc_mem_type type, uint64_t address, case UC_MEM_FETCH_UNMAPPED: { std::printf(">>> fetching invalid instructions at address = %p\n", address); + + std::uintptr_t rip, rsp; + uc_reg_read(uc, UC_X86_REG_RSP, &rsp); + uc_mem_read(uc, rsp, &rip, sizeof rip); + rsp += 8; + uc_reg_write(uc, UC_X86_REG_RSP, &rsp); + uc_reg_write(uc, UC_X86_REG_RIP, &rip); + std::printf(">>> injecting return to try and recover... rip = %p\n", rip); break; } default: