diff --git a/.clang-format b/.clang-format index 8063c5e..d382898 100644 --- a/.clang-format +++ b/.clang-format @@ -1,18 +1,4 @@ --- -BasedOnStyle: Microsoft -AlignAfterOpenBracket: Align -AllowAllArgumentsOnNextLine: 'true' -AllowAllParametersOfDeclarationOnNextLine: 'true' -AllowShortIfStatementsOnASingleLine: Never -BreakBeforeBraces: Allman -IndentWidth: '4' -Language: Cpp -NamespaceIndentation: All -SpacesInAngles: 'true' -SpacesInCStyleCastParentheses: 'true' -SpacesInContainerLiterals: 'true' -SpacesInParentheses: 'true' -SpacesInSquareBrackets: 'true' -UseTab: Never +BasedOnStyle: Chromium ... diff --git a/include/unpacker.hpp b/include/unpacker.hpp index aeb07cb..9588ee6 100644 --- a/include/unpacker.hpp +++ b/include/unpacker.hpp @@ -32,6 +32,8 @@ #define UNMAP_VIEW_OF_FILE_VECTOR 11 #define CLOSE_HANDLE_VECTOR 12 #define VIRTUAL_PROTECT_VECTOR 13 +#define IS_DEBUGGER_PRESENT_VECTOR 14 +#define IS_REMOTE_DEBUGGER_PRESENT_VECTOR 15 #define MOV_RAX_0_SIG "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x00" #define MOV_RAX_0_MASK "xxxxxxxxxx" @@ -42,48 +44,58 @@ static_assert(sizeof MOV_RAX_0_SIG == sizeof MOV_RAX_0_MASK, namespace engine { class unpack_t { public: - explicit unpack_t(const std::string &module_name, - const std::vector &bin); + explicit unpack_t(const std::string& module_name, + const std::vector& bin); ~unpack_t(void); bool init(void); - bool unpack(std::vector &output); + bool unpack(std::vector& output); private: - using iat_hook_t = std::function; + using iat_hook_t = std::function; - uc_engine *uc_ctx; + uc_engine* uc_ctx; std::vector bin, map_bin; - std::vector uc_hooks; + std::vector uc_hooks; std::string module_name; std::uintptr_t img_base, img_size, heap_offset, pack_section_offset; - win::image_t<> *win_img; - - static void local_alloc_hook(uc_engine *, unpack_t *); - static void local_free_hook(uc_engine *, unpack_t *); - static void load_library_hook(uc_engine *, unpack_t *); - static void get_module_file_name_w_hook(uc_engine *, unpack_t *); - static void create_file_w_hook(uc_engine *, unpack_t *); - static void get_file_size_hook(uc_engine *, unpack_t *); - static void create_file_mapping_hook(uc_engine *, unpack_t *); - static void map_view_of_file_hook(uc_engine *, unpack_t *); - static void unmap_view_of_file_hook(uc_engine *, unpack_t *); - static void close_handle_hook(uc_engine *, unpack_t *); - static void virtual_protect_hook(uc_engine *, unpack_t *); - - static void uc_strcpy(uc_engine *uc, char *buff, std::uintptr_t addr); - static void uc_strcpy(uc_engine *uc, std::uintptr_t addr, char *buff); - - static bool iat_dispatcher(uc_engine *uc, uint64_t address, uint32_t size, - unpack_t *unpack); - - static bool unpack_section_callback(uc_engine *uc, uc_mem_type type, - uint64_t address, int size, int64_t value, - unpack_t *unpack); - - static void invalid_mem(uc_engine *uc, uc_mem_type type, uint64_t address, - int size, int64_t value, unpack_t *unpack); + win::image_t<>* win_img; + + static void local_alloc_hook(uc_engine*, unpack_t*); + static void local_free_hook(uc_engine*, unpack_t*); + static void load_library_hook(uc_engine*, unpack_t*); + static void get_module_file_name_w_hook(uc_engine*, unpack_t*); + static void create_file_w_hook(uc_engine*, unpack_t*); + static void get_file_size_hook(uc_engine*, unpack_t*); + static void create_file_mapping_hook(uc_engine*, unpack_t*); + static void map_view_of_file_hook(uc_engine*, unpack_t*); + static void unmap_view_of_file_hook(uc_engine*, unpack_t*); + static void close_handle_hook(uc_engine*, unpack_t*); + static void virtual_protect_hook(uc_engine*, unpack_t*); + static void is_debugger_present_hook(uc_engine*, unpack_t*); + + static void uc_strcpy(uc_engine* uc, char* buff, std::uintptr_t addr); + static void uc_strcpy(uc_engine* uc, std::uintptr_t addr, char* buff); + + static bool iat_dispatcher(uc_engine* uc, + uint64_t address, + uint32_t size, + unpack_t* unpack); + + static bool unpack_section_callback(uc_engine* uc, + uc_mem_type type, + uint64_t address, + int size, + int64_t value, + unpack_t* unpack); + + static void invalid_mem(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 = { @@ -100,6 +112,10 @@ class unpack_t { {"UnmapViewOfFile", {UNMAP_VIEW_OF_FILE_VECTOR, &unmap_view_of_file_hook}}, {"CloseHandle", {CLOSE_HANDLE_VECTOR, &close_handle_hook}}, - {"VirtualProtect", {VIRTUAL_PROTECT_VECTOR, &virtual_protect_hook}}}; + {"VirtualProtect", {VIRTUAL_PROTECT_VECTOR, &virtual_protect_hook}}, + {"IsDebuggerPresent", + {IS_DEBUGGER_PRESENT_VECTOR, &is_debugger_present_hook}}, + {"CheckRemoteDebuggerPresent", + {IS_REMOTE_DEBUGGER_PRESENT_VECTOR, &is_debugger_present_hook}}}; }; } // namespace engine \ No newline at end of file diff --git a/include/vmemu_t.hpp b/include/vmemu_t.hpp index cf7057f..50f298e 100644 --- a/include/vmemu_t.hpp +++ b/include/vmemu_t.hpp @@ -17,7 +17,7 @@ inline bool g_force_emu = false; class emu_t { struct cpu_ctx_t { std::uintptr_t rip; - uc_context *context; + uc_context* context; std::uint8_t stack[STACK_SIZE]; }; @@ -28,29 +28,36 @@ class emu_t { }; public: - explicit emu_t(vm::ctx_t *vm_ctx); + explicit emu_t(vm::ctx_t* vm_ctx); ~emu_t(); bool init(); - bool get_trace(std::vector &code_blocks); + bool get_trace(std::vector& code_blocks); private: std::uintptr_t img_base, img_size; uc_hook code_exec_hook, invalid_mem_hook, int_hook; - uc_engine *uc_ctx; - vm::ctx_t *g_vm_ctx; - code_block_data_t *cc_block; + uc_engine* uc_ctx; + vm::ctx_t* g_vm_ctx; + code_block_data_t* cc_block; std::vector vip_begins; std::vector code_blocks; std::map > vm_ctxs; - uc_err create_entry(vmp2::v2::entry_t *entry); - static void int_callback(uc_engine *uc, std::uint32_t intno, emu_t *obj); - static bool code_exec_callback(uc_engine *uc, uint64_t address, uint32_t size, - emu_t *obj); - static void invalid_mem(uc_engine *uc, uc_mem_type type, uint64_t address, - int size, int64_t value, emu_t *obj); + uc_err create_entry(vmp2::v2::entry_t* entry); + static void int_callback(uc_engine* uc, std::uint32_t intno, emu_t* obj); + static bool code_exec_callback(uc_engine* uc, + uint64_t address, + uint32_t size, + emu_t* obj); + + static void invalid_mem(uc_engine* uc, + uc_mem_type type, + uint64_t address, + int size, + int64_t value, + emu_t* obj); }; } // namespace vm \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index a3cce1f..12365a7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,7 @@ #define NUM_THREADS 20 -int __cdecl main(int argc, const char *argv[]) { +int __cdecl main(int argc, const char* argv[]) { argparse::argument_parser_t parser("VMEmu", "VMProtect 2 VM Handler Emulator"); parser.add_argument() @@ -56,7 +56,7 @@ int __cdecl main(int argc, const char *argv[]) { return -1; } - auto img = reinterpret_cast *>(module_data.data()); + auto img = reinterpret_cast*>(module_data.data()); auto image_size = img->get_nt_headers()->optional_header.size_image; const auto image_base = img->get_nt_headers()->optional_header.image_base; @@ -66,34 +66,34 @@ int __cdecl main(int argc, const char *argv[]) { reinterpret_cast(tmp.data()) + (PAGE_4KB - (reinterpret_cast(tmp.data()) & 0xFFFull)); - std::memcpy((void *)module_base, module_data.data(), 0x1000); + std::memcpy((void*)module_base, module_data.data(), 0x1000); std::for_each(img->get_nt_headers()->get_sections(), img->get_nt_headers()->get_sections() + img->get_nt_headers()->file_header.num_sections, - [&](const auto §ion_header) { + [&](const auto& section_header) { std::memcpy( - (void *)(module_base + section_header.virtual_address), + (void*)(module_base + section_header.virtual_address), module_data.data() + section_header.ptr_raw_data, section_header.size_raw_data); }); - auto win_img = reinterpret_cast *>(module_base); + auto win_img = reinterpret_cast*>(module_base); auto basereloc_dir = win_img->get_directory(win::directory_id::directory_entry_basereloc); - auto reloc_dir = reinterpret_cast( + auto reloc_dir = reinterpret_cast( basereloc_dir->rva + module_base); - win::reloc_block_t *reloc_block = &reloc_dir->first_block; + win::reloc_block_t* reloc_block = &reloc_dir->first_block; // apply relocations to all sections... while (reloc_block->base_rva && reloc_block->size_block) { std::for_each(reloc_block->begin(), reloc_block->end(), - [&](win::reloc_entry_t &entry) { + [&](win::reloc_entry_t& entry) { switch (entry.type) { case win::reloc_type_id::rel_based_dir64: { - auto reloc_at = reinterpret_cast( + auto reloc_at = reinterpret_cast( entry.offset + reloc_block->base_rva + module_base); *reloc_at = module_base + ((*reloc_at) - image_base); break; @@ -145,7 +145,7 @@ int __cdecl main(int argc, const char *argv[]) { } std::printf("> number of blocks = %d\n", code_blocks.size()); - for (auto &code_block : code_blocks) { + for (auto& code_block : code_blocks) { std::printf("> code block starts at = %p\n", code_block.vip_begin); std::printf("> number of virtual instructions = %d\n", code_block.vinstrs.size()); @@ -190,19 +190,19 @@ int __cdecl main(int argc, const char *argv[]) { vmp2::v4::rtn_t rtn; std::ofstream output(parser.get("out"), std::ios::binary); - output.write(reinterpret_cast(&file_header), + output.write(reinterpret_cast(&file_header), sizeof file_header); - output.write(reinterpret_cast(module_base), image_size); + output.write(reinterpret_cast(module_base), image_size); - std::vector vmp2_blocks; - for (const auto &code_block : code_blocks) { + std::vector vmp2_blocks; + for (const auto& code_block : code_blocks) { const auto _code_block_size = sizeof(vmp2::v4::code_block_t) + (code_block.jcc.block_addr.size() * 8) + code_block.vinstrs.size() * sizeof(vm::instrs::virt_instr_t); - vmp2::v4::code_block_t *_code_block = - reinterpret_cast(malloc(_code_block_size)); + vmp2::v4::code_block_t* _code_block = + reinterpret_cast(malloc(_code_block_size)); // serialize block meta data... _code_block->vip_begin = code_block.vip_begin; @@ -216,7 +216,7 @@ int __cdecl main(int argc, const char *argv[]) { for (auto idx = 0u; idx < code_block.jcc.block_addr.size(); ++idx) _code_block->branch_addr[idx] = code_block.jcc.block_addr[idx]; - auto block_vinstrs = reinterpret_cast( + auto block_vinstrs = reinterpret_cast( reinterpret_cast(_code_block) + sizeof(vmp2::v4::code_block_t) + (code_block.jcc.block_addr.size() * 8)); @@ -232,7 +232,7 @@ int __cdecl main(int argc, const char *argv[]) { sizeof(vmp2::v4::rtn_t::vm_enter_offset); std::for_each(vmp2_blocks.begin(), vmp2_blocks.end(), - [&](vmp2::v4::code_block_t *vmp2_block) -> void { + [&](vmp2::v4::code_block_t* vmp2_block) -> void { code_blocks_size += vmp2_block->next_block_offset; }); @@ -240,14 +240,14 @@ int __cdecl main(int argc, const char *argv[]) { rtn.code_block_count = vmp2_blocks.size(); rtn.vm_enter_offset = vm_entry_rva; - output.write(reinterpret_cast(&rtn), + output.write(reinterpret_cast(&rtn), sizeof(vmp2::v4::rtn_t::size) + sizeof(vmp2::v4::rtn_t::code_block_count) + sizeof(vmp2::v4::rtn_t::vm_enter_offset)); std::for_each(vmp2_blocks.begin(), vmp2_blocks.end(), - [&](vmp2::v4::code_block_t *vmp2_block) -> void { - output.write(reinterpret_cast(vmp2_block), + [&](vmp2::v4::code_block_t* vmp2_block) -> void { + output.write(reinterpret_cast(vmp2_block), vmp2_block->next_block_offset); free(vmp2_block); }); @@ -269,7 +269,7 @@ int __cdecl main(int argc, const char *argv[]) { parser.get("out").c_str()); std::ofstream output(parser.get("out"), std::ios::binary); - output.write(reinterpret_cast(unpacked_bin.data()), + output.write(reinterpret_cast(unpacked_bin.data()), unpacked_bin.size()); output.close(); @@ -281,10 +281,10 @@ int __cdecl main(int argc, const char *argv[]) { virt_rtns; std::vector threads; - for (const auto &[vm_enter_offset, encrypted_rva, hndlr_tble] : entries) { + for (const auto& [vm_enter_offset, encrypted_rva, hndlr_tble] : entries) { if (threads.size() == NUM_THREADS) { std::for_each(threads.begin(), threads.end(), - [&](std::thread &t) { t.join(); }); + [&](std::thread& t) { t.join(); }); threads.clear(); } @@ -328,7 +328,7 @@ int __cdecl main(int argc, const char *argv[]) { } std::for_each(threads.begin(), threads.end(), - [&](std::thread &t) { t.join(); }); + [&](std::thread& t) { t.join(); }); std::printf("> traced %d virtual routines...\n", virt_rtns.size()); std::printf("> serializing results....\n"); @@ -346,23 +346,22 @@ int __cdecl main(int argc, const char *argv[]) { file_header.rtn_offset = image_size + sizeof file_header; std::ofstream output(parser.get("out"), std::ios::binary); - output.write(reinterpret_cast(&file_header), + output.write(reinterpret_cast(&file_header), sizeof file_header); - output.write(reinterpret_cast(module_base), image_size); + output.write(reinterpret_cast(module_base), image_size); - for (auto &[vm_enter_offset, virt_rtn] : virt_rtns) { + for (auto& [vm_enter_offset, virt_rtn] : virt_rtns) { vmp2::v4::rtn_t rtn{(u32)virt_rtn.size()}; - std::vector vmp2_blocks; + std::vector vmp2_blocks; - for (const auto &code_block : virt_rtn) { + for (const auto& code_block : virt_rtn) { const auto _code_block_size = sizeof(vmp2::v4::code_block_t) + (code_block.jcc.block_addr.size() * 8) + code_block.vinstrs.size() * sizeof(vm::instrs::virt_instr_t); - vmp2::v4::code_block_t *_code_block = - reinterpret_cast( - malloc(_code_block_size)); + vmp2::v4::code_block_t* _code_block = + reinterpret_cast(malloc(_code_block_size)); // serialize block meta data... _code_block->vip_begin = code_block.vip_begin; @@ -376,7 +375,7 @@ int __cdecl main(int argc, const char *argv[]) { for (auto idx = 0u; idx < code_block.jcc.block_addr.size(); ++idx) _code_block->branch_addr[idx] = code_block.jcc.block_addr[idx]; - auto block_vinstrs = reinterpret_cast( + auto block_vinstrs = reinterpret_cast( reinterpret_cast(_code_block) + sizeof(vmp2::v4::code_block_t) + (code_block.jcc.block_addr.size() * 8)); @@ -392,7 +391,7 @@ int __cdecl main(int argc, const char *argv[]) { sizeof(vmp2::v4::rtn_t::code_block_count); std::for_each(vmp2_blocks.begin(), vmp2_blocks.end(), - [&](vmp2::v4::code_block_t *vmp2_block) -> void { + [&](vmp2::v4::code_block_t* vmp2_block) -> void { code_blocks_size += vmp2_block->next_block_offset; }); @@ -400,14 +399,14 @@ int __cdecl main(int argc, const char *argv[]) { rtn.code_block_count = vmp2_blocks.size(); rtn.vm_enter_offset = vm_enter_offset; - output.write(reinterpret_cast(&rtn), + output.write(reinterpret_cast(&rtn), sizeof(vmp2::v4::rtn_t::size) + sizeof(vmp2::v4::rtn_t::code_block_count) + sizeof(vmp2::v4::rtn_t::vm_enter_offset)); std::for_each(vmp2_blocks.begin(), vmp2_blocks.end(), - [&](vmp2::v4::code_block_t *vmp2_block) -> void { - output.write(reinterpret_cast(vmp2_block), + [&](vmp2::v4::code_block_t* vmp2_block) -> void { + output.write(reinterpret_cast(vmp2_block), vmp2_block->next_block_offset); free(vmp2_block); }); diff --git a/src/unpacker.cpp b/src/unpacker.cpp index 4953958..bf77b98 100644 --- a/src/unpacker.cpp +++ b/src/unpacker.cpp @@ -1,24 +1,26 @@ #include namespace engine { -unpack_t::unpack_t(const std::string &module_name, - const std::vector &packed_bin) +unpack_t::unpack_t(const std::string& module_name, + const std::vector& packed_bin) : module_name(module_name), bin(packed_bin), uc_ctx(nullptr), heap_offset(0ull), pack_section_offset(0ull) { - win_img = reinterpret_cast *>(bin.data()); + win_img = reinterpret_cast*>(bin.data()); img_base = win_img->get_nt_headers()->optional_header.image_base; img_size = win_img->get_nt_headers()->optional_header.size_image; std::printf("> image base = 0x%p, image size = 0x%x\n", img_base, img_size); } unpack_t::~unpack_t(void) { - if (uc_ctx) uc_close(uc_ctx); + if (uc_ctx) + uc_close(uc_ctx); - for (auto &ptr : uc_hooks) - if (ptr) delete ptr; + for (auto& ptr : uc_hooks) + if (ptr) + delete ptr; } bool unpack_t::init(void) { @@ -67,7 +69,7 @@ bool unpack_t::init(void) { win_img->get_nt_headers()->file_header.num_sections; std::for_each( - sec_begin, sec_end, [&](const win::section_header_t &sec_header) { + sec_begin, sec_end, [&](const win::section_header_t& sec_header) { memcpy(map_bin.data() + sec_header.virtual_address, bin.data() + sec_header.ptr_raw_data, sec_header.size_raw_data); }); @@ -75,19 +77,19 @@ bool unpack_t::init(void) { auto basereloc_dir = win_img->get_directory(win::directory_id::directory_entry_basereloc); - auto reloc_dir = reinterpret_cast( + auto reloc_dir = reinterpret_cast( basereloc_dir->rva + map_bin.data()); - win::reloc_block_t *reloc_block = &reloc_dir->first_block; + win::reloc_block_t* reloc_block = &reloc_dir->first_block; // apply relocations to all sections... while (reloc_block->base_rva && reloc_block->size_block) { std::for_each( reloc_block->begin(), reloc_block->end(), - [&](win::reloc_entry_t &entry) { + [&](win::reloc_entry_t& entry) { switch (entry.type) { case win::reloc_type_id::rel_based_dir64: { - auto reloc_at = reinterpret_cast( + auto reloc_at = reinterpret_cast( entry.offset + reloc_block->base_rva + map_bin.data()); *reloc_at = img_base + ((*reloc_at) - img_base); @@ -102,17 +104,18 @@ bool unpack_t::init(void) { } // install iat hooks... - for (auto import_dir = reinterpret_cast( + for (auto import_dir = reinterpret_cast( win_img->get_directory(win::directory_id::directory_entry_import) ->rva + map_bin.data()); import_dir->rva_name; ++import_dir) { - for (auto iat_thunk = reinterpret_cast *>( + for (auto iat_thunk = reinterpret_cast*>( import_dir->rva_first_thunk + map_bin.data()); iat_thunk->address; ++iat_thunk) { - if (iat_thunk->is_ordinal) continue; + if (iat_thunk->is_ordinal) + continue; - auto iat_name = reinterpret_cast( + auto iat_name = reinterpret_cast( iat_thunk->address + map_bin.data()); if (iat_hooks.find(iat_name->name) != iat_hooks.end()) { @@ -137,7 +140,7 @@ bool unpack_t::init(void) { uc_hooks.push_back(new uc_hook); if ((err = uc_hook_add(uc_ctx, uc_hooks.back(), UC_HOOK_CODE, - (void *)&engine::unpack_t::iat_dispatcher, this, + (void*)&engine::unpack_t::iat_dispatcher, this, IAT_VECTOR_TABLE, IAT_VECTOR_TABLE + PAGE_4KB))) { std::printf("> uc_hook_add error, reason = %d\n", err); return false; @@ -148,21 +151,21 @@ bool unpack_t::init(void) { uc_ctx, uc_hooks.back(), UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_FETCH_UNMAPPED | UC_HOOK_INSN_INVALID, - (void *)&engine::unpack_t::invalid_mem, this, true, false))) { + (void*)&engine::unpack_t::invalid_mem, this, true, false))) { std::printf("> uc_hook_add error, reason = %d\n", err); return false; } // execution break points on all sections that are executable but have no // physical size on disk... - std::for_each(sec_begin, sec_end, [&](const win::section_header_t &header) { + std::for_each(sec_begin, sec_end, [&](const win::section_header_t& header) { if (!header.ptr_raw_data && !header.size_raw_data && header.characteristics.mem_execute && header.characteristics.mem_write && !header.is_discardable()) { uc_hooks.push_back(new uc_hook); if ((err = uc_hook_add( uc_ctx, uc_hooks.back(), UC_HOOK_CODE | UC_HOOK_MEM_WRITE, - (void *)&engine::unpack_t::unpack_section_callback, this, + (void*)&engine::unpack_t::unpack_section_callback, this, header.virtual_address + img_base, header.virtual_address + header.virtual_size + img_base))) { std::printf("> failed to add hook... reason = %d\n", err); @@ -175,7 +178,7 @@ bool unpack_t::init(void) { return true; } -bool unpack_t::unpack(std::vector &output) { +bool unpack_t::unpack(std::vector& output) { uc_err err; auto nt_headers = win_img->get_nt_headers(); std::uintptr_t rip = nt_headers->optional_header.entry_point + img_base, @@ -204,21 +207,21 @@ bool unpack_t::unpack(std::vector &output) { return false; } - auto output_img = reinterpret_cast *>(output.data()); + auto output_img = reinterpret_cast*>(output.data()); auto sections = output_img->get_nt_headers()->get_sections(); auto section_cnt = output_img->get_file_header()->num_sections; // { section virtual address -> vector of section offset to reloc } - std::map > new_relocs; + std::map> new_relocs; // search executable sections for MOV RAX, 00 00 00 00 00 00 00 00... std::for_each( - sections, sections + section_cnt, [&](win::section_header_t &header) { + sections, sections + section_cnt, [&](win::section_header_t& header) { if (header.characteristics.mem_execute) { auto result = output.data() + header.virtual_address; do { - result = reinterpret_cast(vm::locate::sigscan( + result = reinterpret_cast(vm::locate::sigscan( result, header.virtual_size - (reinterpret_cast(result) - @@ -247,18 +250,19 @@ bool unpack_t::unpack(std::vector &output) { // determines if a relocation block exists for a given page... static const auto has_reloc_page = [&](std::uint32_t page) -> bool { - auto img = reinterpret_cast *>(output.data()); + auto img = reinterpret_cast*>(output.data()); auto sections = img->get_nt_headers()->get_sections(); auto section_cnt = img->get_file_header()->num_sections; auto basereloc_dir = img->get_directory(win::directory_id::directory_entry_basereloc); - auto reloc_dir = reinterpret_cast( + auto reloc_dir = reinterpret_cast( basereloc_dir->rva + output.data()); - win::reloc_block_t *reloc_block = &reloc_dir->first_block; + win::reloc_block_t* reloc_block = &reloc_dir->first_block; while (reloc_block->base_rva && reloc_block->size_block) { - if (reloc_block->base_rva == page) return true; + if (reloc_block->base_rva == page) + return true; reloc_block = reloc_block->next(); } @@ -268,7 +272,7 @@ bool unpack_t::unpack(std::vector &output) { // calc size to add new reloc info... std::size_t resize_cnt = 0ull; - for (const auto &[reloc_rva, relocs] : new_relocs) + for (const auto& [reloc_rva, relocs] : new_relocs) if (!has_reloc_page(reloc_rva)) resize_cnt += sizeof(win::reloc_block_t) + (relocs.size() * sizeof(win::reloc_entry_t)); @@ -278,12 +282,12 @@ bool unpack_t::unpack(std::vector &output) { resize_cnt += sizeof(win::reloc_block_t) + basereloc_dir->size; output.resize(output.size() + resize_cnt); - output_img = reinterpret_cast *>(output.data()); + output_img = reinterpret_cast*>(output.data()); basereloc_dir = output_img->get_directory(win::directory_id::directory_entry_basereloc); - auto reloc_dir = reinterpret_cast( + auto reloc_dir = reinterpret_cast( basereloc_dir->rva + output.data()); // move .reloc section to the end of the file... @@ -291,7 +295,7 @@ bool unpack_t::unpack(std::vector &output) { output_img->get_nt_headers()->get_sections(), output_img->get_nt_headers()->get_sections() + output_img->get_nt_headers()->file_header.num_sections, - [&](coff::section_header_t &hdr) { + [&](coff::section_header_t& hdr) { if (hdr.virtual_address == basereloc_dir->rva) { hdr.virtual_size = resize_cnt; hdr.size_raw_data = resize_cnt; @@ -316,10 +320,11 @@ bool unpack_t::unpack(std::vector &output) { ~0xFFFull; // add new relocs to the .reloc section... - for (const auto &[reloc_rva, relocs] : new_relocs) { - if (has_reloc_page(reloc_rva)) continue; + for (const auto& [reloc_rva, relocs] : new_relocs) { + if (has_reloc_page(reloc_rva)) + continue; - win::reloc_block_t *reloc_block = &reloc_dir->first_block; + win::reloc_block_t* reloc_block = &reloc_dir->first_block; while (reloc_block->base_rva && reloc_block->size_block) reloc_block = reloc_block->next(); @@ -338,7 +343,7 @@ bool unpack_t::unpack(std::vector &output) { return true; } -void unpack_t::local_alloc_hook(uc_engine *uc_ctx, unpack_t *obj) { +void unpack_t::local_alloc_hook(uc_engine* uc_ctx, unpack_t* obj) { uc_err err; std::uintptr_t rax, rdx; @@ -363,7 +368,12 @@ void unpack_t::local_alloc_hook(uc_engine *uc_ctx, unpack_t *obj) { } } -void unpack_t::local_free_hook(uc_engine *uc_ctx, unpack_t *obj) { +void unpack_t::is_debugger_present_hook(uc_engine* uc, unpack_t* obj) { + std::uintptr_t rax = 0ull; + uc_reg_write(uc, UC_X86_REG_RAX, &rax); +} + +void unpack_t::local_free_hook(uc_engine* uc_ctx, unpack_t* obj) { uc_err err; std::uintptr_t rax = 0ull; @@ -373,34 +383,34 @@ void unpack_t::local_free_hook(uc_engine *uc_ctx, unpack_t *obj) { } } -void unpack_t::unmap_view_of_file_hook(uc_engine *uc, unpack_t *obj) { +void unpack_t::unmap_view_of_file_hook(uc_engine* uc, unpack_t* obj) { std::uintptr_t rcx, rax = true; uc_reg_read(uc, UC_X86_REG_RCX, &rcx); uc_reg_write(uc, UC_X86_REG_RAX, &rax); std::printf("> UnmapViewOfFile(%p)\n", rcx); } -void unpack_t::close_handle_hook(uc_engine *uc, unpack_t *obj) { +void unpack_t::close_handle_hook(uc_engine* uc, unpack_t* obj) { std::uintptr_t rcx, rax = true; uc_reg_read(uc, UC_X86_REG_RCX, &rcx); uc_reg_write(uc, UC_X86_REG_RAX, &rax); std::printf("> CloseHandle(%x)\n", rcx); } -void unpack_t::get_module_file_name_w_hook(uc_engine *uc, unpack_t *obj) { +void unpack_t::get_module_file_name_w_hook(uc_engine* uc, unpack_t* obj) { uc_err err; std::uintptr_t rcx, rdx, r8; uc_reg_read(uc, UC_X86_REG_RCX, &rcx); uc_reg_read(uc, UC_X86_REG_RDX, &rdx); uc_reg_read(uc, UC_X86_REG_R8, &r8); std::printf("> GetModuleFileNameW(%p, %p, %d)\n", rcx, rdx, r8); - uc_strcpy(uc, rdx, (char *)obj->module_name.c_str()); + uc_strcpy(uc, rdx, (char*)obj->module_name.c_str()); std::uint32_t size = obj->module_name.size(); uc_reg_write(uc, UC_X86_REG_RAX, &size); } -void unpack_t::create_file_w_hook(uc_engine *uc, unpack_t *obj) { +void unpack_t::create_file_w_hook(uc_engine* uc, unpack_t* obj) { char buff[256]; std::uintptr_t rcx, rax = PACKED_FILE_HANDLE; uc_reg_read(uc, UC_X86_REG_RCX, &rcx); @@ -410,7 +420,7 @@ void unpack_t::create_file_w_hook(uc_engine *uc, unpack_t *obj) { uc_reg_write(uc, UC_X86_REG_RAX, &rax); } -void unpack_t::get_file_size_hook(uc_engine *uc, unpack_t *obj) { +void unpack_t::get_file_size_hook(uc_engine* uc, unpack_t* obj) { std::uintptr_t rcx, rdx, rax; uc_reg_read(uc, UC_X86_REG_RCX, &rcx); uc_reg_read(uc, UC_X86_REG_RDX, &rdx); @@ -425,7 +435,7 @@ void unpack_t::get_file_size_hook(uc_engine *uc, unpack_t *obj) { } } -void unpack_t::create_file_mapping_hook(uc_engine *uc, unpack_t *obj) { +void unpack_t::create_file_mapping_hook(uc_engine* uc, unpack_t* obj) { std::uintptr_t rcx, r8, rax = PACKED_FILE_HANDLE; uc_reg_read(uc, UC_X86_REG_RCX, &rcx); uc_reg_read(uc, UC_X86_REG_R8, &r8); @@ -438,7 +448,7 @@ void unpack_t::create_file_mapping_hook(uc_engine *uc, unpack_t *obj) { } } -void unpack_t::map_view_of_file_hook(uc_engine *uc, unpack_t *obj) { +void unpack_t::map_view_of_file_hook(uc_engine* uc, unpack_t* obj) { std::uintptr_t rcx, rdx, r8, r9, rax; uc_reg_read(uc, UC_X86_REG_RCX, &rcx); uc_reg_read(uc, UC_X86_REG_RDX, &rdx); @@ -472,7 +482,7 @@ void unpack_t::map_view_of_file_hook(uc_engine *uc, unpack_t *obj) { } } -void unpack_t::virtual_protect_hook(uc_engine *uc, unpack_t *obj) { +void unpack_t::virtual_protect_hook(uc_engine* uc, unpack_t* obj) { std::uintptr_t rcx, rdx, r8, r9, rax = true; uc_reg_read(uc, UC_X86_REG_RCX, &rcx); uc_reg_read(uc, UC_X86_REG_RDX, &rdx); @@ -482,7 +492,7 @@ void unpack_t::virtual_protect_hook(uc_engine *uc, unpack_t *obj) { uc_reg_write(uc, UC_X86_REG_RAX, &rax); } -void unpack_t::load_library_hook(uc_engine *uc_ctx, unpack_t *obj) { +void unpack_t::load_library_hook(uc_engine* uc_ctx, unpack_t* obj) { uc_err err; std::uintptr_t rcx = 0ull; @@ -506,7 +516,7 @@ void unpack_t::load_library_hook(uc_engine *uc_ctx, unpack_t *obj) { exit(-1); } - auto img = reinterpret_cast *>(module_data.data()); + auto img = reinterpret_cast*>(module_data.data()); auto image_size = img->get_nt_headers()->optional_header.size_image; tmp.resize(image_size); @@ -514,7 +524,7 @@ void unpack_t::load_library_hook(uc_engine *uc_ctx, unpack_t *obj) { std::for_each(img->get_nt_headers()->get_sections(), img->get_nt_headers()->get_sections() + img->get_nt_headers()->file_header.num_sections, - [&](const auto §ion_header) { + [&](const auto& section_header) { std::memcpy( tmp.data() + section_header.virtual_address, module_data.data() + section_header.ptr_raw_data, @@ -522,31 +532,38 @@ void unpack_t::load_library_hook(uc_engine *uc_ctx, unpack_t *obj) { }); const auto module_base = reinterpret_cast(tmp.data()); - img = reinterpret_cast *>(module_base); + img = reinterpret_cast*>(module_base); const auto image_base = img->get_nt_headers()->optional_header.image_base; const auto alloc_addr = module_base & ~0xFFFull; obj->loaded_modules[buff] = alloc_addr; - // install iat hooks... - for (auto import_dir = reinterpret_cast( - img->get_directory(win::directory_id::directory_entry_import) - ->rva + - module_base); - import_dir->rva_name; ++import_dir) { - for (auto iat_thunk = reinterpret_cast *>( - import_dir->rva_first_thunk + module_base); - iat_thunk->address; ++iat_thunk) { - if (iat_thunk->is_ordinal) continue; - - auto iat_name = reinterpret_cast( - iat_thunk->address + module_base); - - if (obj->iat_hooks.find(iat_name->name) != obj->iat_hooks.end()) { - std::printf("> iat hooking %s to vector table %p\n", iat_name->name, - obj->iat_hooks[iat_name->name].first + IAT_VECTOR_TABLE); - - iat_thunk->function = - obj->iat_hooks[iat_name->name].first + IAT_VECTOR_TABLE; + auto dir = reinterpret_cast( + img->get_directory(win::directory_id::directory_entry_import)); + + if (dir) { + // install iat hooks... + for (auto import_dir = reinterpret_cast( + img->get_directory(win::directory_id::directory_entry_import) + ->rva + + module_base); + import_dir->rva_name; ++import_dir) { + for (auto iat_thunk = reinterpret_cast*>( + import_dir->rva_first_thunk + module_base); + iat_thunk->address; ++iat_thunk) { + if (iat_thunk->is_ordinal) + continue; + + auto iat_name = reinterpret_cast( + iat_thunk->address + module_base); + + if (obj->iat_hooks.find(iat_name->name) != obj->iat_hooks.end()) { + std::printf( + "> iat hooking %s to vector table %p\n", iat_name->name, + obj->iat_hooks[iat_name->name].first + IAT_VECTOR_TABLE); + + iat_thunk->function = + obj->iat_hooks[iat_name->name].first + IAT_VECTOR_TABLE; + } } } } @@ -577,7 +594,7 @@ void unpack_t::load_library_hook(uc_engine *uc_ctx, unpack_t *obj) { } } // namespace engine -void unpack_t::uc_strcpy(uc_engine *uc_ctx, char *buff, std::uintptr_t addr) { +void unpack_t::uc_strcpy(uc_engine* uc_ctx, char* buff, std::uintptr_t addr) { uc_err err; char i = 0u; auto idx = 0ul; @@ -590,7 +607,7 @@ void unpack_t::uc_strcpy(uc_engine *uc_ctx, char *buff, std::uintptr_t addr) { } while ((buff[idx++] = i)); } -void unpack_t::uc_strcpy(uc_engine *uc, std::uintptr_t addr, char *buff) { +void unpack_t::uc_strcpy(uc_engine* uc, std::uintptr_t addr, char* buff) { uc_err err; for (char idx = 0u, c = buff[idx]; buff[idx]; ++idx, c = buff[idx]) { if ((err = uc_mem_write(uc, addr + idx, &c, sizeof c))) { @@ -600,10 +617,12 @@ void unpack_t::uc_strcpy(uc_engine *uc, std::uintptr_t addr, char *buff) { } } -bool unpack_t::iat_dispatcher(uc_engine *uc, uint64_t address, uint32_t size, - unpack_t *unpack) { +bool unpack_t::iat_dispatcher(uc_engine* uc, + uint64_t address, + uint32_t size, + unpack_t* unpack) { auto vec = address - IAT_VECTOR_TABLE; - for (auto &[iat_name, iat_hook_data] : unpack->iat_hooks) { + for (auto& [iat_name, iat_hook_data] : unpack->iat_hooks) { if (iat_hook_data.first == vec) { iat_hook_data.second(uc, unpack); return true; @@ -612,9 +631,12 @@ bool unpack_t::iat_dispatcher(uc_engine *uc, uint64_t address, uint32_t size, return false; } -bool unpack_t::unpack_section_callback(uc_engine *uc, uc_mem_type type, - uint64_t address, int size, - int64_t value, unpack_t *unpack) { +bool unpack_t::unpack_section_callback(uc_engine* uc, + uc_mem_type type, + uint64_t address, + int size, + int64_t value, + unpack_t* unpack) { if (address == unpack->pack_section_offset + unpack->img_base) { std::printf("> last byte written to unpack section... dumping...\n"); uc_emu_stop(uc); @@ -623,8 +645,12 @@ bool unpack_t::unpack_section_callback(uc_engine *uc, uc_mem_type type, return true; } -void unpack_t::invalid_mem(uc_engine *uc, uc_mem_type type, uint64_t address, - int size, int64_t value, unpack_t *unpack) { +void unpack_t::invalid_mem(uc_engine* uc, + uc_mem_type type, + uint64_t address, + int size, + int64_t value, + unpack_t* unpack) { switch (type) { case UC_MEM_READ_UNMAPPED: { uc_mem_map(uc, address & ~0xFFFull, PAGE_4KB, UC_PROT_ALL); diff --git a/src/vmemu_t.cpp b/src/vmemu_t.cpp index 1003d00..6d80937 100644 --- a/src/vmemu_t.cpp +++ b/src/vmemu_t.cpp @@ -1,14 +1,15 @@ #include "vmemu_t.hpp" namespace vm { -emu_t::emu_t(vm::ctx_t *vm_ctx) +emu_t::emu_t(vm::ctx_t* vm_ctx) : g_vm_ctx(vm_ctx), uc_ctx(nullptr), img_base(vm_ctx->image_base), img_size(vm_ctx->image_size) {} emu_t::~emu_t() { - if (uc_ctx) uc_close(uc_ctx); + if (uc_ctx) + uc_close(uc_ctx); } bool emu_t::init() { @@ -41,18 +42,19 @@ bool emu_t::init() { } free(c3_page); - auto win_img = reinterpret_cast *>(g_vm_ctx->module_base); + auto win_img = reinterpret_cast*>(g_vm_ctx->module_base); // iat hook all imports to return... - for (auto import_dir = reinterpret_cast( + 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 *>( + 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; + if (iat_thunk->is_ordinal) + continue; iat_thunk->function = IAT_VECTOR_TABLE; } } @@ -64,14 +66,14 @@ bool emu_t::init() { } if ((err = uc_mem_write(uc_ctx, g_vm_ctx->module_base, - reinterpret_cast(g_vm_ctx->module_base), + reinterpret_cast(g_vm_ctx->module_base), img_size))) { std::printf("> failed to write memory... reason = %d\n", err); return false; } if ((err = uc_hook_add(uc_ctx, &code_exec_hook, UC_HOOK_CODE, - (void *)&vm::emu_t::code_exec_callback, this, + (void*)&vm::emu_t::code_exec_callback, this, g_vm_ctx->module_base, g_vm_ctx->module_base + img_size))) { std::printf("> uc_hook_add error, reason = %d\n", err); @@ -79,7 +81,7 @@ bool emu_t::init() { } if ((err = uc_hook_add(uc_ctx, &int_hook, UC_HOOK_INTR, - (void *)&vm::emu_t::int_callback, this, 0ull, 0ull))) { + (void*)&vm::emu_t::int_callback, this, 0ull, 0ull))) { std::printf("> uc_hook_add error, reason = %d\n", err); return false; } @@ -88,14 +90,14 @@ bool emu_t::init() { uc_hook_add(uc_ctx, &invalid_mem_hook, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_FETCH_UNMAPPED, - (void *)&vm::emu_t::invalid_mem, this, true, false))) { + (void*)&vm::emu_t::invalid_mem, this, true, false))) { std::printf("> uc_hook_add error, reason = %d\n", err); return false; } return true; } -bool emu_t::get_trace(std::vector &entries) { +bool emu_t::get_trace(std::vector& entries) { uc_err err; std::uintptr_t rip = g_vm_ctx->vm_entry_rva + g_vm_ctx->module_base, rsp = STACK_BASE + STACK_SIZE - PAGE_4KB; @@ -120,13 +122,15 @@ bool emu_t::get_trace(std::vector &entries) { return false; } - if (cc_block) code_blocks.push_back(code_block); + if (cc_block) + code_blocks.push_back(code_block); // code_blocks.size() will continue to grow as all branches are traced... // when idx is > code_blocks.size() then we have traced all branches... for (auto idx = 0u; idx < code_blocks.size(); ++idx) { const auto _code_block = code_blocks[idx]; - if (!_code_block.code_block.jcc.has_jcc) continue; + if (!_code_block.code_block.jcc.has_jcc) + continue; switch (_code_block.code_block.jcc.type) { case vm::instrs::jcc_type::branching: { @@ -306,7 +310,7 @@ bool emu_t::get_trace(std::vector &entries) { } } - for (auto &[code_block, cpu_ctx, vm_ctx] : code_blocks) { + for (auto& [code_block, cpu_ctx, vm_ctx] : code_blocks) { // convert linear virtual addresses to image based addresses... code_block.vip_begin = (code_block.vip_begin - g_vm_ctx->module_base) + g_vm_ctx->image_base; @@ -338,7 +342,7 @@ bool emu_t::get_trace(std::vector &entries) { return true; } -uc_err emu_t::create_entry(vmp2::v2::entry_t *entry) { +uc_err emu_t::create_entry(vmp2::v2::entry_t* entry) { uc_reg_read(uc_ctx, UC_X86_REG_R15, &entry->regs.r15); uc_reg_read(uc_ctx, UC_X86_REG_R14, &entry->regs.r14); uc_reg_read(uc_ctx, UC_X86_REG_R13, &entry->regs.r13); @@ -375,8 +379,10 @@ uc_err emu_t::create_entry(vmp2::v2::entry_t *entry) { return UC_ERR_OK; } -bool emu_t::code_exec_callback(uc_engine *uc, uint64_t address, uint32_t size, - emu_t *obj) { +bool emu_t::code_exec_callback(uc_engine* uc, + uint64_t address, + uint32_t size, + emu_t* obj) { uc_err err; vmp2::v2::entry_t vinstr_entry; std::uint8_t vm_handler_table_idx = 0u; @@ -388,7 +394,7 @@ bool emu_t::code_exec_callback(uc_engine *uc, uint64_t address, uint32_t size, static thread_local ZydisDecodedInstruction instr; if (!ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(vm::util::g_decoder.get(), - reinterpret_cast(address), + reinterpret_cast(address), PAGE_4KB, &instr))) { std::printf("> failed to decode instruction at = 0x%p\n", address); if ((err = uc_emu_stop(uc))) { @@ -460,7 +466,7 @@ bool emu_t::code_exec_callback(uc_engine *uc, uint64_t address, uint32_t size, return false; } - auto &vm_handler = obj->g_vm_ctx->vm_handlers[vm_handler_table_idx]; + auto& vm_handler = obj->g_vm_ctx->vm_handlers[vm_handler_table_idx]; if ((err = obj->create_entry(&vinstr_entry))) { std::printf("> failed to create vinstr entry... reason = %d\n", err); @@ -491,7 +497,8 @@ bool emu_t::code_exec_callback(uc_engine *uc, uint64_t address, uint32_t size, } if (!vm_handler.profile) { - if (!g_force_emu) obj->cc_block = nullptr; + if (!g_force_emu) + obj->cc_block = nullptr; std::printf("> please define virtual machine handler (%p): \n\n", (vm_handler_addr - obj->g_vm_ctx->module_base) + @@ -500,7 +507,8 @@ bool emu_t::code_exec_callback(uc_engine *uc, uint64_t address, uint32_t size, vm::util::print(vm_handler.instrs); std::printf("\n\n"); - if (!g_force_emu) exit(0); + if (!g_force_emu) + exit(0); } auto vinstr = vm::instrs::get(*obj->g_vm_ctx, vinstr_entry); @@ -627,7 +635,7 @@ bool emu_t::code_exec_callback(uc_engine *uc, uint64_t address, uint32_t size, return true; } -void emu_t::int_callback(uc_engine *uc, std::uint32_t intno, emu_t *obj) { +void emu_t::int_callback(uc_engine* uc, std::uint32_t intno, emu_t* obj) { uc_err err; std::uintptr_t rip = 0ull; static ZydisDecoder decoder; @@ -643,7 +651,7 @@ void emu_t::int_callback(uc_engine *uc, std::uint32_t intno, emu_t *obj) { } if (!ZYAN_SUCCESS(ZydisDecoderDecodeBuffer( - &decoder, reinterpret_cast(rip), PAGE_4KB, &instr))) { + &decoder, reinterpret_cast(rip), PAGE_4KB, &instr))) { std::printf("> failed to decode instruction at = 0x%p\n", rip); if ((err = uc_emu_stop(uc))) { @@ -662,8 +670,12 @@ void emu_t::int_callback(uc_engine *uc, std::uint32_t intno, emu_t *obj) { } } -void emu_t::invalid_mem(uc_engine *uc, uc_mem_type type, uint64_t address, - int size, int64_t value, emu_t *obj) { +void emu_t::invalid_mem(uc_engine* uc, + uc_mem_type type, + uint64_t address, + int size, + int64_t value, + emu_t* obj) { switch (type) { case UC_MEM_READ_UNMAPPED: { uc_mem_map(uc, address & ~0xFFFull, PAGE_4KB, UC_PROT_ALL);