diff --git a/cmake.toml b/cmake.toml index 121a501..bd7926e 100644 --- a/cmake.toml +++ b/cmake.toml @@ -2,13 +2,14 @@ name = "vmprofiler-cli" [subdir.dependencies] - [target.vmprofiler-cli] type = "executable" + sources = [ "src/main.cpp", "src/icon.rc" ] + link-libraries = [ "cli-parser", "xtils", diff --git a/dependencies/vmprofiler b/dependencies/vmprofiler index 16aeb2d..be14462 160000 --- a/dependencies/vmprofiler +++ b/dependencies/vmprofiler @@ -1 +1 @@ -Subproject commit 16aeb2d6d48c4822b89497ad660911eb0f5e54bd +Subproject commit be144629075d10eceebbea30361d1b6c96512c01 diff --git a/src/main.cpp b/src/main.cpp index 4218f1a..842489c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,8 +9,7 @@ int __cdecl main( int argc, const char *argv[] ) { - argparse::argument_parser_t parser( "vmprofiler-cli", "virtual instruction pseudo code generator" ); - + argparse::argument_parser_t parser( "vmprofiler-cli", "virtual machine information inspector" ); parser.add_argument().names( { "--bin", "--vmpbin" } ).description( "unpacked binary protected with VMProtect 2" ); parser.add_argument().names( { "--vmentry", "--entry" } ).description( "rva to push prior to a vm_entry" ); parser.add_argument().name( "--showhandlers" ).description( "show all vm handlers..." ); @@ -23,9 +22,12 @@ int __cdecl main( int argc, const char *argv[] ) .name( "--scanfortables" ) .description( "scans all executable sections for vm handler tables..." ); parser.add_argument() - .name( "--showblockinstrs" ) - .description( "show the virtual instructions of a specific code block..." ); - parser.add_argument().name( "--showallblocks" ).description( "shows all information for all code blocks..." ); + .name( "--showvirtinstrs" ) + .description( "show the virtual instructions of a specific virtual routine..." ); + parser.add_argument().name( "--showallrtns" ).description( "shows all information for all virtual routines..." ); + parser.add_argument() + .name( "--rtnaddr" ) + .description( "rva of the virtualized routine to apply another action upon such as --showallblocks..." ); parser.enable_help(); auto err = parser.parse( argc, argv ); @@ -186,77 +188,83 @@ int __cdecl main( int argc, const char *argv[] ) return -1; } - const auto file_header = reinterpret_cast< vmp2::v3::file_header * >( vmp2file.data() ); + const auto file_header = reinterpret_cast< vmp2::v4::file_header * >( vmp2file.data() ); - if ( file_header->version != vmp2::version_t::v3 ) + if ( file_header->version != vmp2::version_t::v4 ) { std::printf( "[!] invalid vmp2 file version... this build uses v3...\n" ); return -1; } - auto first_block = reinterpret_cast< vmp2::v3::code_block_t * >( reinterpret_cast< std::uintptr_t >( file_header ) + - file_header->code_block_offset ); + auto first_rtn = reinterpret_cast< vmp2::v4::rtn_t * >( reinterpret_cast< std::uintptr_t >( file_header ) + + file_header->rtn_offset ); - if ( parser.exists( "showallblocks" ) ) + if ( parser.exists( "showallrtns" ) ) { - for ( auto [ code_block, code_block_num ] = std::tuple{ first_block, 0u }; - code_block_num < file_header->code_block_count; - code_block = reinterpret_cast< vmp2::v3::code_block_t * >( - reinterpret_cast< std::uintptr_t >( code_block ) + code_block->next_block_offset ), - ++code_block_num ) + for ( auto [ rtn_block, rtn_idx ] = std::pair{ first_rtn, 0ull }; rtn_idx < file_header->rtn_count; + ++rtn_idx, rtn_block = reinterpret_cast< vmp2::v4::rtn_t * >( + reinterpret_cast< std::uintptr_t >( rtn_block ) + rtn_block->size ) ) { + std::printf( "[rtn_0x%p] number of code blocks = %d\n", rtn_block->code_blocks[ 0 ].vip_begin, + rtn_block->code_block_count ); - std::printf( "[code block #%d] begin = 0x%p, virtual instruction count = %d\n", code_block_num, - ABS_TO_IMG( code_block->vip_begin, file_header->module_base, file_header->image_base ), - code_block->vinstr_count ); - - if ( code_block->jcc.has_jcc ) - std::printf( - "\tcode block branches to 0x%p and 0x%p\n", - ABS_TO_IMG( code_block->jcc.block_addr[ 0 ], file_header->module_base, file_header->image_base ), - ABS_TO_IMG( code_block->jcc.block_addr[ 1 ], file_header->module_base, file_header->image_base ) ); + for ( auto [ code_block, block_idx ] = std::pair{ &rtn_block->code_blocks[ 0 ], 0ull }; + block_idx < rtn_block->code_block_count; + ++block_idx, code_block = reinterpret_cast< vmp2::v4::code_block_t * >( + reinterpret_cast< std::uintptr_t >( code_block ) + code_block->next_block_offset ) ) + { + std::printf( " [blk_0x%p] number of virtual instructions = %d\n", code_block->vip_begin, + code_block->vinstr_count ); + } } } - if ( parser.exists( "showblockinstrs" ) ) + if ( parser.exists( "showvirtinstrs" ) && parser.exists( "rtnaddr" ) ) { - const auto block_img_addr = parser.get< std::string >( "showblockinstrs" ); - - for ( auto [ code_block, code_block_num ] = std::tuple{ first_block, 0u }; - code_block_num < file_header->code_block_count; - code_block = reinterpret_cast< vmp2::v3::code_block_t * >( - reinterpret_cast< std::uintptr_t >( code_block ) + code_block->next_block_offset ), - ++code_block_num ) + auto rtn_addr = std::stoull( parser.get< std::string >( "rtnaddr" ).c_str(), nullptr, 16 ); + for ( auto [ rtn_block, rtn_idx ] = std::pair{ first_rtn, 0ull }; rtn_idx < file_header->rtn_count; + ++rtn_idx, rtn_block = reinterpret_cast< vmp2::v4::rtn_t * >( + reinterpret_cast< std::uintptr_t >( rtn_block ) + rtn_block->size ) ) { - if ( ABS_TO_IMG( code_block->vip_begin, file_header->module_base, file_header->image_base ) == - std::strtoull( block_img_addr.c_str(), nullptr, 16 ) ) + if ( rtn_block->code_blocks[ 0 ].vip_begin == rtn_addr ) { - std::printf( "[code block #%d] begin = 0x%p, virtual instruction count = %d\n", code_block_num, - ABS_TO_IMG( code_block->vip_begin, file_header->module_base, file_header->image_base ), - code_block->vinstr_count ); - - std::printf( "> -----------------------------------------------------------------------\n" ); - std::printf( "> opcode | virtual instructions | virtual instruction pointer\n" ); - std::printf( "> -----------------------------------------------------------------------\n" ); - for ( auto idx = 0u; idx < code_block->vinstr_count; ++idx ) + for ( auto [ code_block, block_idx ] = std::pair{ &rtn_block->code_blocks[ 0 ], 0ull }; + block_idx < rtn_block->code_block_count; + ++block_idx, code_block = reinterpret_cast< vmp2::v4::code_block_t * >( + reinterpret_cast< std::uintptr_t >( code_block ) + + code_block->next_block_offset ) ) { - const auto vinstr = &code_block->vinstr[ idx ]; - const auto vm_profile = vm::handler::get_profile( vinstr->mnemonic_t ); - if ( vinstr->operand.has_imm ) - { - std::printf( - "> %-6x | %-15s %-15p | 0x%p\n", vinstr->opcode, vm_profile ? vm_profile->name : "UNK", - vinstr->operand.imm.u, - ABS_TO_IMG( vinstr->trace_data.vip, file_header->module_base, file_header->image_base ) ); - } - else + std::printf( "[blk_0x%p] number of virtual instructions = %d\n", code_block->vip_begin, + code_block->vinstr_count ); + + std::printf( "> -----------------------------------------------------------------------\n" ); + std::printf( "> opcode | virtual instructions | virtual instruction pointer\n" ); + std::printf( "> -----------------------------------------------------------------------\n" ); + + auto block_vinstrs = reinterpret_cast< vm::instrs::virt_instr_t * >( + reinterpret_cast< std::uintptr_t >( code_block ) + sizeof vmp2::v4::code_block_t + + ( code_block->num_block_addrs * 8 ) ); + + for ( auto idx = 0u; idx < code_block->vinstr_count; ++idx ) { - std::printf( - "> %-6x | %-32s | 0x%p\n", vinstr->opcode, vm_profile ? vm_profile->name : "UNK", - ABS_TO_IMG( vinstr->trace_data.vip, file_header->module_base, file_header->image_base ) ); + const auto vinstr = &block_vinstrs[ idx ]; + const auto vm_profile = vm::handler::get_profile( vinstr->mnemonic_t ); + if ( vinstr->operand.has_imm ) + { + std::printf( "> %-6x | %-15s %-15p | 0x%p\n", vinstr->opcode, + vm_profile ? vm_profile->name : "UNK", vinstr->operand.imm.u, + ABS_TO_IMG( vinstr->trace_data.vip, file_header->module_base, + file_header->image_base ) ); + } + else + { + std::printf( "> %-6x | %-32s | 0x%p\n", vinstr->opcode, + vm_profile ? vm_profile->name : "UNK", + ABS_TO_IMG( vinstr->trace_data.vip, file_header->module_base, + file_header->image_base ) ); + } } } - break; } } }