From 50574c1b9da0ed2e71336a00c20ab786534fbb37 Mon Sep 17 00:00:00 2001 From: _xeroxz <_xeroxz@back.engineer> Date: Tue, 30 Nov 2021 18:52:09 -0800 Subject: [PATCH] added --findentries to find all vm enters... shit works... --- dependencies/vmprofiler | 2 +- src/main.cpp | 406 ++++++++++++++++++++++++++-------------- 2 files changed, 266 insertions(+), 142 deletions(-) diff --git a/dependencies/vmprofiler b/dependencies/vmprofiler index 300eed7..ade6b0f 160000 --- a/dependencies/vmprofiler +++ b/dependencies/vmprofiler @@ -1 +1 @@ -Subproject commit 300eed7a62afb0e57056afef1d243092e9667533 +Subproject commit ade6b0fdd77d43c06bab255011675dffce1507ab diff --git a/src/main.cpp b/src/main.cpp index 7583dd0..7395cad 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,177 +1,301 @@ #include + +#include +#include #include #include #include -#include - #include -#include #include -auto open_binary_file( const std::string &file, std::vector< uint8_t > &data ) -> bool -{ - std::ifstream fstr( file, std::ios::binary ); +auto open_binary_file(const std::string &file, std::vector &data) + -> bool { + std::ifstream fstr(file, std::ios::binary); - if ( !fstr.is_open() ) - return false; + if (!fstr.is_open()) return false; - fstr.unsetf( std::ios::skipws ); - fstr.seekg( 0, std::ios::end ); + fstr.unsetf(std::ios::skipws); + fstr.seekg(0, std::ios::end); - const auto file_size = fstr.tellg(); + const auto file_size = fstr.tellg(); - fstr.seekg( NULL, std::ios::beg ); - data.reserve( static_cast< uint32_t >( file_size ) ); - data.insert( data.begin(), std::istream_iterator< uint8_t >( fstr ), std::istream_iterator< uint8_t >() ); - return true; + fstr.seekg(NULL, std::ios::beg); + data.reserve(static_cast(file_size)); + data.insert(data.begin(), std::istream_iterator(fstr), + std::istream_iterator()); + return true; } -int __cdecl main( int argc, const char *argv[] ) -{ - 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..." ); - parser.add_argument().name( "--showhandler" ).description( "show a specific vm handler given its index..." ); - parser.add_argument().name( "--indexes" ).description( "displays vm handler table indexes for a given vm handler name such as 'READQ', or 'WRITEQ'..." ); - - parser.enable_help(); - auto err = parser.parse( argc, argv ); - - if ( err ) - { - std::cout << err << std::endl; - return -1; +int __cdecl main(int argc, const char *argv[]) { + 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..."); + parser.add_argument() + .name("--showhandler") + .description("show a specific vm handler given its index..."); + parser.add_argument() + .name("--indexes") + .description( + "displays vm handler table indexes for a given vm handler name such " + "as 'READQ', or 'WRITEQ'..."); + parser.add_argument() + .name("--findentries") + .description( + "finds all virtual machine entries and displays information for " + "them..."); + + parser.enable_help(); + auto err = parser.parse(argc, argv); + + if (err) { + std::cout << err << std::endl; + return -1; + } + + if (parser.exists("help")) { + parser.print_help(); + return 0; + } + + if (parser.exists("bin")) { + if (!std::filesystem::exists(parser.get("bin"))) { + std::printf( + "> path to protected file is invalid... check your cli args...\n"); + return -1; } - if ( parser.exists( "help" ) ) - { - parser.print_help(); - return 0; + std::vector module_data, tmp; + if (!open_binary_file(parser.get("bin"), module_data)) { + std::printf("[!] failed to open binary = %s\n", + parser.get("bin").c_str()); + return -1; } - if ( parser.exists( "bin" ) && parser.exists( "vmentry" ) ) - { - if ( !std::filesystem::exists( parser.get< std::string >( "bin" ) ) ) - { - std::printf( "> path to protected file is invalid... check your cli args...\n" ); - return -1; + auto img = reinterpret_cast *>(module_data.data()); + auto image_size = img->get_nt_headers()->optional_header.size_image; + + tmp.resize(image_size); + std::memcpy(tmp.data(), 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) { + std::memcpy( + tmp.data() + section_header.virtual_address, + module_data.data() + section_header.ptr_raw_data, + section_header.size_raw_data); + }); + + const auto module_base = reinterpret_cast(tmp.data()); + const auto image_base = img->get_nt_headers()->optional_header.image_base; + + if (parser.exists("vmentry")) { + const auto vm_entry_rva = std::strtoull( + parser.get("vmentry").c_str(), nullptr, 16); + + std::printf( + "> module base = %p, image base = %p, image size = %p, vm entry = " + "0x%x\n", + module_base, image_base, image_size, vm_entry_rva); + + vm::ctx_t vmctx(module_base, image_base, image_size, vm_entry_rva); + + if (!vmctx.init()) { + std::printf( + "[!] failed to init vm::ctx_t... make sure all cli arguments are " + "correct!\n"); + return -1; + } + + std::puts( + "======================== [vm entry] ========================\n"); + + std::for_each(vmctx.vm_entry.begin(), vmctx.vm_entry.end(), + [&](zydis_instr_t &instr) { + instr.addr -= module_base; + instr.addr += image_base; + }); + + vm::util::print(vmctx.vm_entry); + std::puts( + "======================== [calc jmp] ========================\n"); + + std::for_each(vmctx.calc_jmp.begin(), vmctx.calc_jmp.end(), + [&](zydis_instr_t &instr) { + instr.addr -= module_base; + instr.addr += image_base; + }); + std::puts( + "============================================================\n"); + std::printf("> vip advancement = %s\n\n", + vmctx.exec_type == vmp2::exec_type_t::forward ? "forward" + : "backward"); + + if (parser.exists("showhandlers")) { + for (auto idx = 0u; idx < vmctx.vm_handlers.size(); ++idx) { + std::printf( + "======================== [%s #%d] ========================\n", + vmctx.vm_handlers[idx].profile + ? vmctx.vm_handlers[idx].profile->name + : "UNK", + idx); + + vm::util::print(vmctx.vm_handlers[idx].instrs); + + // if there is no imm then there are no transforms... + if (!vmctx.vm_handlers[idx].imm_size) { + std::puts("\n"); + continue; + } + + std::puts( + "======================== [transforms] " + "========================\n"); + for (auto &[mnemonic, instr] : vmctx.vm_handlers[idx].transforms) { + if (instr.mnemonic == ZYDIS_MNEMONIC_INVALID) continue; + + vm::util::print(instr); + } + std::puts("\n"); } + } + if (parser.exists("showhandler")) { + const auto vm_handler_idx = std::strtoul( + parser.get("showhandler").c_str(), nullptr, 10); - std::vector module_data, tmp; - if(!open_binary_file(parser.get< std::string >( "bin" ), module_data)) - { - std::printf("[!] failed to open binary = %s\n", parser.get< std::string >( "bin" ).c_str()); - return -1; + if (vm_handler_idx > 256) { + std::printf("> invalid vm handler index... too large...\n"); + return -1; } - auto img = reinterpret_cast*>(module_data.data()); - auto image_size = img->get_nt_headers()->optional_header.size_image; - - tmp.resize(image_size); - std::memcpy(tmp.data(), 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& section_header) - { - std::memcpy(tmp.data() + section_header.virtual_address, - module_data.data() + section_header.ptr_raw_data, - section_header.size_raw_data); - }); - - const auto module_base = reinterpret_cast(tmp.data()); - const auto vm_entry_rva = std::strtoull( parser.get< std::string >( "vmentry" ).c_str(), nullptr, 16 ); - const auto image_base = img->get_nt_headers()->optional_header.image_base; - - std::printf( "> module base = %p, image base = %p, image size = %p, vm entry = 0x%x\n", module_base, image_base, - image_size, vm_entry_rva ); - - vm::ctx_t vmctx( module_base, image_base, image_size, vm_entry_rva ); - - if ( !vmctx.init() ) - { - std::printf( "[!] failed to init vm::ctx_t... make sure all cli arguments are correct!\n" ); - return -1; + std::printf( + "======================== [%s #%d] ========================\n", + vmctx.vm_handlers[vm_handler_idx].profile + ? vmctx.vm_handlers[vm_handler_idx].profile->name + : "UNK", + vm_handler_idx); + + vm::util::print(vmctx.vm_handlers[vm_handler_idx].instrs); + + // if there is no imm then there are no transforms... + if (!vmctx.vm_handlers[vm_handler_idx].imm_size) { + std::puts("\n"); + return {}; } - std::puts( "======================== [vm entry] ========================\n" ); - vm::util::print( vmctx.vm_entry ); - std::puts( "======================== [calc jmp] ========================\n" ); - vm::util::print( vmctx.calc_jmp ); - std::puts( "============================================================\n" ); - std::printf( "> vip advancement = %s\n\n", - vmctx.exec_type == vmp2::exec_type_t::forward ? "forward" : "backward" ); - - if ( parser.exists( "showhandlers" ) ) - { - for ( auto idx = 0u; idx < vmctx.vm_handlers.size(); ++idx ) - { - std::printf( "======================== [%s #%d] ========================\n", - vmctx.vm_handlers[ idx ].profile ? vmctx.vm_handlers[ idx ].profile->name : "UNK", idx ); - - vm::util::print( vmctx.vm_handlers[ idx ].instrs ); - - // if there is no imm then there are no transforms... - if ( !vmctx.vm_handlers[ idx ].imm_size ) - { - std::puts( "\n" ); - continue; - } - - std::puts( "======================== [transforms] ========================\n" ); - for ( auto &[ mnemonic, instr ] : vmctx.vm_handlers[ idx ].transforms ) - { - if ( instr.mnemonic == ZYDIS_MNEMONIC_INVALID ) - continue; - - vm::util::print( instr ); - } - std::puts( "\n" ); - } + std::puts( + "======================== [transforms] ========================\n"); + + for (auto &[mnemonic, instr] : + vmctx.vm_handlers[vm_handler_idx].transforms) { + if (instr.mnemonic == ZYDIS_MNEMONIC_INVALID) continue; + + vm::util::print(instr); } - else if ( parser.exists( "showhandler" ) ) - { - const auto vm_handler_idx = std::strtoul( parser.get< std::string >( "showhandler" ).c_str(), nullptr, 10 ); - - if ( vm_handler_idx > 256 ) - { - std::printf( "> invalid vm handler index... too large...\n" ); - return -1; - } + std::puts("\n"); + } + + if (parser.exists("indexes")) { + const auto handler_name = parser.get("indexes"); + std::printf("{\n"); + for (auto idx = 0u; idx < vmctx.vm_handlers.size(); ++idx) + if (vmctx.vm_handlers[idx].profile && + !strcmp(vmctx.vm_handlers[idx].profile->name, + handler_name.c_str())) + std::printf("\t0x%x,\n", idx); + std::printf("}\n"); + } + } + if (parser.exists("findentries")) { + std::printf("> scanning for all entries...\n"); + const auto entries = vm::locate::get_vm_entries(module_base, image_size); + std::printf("> number of entries located = %d\n", entries.size()); + + for (const auto &vm_enter : entries) { + vm::ctx_t vmctx(module_base, image_base, image_size, vm_enter.rva); + + if (!vmctx.init()) { + std::printf( + "[!] failed to init vm::ctx_t... make sure all cli arguments are " + "correct!\n"); + return -1; + } + + std::puts( + "======================== [vm entry] ========================\n"); + + std::for_each(vmctx.vm_entry.begin(), vmctx.vm_entry.end(), + [&](zydis_instr_t &instr) { + instr.addr -= module_base; + instr.addr += image_base; + }); - std::printf( "======================== [%s #%d] ========================\n", - vmctx.vm_handlers[ vm_handler_idx ].profile ? vmctx.vm_handlers[ vm_handler_idx ].profile->name - : "UNK", - vm_handler_idx ); + vm::util::print(vmctx.vm_entry); + std::puts( + "======================== [calc jmp] ========================\n"); - vm::util::print( vmctx.vm_handlers[ vm_handler_idx ].instrs ); + std::for_each(vmctx.calc_jmp.begin(), vmctx.calc_jmp.end(), + [&](zydis_instr_t &instr) { + instr.addr -= module_base; + instr.addr += image_base; + }); + + vm::util::print(vmctx.calc_jmp); + std::puts( + "============================================================\n"); + + std::printf("> vip advancement = %s\n\n", + vmctx.exec_type == vmp2::exec_type_t::forward ? "forward" + : "backward"); + + if (parser.exists("showhandlers")) { + for (auto idx = 0u; idx < vmctx.vm_handlers.size(); ++idx) { + std::printf( + "======================== [%s #%d] ========================\n", + vmctx.vm_handlers[idx].profile + ? vmctx.vm_handlers[idx].profile->name + : "UNK", + idx); + + vm::util::print(vmctx.vm_handlers[idx].instrs); // if there is no imm then there are no transforms... - if ( !vmctx.vm_handlers[ vm_handler_idx ].imm_size ) - { - std::puts( "\n" ); - return {}; + if (!vmctx.vm_handlers[idx].imm_size) { + std::puts("\n"); + continue; } - std::puts( "======================== [transforms] ========================\n" ); - for ( auto &[ mnemonic, instr ] : vmctx.vm_handlers[ vm_handler_idx ].transforms ) - { - if ( instr.mnemonic == ZYDIS_MNEMONIC_INVALID ) - continue; + std::puts( + "======================== [transforms] " + "========================\n"); + for (auto &[mnemonic, instr] : vmctx.vm_handlers[idx].transforms) { + if (instr.mnemonic == ZYDIS_MNEMONIC_INVALID) continue; - vm::util::print( instr ); + vm::util::print(instr); } - std::puts( "\n" ); + std::puts("\n"); + } } - else if ( parser.exists( "indexes" ) ) - { - const auto handler_name = parser.get< std::string >( "indexes" ); - std::printf( "{\n" ); - for ( auto idx = 0u; idx < vmctx.vm_handlers.size(); ++idx ) - if ( vmctx.vm_handlers[ idx ].profile && - !strcmp( vmctx.vm_handlers[ idx ].profile->name, handler_name.c_str() ) ) - std::printf( "\t0x%x,\n", idx ); - std::printf( "}\n" ); + + if (parser.exists("indexes")) { + const auto handler_name = parser.get("indexes"); + std::printf("{\n"); + for (auto idx = 0u; idx < vmctx.vm_handlers.size(); ++idx) + if (vmctx.vm_handlers[idx].profile && + !strcmp(vmctx.vm_handlers[idx].profile->name, + handler_name.c_str())) + std::printf("\t0x%x,\n", idx); + std::printf("}\n"); } + } } + } } \ No newline at end of file