diff --git a/dependencies/vmprofiler b/dependencies/vmprofiler index e58c23c..ffd45ec 160000 --- a/dependencies/vmprofiler +++ b/dependencies/vmprofiler @@ -1 +1 @@ -Subproject commit e58c23c40e13528f5d9b84feb7e23b62a886ed5a +Subproject commit ffd45ecb8a6a6a5d066a9b5e96c878ed9e09e243 diff --git a/src/vmemu_t.cpp b/src/vmemu_t.cpp index e8d40d2..4b288b7 100644 --- a/src/vmemu_t.cpp +++ b/src/vmemu_t.cpp @@ -3,47 +3,19 @@ namespace vm { emu_t::emu_t( std::uint32_t vm_entry_rva, std::uintptr_t image_base, std::uintptr_t module_base ) - : module_base( module_base ), image_base( image_base ), vm_entry_rva( vm_entry_rva ), - vm_handler_table( nullptr ), uc( nullptr ), trace_entries( nullptr ) + : module_base( module_base ), image_base( image_base ), vm_entry_rva( vm_entry_rva ), uc( nullptr ), + code_blocks( nullptr ), vmctx( new vm::ctx_t( module_base, image_base, vm_entry_rva ) ) { } bool emu_t::init() { - // vmprofiler init stuff... - if ( !vm::util::flatten( vm_entry, vm_entry_rva + module_base ) ) - { - std::printf( "[!] failed to get vm entry...\n" ); - return false; - } - - vm::util::deobfuscate( vm_entry ); - vm::util::print( vm_entry ); - - if ( !( vm_handler_table = vm::handler::table::get( vm_entry ) ) ) - { - std::printf( "[!] failed to get vm handler table...\n" ); - return false; - } - - std::printf( "> vm handler table = 0x%p\n", vm_handler_table ); - if ( !vm::handler::get_all( module_base, image_base, vm_entry, vm_handler_table, vm_handlers ) ) - { - std::printf( "[!] failed to get all vm handlers...\n" ); - return false; - } - - std::printf( "> got all vm handlers...\n" ); - for ( const vm::handler::handler_t &vm_handler : vm_handlers ) - std::printf( ">>> handler addr = 0x%p\n", vm_handler.address ); - - // unicorn init stuff... - const auto image_size = NT_HEADER( module_base )->OptionalHeader.SizeOfImage; - + uc_err err; std::uintptr_t stack_base = 0x1000000; std::uintptr_t stack_addr = ( stack_base + ( 0x1000 * 20 ) ) - 0x6000; + const auto rip = module_base + vm_entry_rva; + const auto image_size = NT_HEADER( module_base )->OptionalHeader.SizeOfImage; - uc_err err; if ( ( err = uc_open( UC_ARCH_X86, UC_MODE_64, &uc ) ) ) { std::printf( "failed on uc_mem_map() with error returned %u: %s\n", err, uc_strerror( err ) ); @@ -72,7 +44,7 @@ namespace vm return false; } - if ( ( err = uc_reg_write( uc, UC_X86_REG_RIP, &vm_entry ) ) ) + if ( ( err = uc_reg_write( uc, UC_X86_REG_RIP, &rip ) ) ) { std::printf( "failed on uc_reg_write() with error returned %u: %s\n", err, uc_strerror( err ) ); @@ -108,12 +80,14 @@ namespace vm { if ( uc ) uc_close( uc ); + + delete vmctx; } - bool emu_t::get_trace( std::vector< vmp2::v2::entry_t > &entries ) + bool emu_t::get_trace( std::vector< vm::instrs::code_block_t > &entries ) { // hook_code will fill this vector up with values... - trace_entries = &entries; + code_blocks = &entries; uc_err err; if ( ( err = uc_emu_start( uc, vm_entry_rva + module_base, NULL, NULL, NULL ) ) ) @@ -166,17 +140,15 @@ namespace vm std::printf( ">>> Tracing instruction at 0x%p, instruction size = 0x%x\n", address, size ); // grab JMP RDX/RCX <-- this register... - static const auto jmp_reg = obj->vm_entry[ obj->vm_entry.size() ].instr.operands[ 0 ].reg.value; + static const auto jmp_reg = obj->vmctx->vm_entry[ obj->vmctx->vm_entry.size() ].instr.operands[ 0 ].reg.value; static ZydisDecoder decoder; - static std::once_flag once; static ZydisDecodedInstruction instr; static std::uintptr_t reg_val = 0u; - // init zydis decoder just a single time... - std::call_once( once, [ & ]() -> void { + // init zydis decoder only a single time... + if ( static std::atomic< bool > once = true; once.exchange( false ) ) ZydisDecoderInit( &decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64 ); - } ); if ( ZYAN_SUCCESS( ZydisDecoderDecodeBuffer( &decoder, reinterpret_cast< void * >( address ), size, &instr ) ) && @@ -185,6 +157,7 @@ namespace vm { uc_err err; vmp2::v2::entry_t new_entry; + std::optional< vm::instrs::virt_instr_t > virt_instr; vm::handler::profile_t *vm_handler_profile = nullptr; switch ( jmp_reg ) @@ -206,8 +179,8 @@ namespace vm return vm_handler.address == reg_val; }; - if ( std::find_if( obj->vm_handlers.begin(), obj->vm_handlers.end(), vm_handler_check ) == - obj->vm_handlers.end() ) + if ( std::find_if( obj->vmctx->vm_handlers.begin(), obj->vmctx->vm_handlers.end(), vm_handler_check ) == + obj->vmctx->vm_handlers.end() ) return; if ( ( err = obj->create_entry( &new_entry ) ) ) @@ -217,21 +190,34 @@ namespace vm exit( 0 ); } - if ( ( vm_handler_profile = obj->vm_handlers[ new_entry.handler_idx ].profile ) && - vm_handler_profile->mnemonic == vm::handler::mnemonic_t::JMP ) + // the first virtual instruction we are going to create the first code_block_t... + if ( static std::atomic< bool > once = true; once.exchange( false ) ) + if ( obj->code_blocks->empty() ) + obj->code_blocks->push_back( vm::instrs::code_block_t{ new_entry.vip } ); + + if ( virt_instr = vm::instrs::get( *obj->vmctx, new_entry ); !virt_instr.has_value() ) { - std::printf( "> stopping at virtual jump instruction...\n" ); - std::getchar(); + std::printf( "[!] failed to create vm::instrs::virt_instr_t...\n" ); + + exit( 0 ); } - obj->trace_entries->push_back( new_entry ); + obj->code_blocks->back().vinstrs.push_back( virt_instr.value() ); + + // if there is a virtual JMP instruction then we need to create a new code_block_t... + if ( ( vm_handler_profile = obj->vmctx->vm_handlers[ new_entry.handler_idx ].profile ) && + vm_handler_profile->mnemonic == vm::handler::mnemonic_t::JMP ) + { + const auto code_block_address = + vm::instrs::code_block_addr( *obj->vmctx, new_entry, obj->image_base, obj->module_base ); + + // set the next code block up... + obj->code_blocks->push_back( vm::instrs::code_block_t{ code_block_address } ); + } } else if ( instr.mnemonic == ZYDIS_MNEMONIC_RET ) // finish tracing... { uc_emu_stop( uc ); - - std::printf( "> stopping at vmexit instruction...\n" ); - std::getchar(); } } diff --git a/src/vmemu_t.hpp b/src/vmemu_t.hpp index 8a67fee..a884c2e 100644 --- a/src/vmemu_t.hpp +++ b/src/vmemu_t.hpp @@ -11,45 +11,6 @@ namespace vm { - struct virt_instr_t - { - vm::handler::mnemonic_t mnemonic_t; - std::uint8_t opcode; // aka vm handler idx... - - struct - { - bool has_imm; - struct - { - std::uint8_t imm_size; // size in bits... - union - { - std::int64_t s; - std::uint64_t u; - }; - } imm; - } operand; - }; - - enum class jcc_type - { - none, - branching, - absolute - }; - - struct code_block_t - { - struct - { - bool has_jcc; - jcc_type type; - std::uint32_t branch_rva[ 2 ]; - } jcc; - - std::vector< virt_instr_t > vinstrs; - }; - class emu_t { using callback_t = std::function< void( uc_engine *, uint64_t, uint32_t, void * ) >; @@ -59,7 +20,7 @@ namespace vm ~emu_t(); bool init(); - bool get_trace( std::vector< vmp2::v2::entry_t > &entries ); + bool get_trace( std::vector< vm::instrs::code_block_t > &entries ); private: uc_err create_entry( vmp2::v2::entry_t *entry ); @@ -73,9 +34,7 @@ namespace vm std::uintptr_t image_base, module_base; std::uint32_t vm_entry_rva; - zydis_routine_t vm_entry; - std::uintptr_t *vm_handler_table; - std::vector< vm::handler::handler_t > vm_handlers; - std::vector< vmp2::v2::entry_t > *trace_entries; + vm::ctx_t* vmctx; + std::vector< vm::instrs::code_block_t > *code_blocks; }; } // namespace vm \ No newline at end of file