From 2d16994d54c5605f2681badde1e7ef439d50eab6 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Thu, 3 Jun 2021 19:17:58 -0700 Subject: [PATCH] still working on it, just cleaned the code some more... --- .../framelesswindow/framelesswindow.ui | 6 +- src/qvminspector.cpp | 107 +++++++++++++----- src/qvminspector.h | 1 + src/qvminspector.ui | 2 +- 4 files changed, 86 insertions(+), 30 deletions(-) diff --git a/src/DarkStyle/framelesswindow/framelesswindow.ui b/src/DarkStyle/framelesswindow/framelesswindow.ui index fd6fe72..a98d7ae 100644 --- a/src/DarkStyle/framelesswindow/framelesswindow.ui +++ b/src/DarkStyle/framelesswindow/framelesswindow.ui @@ -6,8 +6,8 @@ 0 0 - 1410 - 1048 + 1484 + 983 @@ -143,7 +143,7 @@ color:rgb(153,153,153); - VMProtect 2 - Virtual Instruction Inspector (v1.5) + VMProtect 2 - Virtual Instruction Inspector (v1.6 BETA) Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter diff --git a/src/qvminspector.cpp b/src/qvminspector.cpp index 40c0add..7ceda64 100644 --- a/src/qvminspector.cpp +++ b/src/qvminspector.cpp @@ -3,9 +3,9 @@ qvminspector_t::qvminspector_t( qwidget_t *parent ) : qmain_window_t( parent ), file_header( nullptr ), vmctx( nullptr ) { ui.setupUi( this ); - ui.virt_instrs->setColumnWidth( 0, 100 ); - ui.virt_instrs->setColumnWidth( 1, 125 ); - ui.virt_instrs->setColumnWidth( 2, 250 ); + ui.virt_instrs->setColumnWidth( 0, 115 ); + ui.virt_instrs->setColumnWidth( 1, 140 ); + ui.virt_instrs->setColumnWidth( 2, 200 ); ui.virt_instrs->setColumnWidth( 3, 200 ); connect( ui.action_open, &QAction::triggered, this, &qvminspector_t::on_open ); @@ -55,7 +55,7 @@ void qvminspector_t::on_open() qfile_t open_file( file_path ); file_header = reinterpret_cast< vmp2::v3::file_header * >( malloc( file_size ) ); - dbg_msg( QString( "loading vmp2 file %1..." ).arg( file_path ) ); + dbg_msg( qstring_t( "loading vmp2 file %1..." ).arg( file_path ) ); if ( !open_file.open( QIODevice::ReadOnly ) ) { @@ -81,9 +81,9 @@ void qvminspector_t::dbg_print( qstring_t dbg_output ) void qvminspector_t::dbg_msg( qstring_t dbg_output ) { - QMessageBox MsgBox; - MsgBox.setText( dbg_output ); - MsgBox.exec(); + qmsg_box_t msg_box; + msg_box.setText( dbg_output ); + msg_box.exec(); dbg_print( dbg_output ); } @@ -91,12 +91,12 @@ bool qvminspector_t::init_data() { if ( file_header->magic != VMP_MAGIC ) { - dbg_msg( "invalid magic bytes for vmp2 file...\n" ); + dbg_msg( "invalid magic bytes for vmp2 file..." ); return false; } - dbg_print( "valid magic bytes for vmp2 file...\n" ); + dbg_print( "valid magic bytes for vmp2 file..." ); if ( file_header->version != vmp2::version_t::v3 ) { @@ -111,36 +111,91 @@ bool qvminspector_t::init_data() module_base = reinterpret_cast< std::uintptr_t >( file_header ) + file_header->module_offset; vmctx = new vm::ctx_t( module_base, image_base, image_base, vm_entry_rva ); + + if ( !vmctx->init() ) + { + dbg_msg( "failed to init vm::ctx_t... this can happen for many reasons..." + "ensure that the vmp2 file is not corrupted...\n" ); + + return false; + } + first_block = reinterpret_cast< vmp2::v3::code_block_t * >( reinterpret_cast< std::uintptr_t >( file_header ) + file_header->code_block_offset ); - - dbg_print( "> vm entry displayed below...\n" ); - vm::util::print( vmctx->vm_entry ); return true; } void qvminspector_t::update_ui() { - - const auto end_code_blocks = reinterpret_cast< std::uintptr_t >( first_block ) + - ( file_header->code_block_count * sizeof vmp2::v3::code_block_t ) + - file_header->module_size + sizeof vmp2::v3::file_header; - // for each code block insert their virtual instructions // into the virtual instruction tree... also put meta data about the code // block above the virtual instructions... if the code block has a JCC (with two branches) // then make a child repeating this for loop... - for ( auto [ code_block, idx ] = std::tuple{ first_block, 0u }; idx < file_header->code_block_count; + 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 ), ++idx) + code_block->next_block_offset ), + ++code_block_num ) { - auto blank_entry1 = new qtree_widget_item_t(), blank_entry2 = new qtree_widget_item_t(), - meta_data_entry = new qtree_widget_item_t(); - - dbg_msg( QString( "> number of vinstrs = %1...\n" ).arg( code_block->vinstr_count ) ); - - // ui.virt_instrs->addTopLevelItem( blank_entry1 ); - // meta_data_entry->setText() + dbg_print( qstring_t( "> code block %1 (block_%2), number of vinstrs = %3..." ) + .arg( code_block_num ) + .arg( ( code_block->vip_begin - file_header->module_base ) + file_header->image_base, 0, 16 ) + .arg( code_block->vinstr_count ) ); + + // for each virtual instruction inside of this code block... + for ( auto idx = 0u; idx < code_block->vinstr_count; ++idx ) + { + const auto virt_instr = &code_block->vinstr[ idx ]; + const auto profile = vm::handler::get_profile( virt_instr->mnemonic_t ); + auto virt_instr_entry = new qtree_widget_item_t; + + // virtual instruction image base'ed rva... (column 1)... + virt_instr_entry->setText( 0, qstring_t::number( ( virt_instr->trace_data.vip - file_header->module_base ) + + file_header->image_base, + 16 ) ); + + // virtual instruction operand bytes... (column 2)... + qstring_t operand_bytes; + operand_bytes.append( QString( "%1" ).arg( virt_instr->opcode, 0, 16 ) ); + + // if virt instruction has an imm... grab its bytes... + if ( virt_instr->operand.has_imm ) + { + operand_bytes.append( " - " ); + for ( auto _idx = 0u; _idx < virt_instr->operand.imm.imm_size / 8; ++_idx ) + operand_bytes.append( QString( "%1 " ).arg( + reinterpret_cast< std::uint8_t * >( &virt_instr->operand.imm.u )[ _idx ], 0, 16 ) ); + } + + virt_instr_entry->setText( 1, operand_bytes ); + + // virtual instruction string, includes imm... (colume 3)... + QString decoded_instr( QString( "%1" ).arg( + profile ? profile->name : QString( "UNK(%1)" ).arg( virt_instr->opcode, 0, 16 ) ) ); + + if ( virt_instr->operand.has_imm ) // if there is a second operand (imm) put its value... + decoded_instr.append( QString( " %1" ).arg( virt_instr->operand.imm.u, 0, 16 ) ); + + virt_instr_entry->setText( 2, decoded_instr ); + + // add comments to the virtual instruction... (colume 4)... + if ( virt_instr->mnemonic_t == vm::handler::LREGQ || virt_instr->mnemonic_t == vm::handler::SREGQ ) + virt_instr_entry->setText( 3, QString( "; vreg%1..." ) + .arg( virt_instr->operand.imm.u ? ( virt_instr->operand.imm.u / 8 ) - + 1 /* zero based vreg... */ + : 0u ) ); + + if ( virt_instr->mnemonic_t == vm::handler::JMP && code_block->jcc.has_jcc ) + virt_instr_entry->setText( + 3, + QString( "; { %1, %2 }" ) + .arg( ( code_block->jcc.block_addr[ 0 ] - file_header->module_base ) + file_header->image_base, + 0, 16 ) + .arg( ( code_block->jcc.block_addr[ 1 ] - file_header->module_base ) + file_header->image_base, + 0, 16 ) ); + + ui.virt_instrs->addTopLevelItem( virt_instr_entry ); + } } } \ No newline at end of file diff --git a/src/qvminspector.h b/src/qvminspector.h index fdc715b..c4c813d 100644 --- a/src/qvminspector.h +++ b/src/qvminspector.h @@ -17,6 +17,7 @@ using qwidget_t = QWidget; using qstring_t = QString; using qfile_t = QFile; using qtree_widget_item_t = QTreeWidgetItem; +using qmsg_box_t = QMessageBox; class qvminspector_t : public qmain_window_t { diff --git a/src/qvminspector.ui b/src/qvminspector.ui index 26ed92a..3288c04 100644 --- a/src/qvminspector.ui +++ b/src/qvminspector.ui @@ -57,7 +57,7 @@ - 120 + 160