From 9b05ac43e602d85b46c9f82d50c57204acd1d81d Mon Sep 17 00:00:00 2001 From: _xeroxz <_xeroxz@back.engineer> Date: Sat, 4 Dec 2021 16:55:19 -0800 Subject: [PATCH] project is now multi-threaded --- dependencies/vmprofiler | 2 +- src/main.cpp | 71 +++++++++++++++++++++++++---------------- src/vmemu_t.cpp | 10 +++--- 3 files changed, 50 insertions(+), 33 deletions(-) diff --git a/dependencies/vmprofiler b/dependencies/vmprofiler index 8779ab1..eed2472 160000 --- a/dependencies/vmprofiler +++ b/dependencies/vmprofiler @@ -1 +1 @@ -Subproject commit 8779ab1160b541cc8e0d4862aee66d075bfb2362 +Subproject commit eed247229fa832c2d2a1486e5467a129ce10debb diff --git a/src/main.cpp b/src/main.cpp index 449839a..a3cce1f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,13 @@ #include #include #include +#include #include "unpacker.hpp" #include "vmemu_t.hpp" +#define NUM_THREADS 20 + int __cdecl main(int argc, const char *argv[]) { argparse::argument_parser_t parser("VMEmu", "VMProtect 2 VM Handler Emulator"); @@ -92,8 +95,6 @@ int __cdecl main(int argc, const char *argv[]) { case win::reloc_type_id::rel_based_dir64: { auto reloc_at = reinterpret_cast( entry.offset + reloc_block->base_rva + module_base); - std::printf("> handling reloc at = %x\n", - entry.offset + reloc_block->base_rva); *reloc_at = module_base + ((*reloc_at) - image_base); break; } @@ -144,7 +145,6 @@ int __cdecl main(int argc, const char *argv[]) { } std::printf("> number of blocks = %d\n", code_blocks.size()); - 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", @@ -280,39 +280,56 @@ int __cdecl main(int argc, const char *argv[]) { std::pair > > virt_rtns; + std::vector threads; for (const auto &[vm_enter_offset, encrypted_rva, hndlr_tble] : entries) { - std::printf("> emulating vm enter at rva = 0x%x\n", vm_enter_offset); - vm::ctx_t vm_ctx(module_base, image_base, image_size, vm_enter_offset); - - if (!vm_ctx.init()) { - std::printf( - "[!] failed to init vmctx... this can be for many reasons..." - " try validating your vm entry rva... make sure the binary is " - "unpacked and is" - "protected with VMProtect 2...\n"); - return -1; + if (threads.size() == NUM_THREADS) { + std::for_each(threads.begin(), threads.end(), + [&](std::thread &t) { t.join(); }); + threads.clear(); } - vm::emu_t emu(&vm_ctx); + threads.emplace_back(std::thread([vm_enter_offset = vm_enter_offset, + module_base = module_base, + image_base = image_base, + image_size = image_size, + &virt_rtns = virt_rtns]() { + std::printf("> emulating vm enter at rva = 0x%x\n", vm_enter_offset); + vm::ctx_t vm_ctx(module_base, image_base, image_size, vm_enter_offset); + + if (!vm_ctx.init()) { + std::printf( + "[!] failed to init vmctx... this can be for many reasons..." + " try validating your vm entry rva... make sure the binary is " + "unpacked and is" + "protected with VMProtect 2...\n"); + return; + } - if (!emu.init()) { - std::printf("[!] failed to init emulator...\n"); - return -1; - } + vm::emu_t emu(&vm_ctx); - std::vector code_blocks; + if (!emu.init()) { + std::printf("[!] failed to init emulator...\n"); + return; + } - if (!emu.get_trace(code_blocks)) { - std::printf( - "[!] something failed during tracing, review the console for more " - "information...\n"); - continue; - } + std::vector code_blocks; + + if (!emu.get_trace(code_blocks)) { + std::printf( + "[!] something failed during tracing, review the console for " + "more " + "information...\n"); + return; + } - std::printf("> number of blocks = %d\n", code_blocks.size()); - virt_rtns.push_back({vm_enter_offset, code_blocks}); + std::printf("> number of blocks = %d\n", code_blocks.size()); + virt_rtns.push_back({vm_enter_offset, code_blocks}); + })); } + std::for_each(threads.begin(), threads.end(), + [&](std::thread &t) { t.join(); }); + std::printf("> traced %d virtual routines...\n", virt_rtns.size()); std::printf("> serializing results....\n"); diff --git a/src/vmemu_t.cpp b/src/vmemu_t.cpp index 3f52fb8..1003d00 100644 --- a/src/vmemu_t.cpp +++ b/src/vmemu_t.cpp @@ -382,16 +382,15 @@ bool emu_t::code_exec_callback(uc_engine *uc, uint64_t address, uint32_t size, std::uint8_t vm_handler_table_idx = 0u; std::uintptr_t vm_handler_addr; - static std::shared_ptr _jmp_ctx; - static zydis_routine_t _jmp_stream; - static auto inst_cnt = 0ull; - static ZydisDecodedInstruction instr; + static thread_local std::shared_ptr _jmp_ctx; + static thread_local zydis_routine_t _jmp_stream; + static thread_local auto inst_cnt = 0ull; + static thread_local ZydisDecodedInstruction instr; if (!ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(vm::util::g_decoder.get(), reinterpret_cast(address), PAGE_4KB, &instr))) { std::printf("> failed to decode instruction at = 0x%p\n", address); - if ((err = uc_emu_stop(uc))) { std::printf("> failed to stop emulation, exiting... reason = %d\n", err); exit(0); @@ -408,6 +407,7 @@ bool emu_t::code_exec_callback(uc_engine *uc, uint64_t address, uint32_t size, // if there are over 4k instructions executed before a JMP is found then we // are gunna stop emulation this is a sanity check to prevent inf loops... if (++inst_cnt > 0x1000) { + std::printf("> inf loop detected... stopping emulation...\n"); obj->cc_block = nullptr, inst_cnt = 0ull; uc_emu_stop(uc); return false;