diff --git a/dependencies/vmprofiler b/dependencies/vmprofiler
index c231911..573cc04 160000
--- a/dependencies/vmprofiler
+++ b/dependencies/vmprofiler
@@ -1 +1 @@
-Subproject commit c2319117a07d95794f54db970aa7f72e8726349a
+Subproject commit 573cc04fc1804ac328b555bb1136d132d858a6fe
diff --git a/src/qvminspector.cpp b/src/qvminspector.cpp
index 3e0b151..78279f2 100644
--- a/src/qvminspector.cpp
+++ b/src/qvminspector.cpp
@@ -19,14 +19,10 @@ void qvminspector_t::on_close()
void qvminspector_t::on_open()
{
- if ( file_header && vmctx )
- {
+ if ( file_header )
free( file_header );
- delete vmctx;
- }
- file_header = nullptr, first_block = nullptr;
- code_block_addrs.clear();
+ file_header = nullptr;
image_base = 0u, vm_entry_rva = 0u, module_base = 0u;
file_path = QFileDialog::getOpenFileName(
@@ -55,7 +51,7 @@ void qvminspector_t::on_open()
}
qfile_t open_file( file_path );
- file_header = reinterpret_cast< vmp2::v3::file_header * >( malloc( file_size ) );
+ file_header = reinterpret_cast< vmp2::v4::file_header * >( malloc( file_size ) );
if ( !open_file.open( QIODevice::ReadOnly ) )
{
@@ -70,8 +66,6 @@ void qvminspector_t::on_open()
dbg_msg( "failed to init vmp2 file data..." );
return;
}
-
- update_ui();
}
void qvminspector_t::dbg_print( qstring_t dbg_output )
@@ -98,10 +92,10 @@ bool qvminspector_t::init_data()
dbg_print( "valid magic bytes for vmp2 file..." );
- if ( file_header->version != vmp2::version_t::v3 )
+ if ( file_header->version != vmp2::version_t::v4 )
{
dbg_msg( "invalid vmp2 file version... "
- "this vminspector is compiled for version 3...\n" );
+ "this vminspector is compiled for version 4...\n" );
return false;
}
@@ -111,275 +105,59 @@ bool qvminspector_t::init_data()
image_size = file_header->module_size;
module_base = reinterpret_cast< std::uintptr_t >( file_header ) + file_header->module_offset;
- vmctx = new vm::ctx_t( module_base, image_base, image_size, 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 );
return true;
}
void qvminspector_t::add_branch_children( qtree_widget_item_t *item, std::uintptr_t branch_addr )
{
- if ( std::find( code_block_addrs.begin(), code_block_addrs.end(), branch_addr ) != code_block_addrs.end() )
- return;
-
- code_block_addrs.push_back( branch_addr );
- // for each code block find the one that starts with the desired branch...
- 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 )
- {
- if ( code_block->vip_begin != branch_addr )
- continue;
+}
- dbg_print( qstring_t( "> code block %1 (block_%2), number of vinstrs = %3..." )
- .arg( code_block_num )
- .arg( code_block->vip_begin, 0, 16 )
- .arg( code_block->vinstr_count ) );
+void qvminspector_t::update_ui()
+{
- // 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( "block_%1+%2" )
- .arg( branch_addr, 0, 16 )
- .arg( idx ? code_block->vip_begin >
- ( ( virt_instr->trace_data.vip - file_header->module_base ) + image_base )
- ? code_block->vip_begin -
- ( ( virt_instr->trace_data.vip - file_header->module_base ) + image_base )
- : ( ( virt_instr->trace_data.vip - file_header->module_base ) + image_base ) -
- code_block->vip_begin
- : 0u,
- 0, 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 ) : 0u ) );
-
- QVariant var;
- var.setValue( virt_instr );
- virt_instr_entry->setData( 3, Qt::UserRole, var );
-
- if ( virt_instr->mnemonic_t == vm::handler::JMP )
- {
- if ( code_block->jcc.type == vm::instrs::jcc_type::branching )
- {
- virt_instr_entry->setText( 3, QString( "; { %1, %2 }" )
- .arg( code_block->jcc.block_addr[ 0 ], 0, 16 )
- .arg( code_block->jcc.block_addr[ 1 ], 0, 16 ) );
-
- auto branch_entry1 = new qtree_widget_item_t(), branch_entry2 = new qtree_widget_item_t();
- const auto block1_addr = code_block->jcc.block_addr[ 0 ];
- const auto block2_addr = code_block->jcc.block_addr[ 1 ];
-
- branch_entry1->setText( 0, QString( "%1" ).arg( block1_addr, 0, 16 ) );
- branch_entry1->setText( 3, QString( "; block_%1" ).arg( block1_addr, 0, 16 ) );
-
- branch_entry2->setText( 0, QString( "%1" ).arg( block2_addr, 0, 16 ) );
- branch_entry2->setText( 3, QString( "; block_%1" ).arg( block2_addr, 0, 16 ) );
-
- add_branch_children( branch_entry1, code_block->jcc.block_addr[ 0 ] );
- add_branch_children( branch_entry2, code_block->jcc.block_addr[ 1 ] );
-
- virt_instr_entry->addChildren( { branch_entry1, branch_entry2 } );
- // if its a JMP with branches we want to insert the next code block
- // instructions into the child widget entries...
- item->addChild( virt_instr_entry );
- return;
- }
- else
- {
- virt_instr_entry->setText( 3, QString( "; { %1 }" ).arg( code_block->jcc.block_addr[ 0 ], 0, 16 ) );
-
- // else if this jmp doesnt have two branches add the next code block to it...
- item->addChild( virt_instr_entry );
- add_branch_children( item, code_block->jcc.block_addr[ 0 ] );
- }
- }
- item->addChild( virt_instr_entry );
- }
- }
}
-void qvminspector_t::update_ui()
+bool qvminspector_t::serialize_vmp2( std::vector< rtn_data_t > &virt_rtns, std::vector< std::uint8_t > &vmp2file )
{
- // add vm handlers to the vm handler tree...
- ui.virt_handlers_tree->clear();
- for ( auto idx = 0u; idx < vmctx->vm_handlers.size(); ++idx )
+ const auto file_header = reinterpret_cast< vmp2::v4::file_header * >( vmp2file.data() );
+
+ if ( file_header->version != vmp2::version_t::v4 )
{
- auto new_handler_entry = new qtree_widget_item_t;
- new_handler_entry->setData( 0, Qt::UserRole, idx );
- new_handler_entry->setText( 0, QString( "%1" ).arg( idx ) );
- new_handler_entry->setText(
- 1, QString( "%1" ).arg(
- ABS_TO_IMG( vmctx->vm_handlers[ idx ].address, module_base, file_header->image_base ), 0, 16 ) );
-
- new_handler_entry->setText( 2, vmctx->vm_handlers[ idx ].profile ? vmctx->vm_handlers[ idx ].profile->name
- : "UNDEFINED" );
-
- new_handler_entry->setText( 3, QString( "%1" ).arg( vmctx->vm_handlers[ idx ].imm_size ) );
-
- if ( vmctx->vm_handlers[ idx ].profile && vmctx->vm_handlers[ idx ].imm_size )
- new_handler_entry->setText( 4, vmctx->vm_handlers[ idx ].profile->extention ==
- vm::handler::extention_t::sign_extend
- ? "SIGN EXTENDED"
- : "ZERO EXTENDED" );
- else
- new_handler_entry->setText( 4, "UNDEFINED" );
-
- ui.virt_handlers_tree->addTopLevelItem( new_handler_entry );
+ std::printf( "[!] invalid vmp2 file version... this build uses v3...\n" );
+ return false;
}
- ui.virt_handlers_tree->topLevelItem( 0 )->setSelected( true );
-
- // 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...
-
- ui.virt_instrs->clear(); // clear old virtual instructions out since we are updating the UI...
- 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 first_rtn = reinterpret_cast< vmp2::v4::rtn_t * >( reinterpret_cast< std::uintptr_t >( file_header ) +
+ file_header->rtn_offset );
+
+ 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 ) )
{
- code_block_addrs.push_back( code_block->vip_begin );
- dbg_print( qstring_t( "> code block %1 (block_%2), number of vinstrs = %3..." )
- .arg( code_block_num )
- .arg( code_block->vip_begin, 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 )
+ virt_rtns.push_back( { rtn_block->vm_enter_offset, {} } );
+ 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 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( "block_%1+%2" )
- .arg( code_block->vip_begin, 0, 16 )
- .arg( idx ? code_block->vip_begin >
- ( ( virt_instr->trace_data.vip - file_header->module_base ) + image_base )
- ? code_block->vip_begin -
- ( ( virt_instr->trace_data.vip - file_header->module_base ) + image_base )
- : ( ( virt_instr->trace_data.vip - file_header->module_base ) + image_base ) -
- code_block->vip_begin
- : 0u,
- 0, 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 ) : 0u ) );
-
- // add virt_instr_t pointer for this current virtual instruction...
- QVariant var;
- var.setValue( virt_instr );
- virt_instr_entry->setData( 3, Qt::UserRole, var );
-
- if ( virt_instr->mnemonic_t == vm::handler::JMP )
- {
- if ( code_block->jcc.type == vm::instrs::jcc_type::branching )
- {
- virt_instr_entry->setText( 3, QString( "; { %1, %2 }" )
- .arg( code_block->jcc.block_addr[ 0 ], 0, 16 )
- .arg( code_block->jcc.block_addr[ 1 ], 0, 16 ) );
-
- auto branch_entry1 = new qtree_widget_item_t(), branch_entry2 = new qtree_widget_item_t();
- const auto block1_addr = code_block->jcc.block_addr[ 0 ];
- const auto block2_addr = code_block->jcc.block_addr[ 1 ];
-
- branch_entry1->setText( 0, QString( "%1" ).arg( block1_addr, 0, 16 ) );
- branch_entry1->setText( 3, QString( "; block_%1" ).arg( block1_addr, 0, 16 ) );
-
- branch_entry2->setText( 0, QString( "%1" ).arg( block2_addr, 0, 16 ) );
- branch_entry2->setText( 3, QString( "; block_%1" ).arg( block2_addr, 0, 16 ) );
-
- add_branch_children( branch_entry1, code_block->jcc.block_addr[ 0 ] );
- add_branch_children( branch_entry2, code_block->jcc.block_addr[ 1 ] );
-
- virt_instr_entry->addChildren( { branch_entry1, branch_entry2 } );
- // if its a JMP with branches we want to insert the next code block
- // instructions into the child widget entries...
- ui.virt_instrs->addTopLevelItem( virt_instr_entry );
- goto finish; // bad code...
- }
- else if ( code_block->jcc.type == vm::instrs::jcc_type::absolute )
- virt_instr_entry->setText( 3, QString( "; { %1 }" ).arg( code_block->jcc.block_addr[ 0 ], 0, 16 ) );
- }
- ui.virt_instrs->addTopLevelItem( virt_instr_entry );
+ 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 ) );
+
+ vm::instrs::code_block_t _code_block{ code_block->vip_begin };
+ _code_block.jcc.has_jcc = code_block->has_jcc;
+ _code_block.jcc.type = code_block->jcc_type;
+
+ for ( auto idx = 0u; idx < code_block->num_block_addrs; ++idx )
+ _code_block.jcc.block_addr.push_back( code_block->branch_addr[ idx ] );
+
+ for ( auto idx = 0u; idx < code_block->vinstr_count; ++idx )
+ _code_block.vinstrs.push_back( block_vinstrs[ idx ] );
+
+ virt_rtns.back().rtn_blks.push_back( _code_block );
}
}
-finish: // bad code...
- ui.virt_instrs->topLevelItem( 0 )->setSelected( true );
+ return true;
}
\ No newline at end of file
diff --git a/src/qvminspector.h b/src/qvminspector.h
index 5f80b65..a3a0b3c 100644
--- a/src/qvminspector.h
+++ b/src/qvminspector.h
@@ -26,6 +26,12 @@ using qfile_t = QFile;
using qtree_widget_item_t = QTreeWidgetItem;
using qmsg_box_t = QMessageBox;
+struct rtn_data_t
+{
+ std::uint32_t rtn_rva;
+ std::vector< vm::instrs::code_block_t > rtn_blks;
+};
+
class qvminspector_t : public qmain_window_t
{
friend class qvirt_instrs_t;
@@ -33,6 +39,7 @@ class qvminspector_t : public qmain_window_t
Q_OBJECT
public:
qvminspector_t( qwidget_t *parent = Q_NULLPTR );
+ static bool serialize_vmp2( std::vector< rtn_data_t > &virt_rtns, std::vector< std::uint8_t > &vmp2file );
private slots:
void on_open();
@@ -50,8 +57,5 @@ class qvminspector_t : public qmain_window_t
qstring_t VMProtectedFilePath;
std::uint64_t image_base, vm_entry_rva, module_base, image_size;
vm::ctx_t *vmctx;
-
- vmp2::v3::file_header *file_header;
- vmp2::v3::code_block_t *first_block;
- std::vector< std::uintptr_t > code_block_addrs;
+ vmp2::v4::file_header *file_header;
};
\ No newline at end of file
diff --git a/src/qvminspector.ui b/src/qvminspector.ui
index 1561742..a108884 100644
--- a/src/qvminspector.ui
+++ b/src/qvminspector.ui
@@ -6,7 +6,7 @@
0
0
- 1496
+ 1414
1093
@@ -27,7 +27,7 @@
-
- 0
+ 1
@@ -44,7 +44,7 @@
0
0
- 1452
+ 1370
854
@@ -414,7 +414,7 @@
0
0
- 672
+ 631
228
@@ -604,6 +604,111 @@
+
+
+ Virtual Routines
+
+
+ -
+
+
+ Virtual Machine Enters
+
+
+
-
+
+
+
+ Name
+
+
+
+
+ Address
+
+
+
+
+ Number Of Code Blocks
+
+
+
-
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Virtual Machine Enter Information
+
+
+
-
+
+
+ Virtual Machine - Enter Instructions
+
+
+
-
+
+
+
+ Address
+
+
+
+
+ Instruction
+
+
+
-
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Virtual Machine - Calc Jmp
+
+
+
-
+
+
+
+ Address
+
+
+
+
+ Instruction
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -613,7 +718,7 @@
0
0
- 1496
+ 1414
21