#include #include #include #include #include using namespace llvm; int main( int argc, const char *argv[] ) { argparse::argument_parser_t parser( "vmdevirt", "virtual instruction pseudo code generator" ); parser.add_argument().name( "--vmp2file" ).required( true ).description( "path to .vmp2 file..." ); 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; } std::vector< std::uint8_t > vmp2file; const auto umtils = xtils::um_t::get_instance(); if ( !umtils->open_binary_file( parser.get< std::string >( "vmp2file" ), vmp2file ) ) { std::printf( "[!] failed to open vmp2 file...\n" ); return -1; } const auto file_header = reinterpret_cast< vmp2::v3::file_header * >( vmp2file.data() ); if ( file_header->version != vmp2::version_t::v3 ) { 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 ); std::vector< vm::instrs::code_block_t > vmp_code_blocks; // convert code blocks back to vm::instrs::code_block_t form... 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 ) { vm::instrs::code_block_t _code_block{ code_block->vip_begin, code_block->jcc }; std::for_each( code_block->vinstr, code_block->vinstr + code_block->vinstr_count, [ & ]( const vm::instrs::virt_instr_t &vinstr ) { _code_block.vinstrs.push_back( vinstr ); } ); vmp_code_blocks.push_back( _code_block ); } LLVMContext llvm_ctx; Module llvm_module( "VMProtect 2 Static Devirtualizer", llvm_ctx ); vm::vmp_rtn_t vmp_rtn( &llvm_ctx, &llvm_module, first_block->vip_begin, vmp_code_blocks ); }