|
|
|
@ -3,7 +3,7 @@
|
|
|
|
|
qvm_inspector::qvm_inspector( QWidget *parent ) : QMainWindow( parent ), file_header( nullptr ), g_vm_ctx( nullptr )
|
|
|
|
|
{
|
|
|
|
|
ui.setupUi( this );
|
|
|
|
|
ui.virt_instrs->setColumnWidth( 0, 180 );
|
|
|
|
|
ui.virt_instrs->setColumnWidth( 0, 125 );
|
|
|
|
|
ui.virt_instrs->setColumnWidth( 1, 150 );
|
|
|
|
|
ui.virt_instrs->setColumnWidth( 2, 190 );
|
|
|
|
|
ui.virt_instrs->setColumnWidth( 3, 200 );
|
|
|
|
@ -178,7 +178,8 @@ bool qvm_inspector::serialize_vmp2( std::vector< rtn_data_t > &virt_rtns )
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void qvm_inspector::update_virtual_instructions( std::uintptr_t rtn_addr, QTreeWidgetItem *parent )
|
|
|
|
|
void qvm_inspector::update_virtual_instructions( std::uintptr_t rtn_addr, std::uintptr_t blk_addr,
|
|
|
|
|
QTreeWidgetItem *parent )
|
|
|
|
|
{
|
|
|
|
|
auto _rtn = std::find_if( virt_rtns.begin(), virt_rtns.end(),
|
|
|
|
|
[ & ]( rtn_data_t &rtn ) -> bool { return rtn.rtn_rva == rtn_addr; } );
|
|
|
|
@ -186,11 +187,31 @@ void qvm_inspector::update_virtual_instructions( std::uintptr_t rtn_addr, QTreeW
|
|
|
|
|
if ( _rtn == virt_rtns.end() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for ( const auto &vinstr : _rtn->rtn_blks[ 0 ].vinstrs )
|
|
|
|
|
auto code_blk = blk_addr ? std::find_if( _rtn->rtn_blks.begin(), _rtn->rtn_blks.end(),
|
|
|
|
|
[ & ]( const vm::instrs::code_block_t &code_block ) -> bool {
|
|
|
|
|
return code_block.vip_begin == blk_addr;
|
|
|
|
|
} )
|
|
|
|
|
: _rtn->rtn_blks.begin();
|
|
|
|
|
|
|
|
|
|
if ( code_blk == _rtn->rtn_blks.end() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ( std::find( code_block_addrs.begin(), code_block_addrs.end(), code_blk->vip_begin ) != code_block_addrs.end() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
code_block_addrs.push_back( code_blk->vip_begin );
|
|
|
|
|
|
|
|
|
|
for ( auto &vinstr : code_blk->vinstrs )
|
|
|
|
|
{
|
|
|
|
|
const auto profile = vm::handler::get_profile( vinstr.mnemonic_t );
|
|
|
|
|
const auto &vm_handler = g_vm_ctx->vm_handlers[ vinstr.opcode ];
|
|
|
|
|
auto virt_instr_entry = new QTreeWidgetItem();
|
|
|
|
|
|
|
|
|
|
// virtual instruction image base'ed rva... (column 1)...
|
|
|
|
|
virt_instr_entry->setText(
|
|
|
|
|
0, QString( "0x%1" ).arg( QString::number(
|
|
|
|
|
( vinstr.trace_data.vip - file_header->module_base ) + file_header->image_base, 16 ) ) );
|
|
|
|
|
|
|
|
|
|
// virtual instruction operand bytes... (column 2)...
|
|
|
|
|
QString operand_bytes;
|
|
|
|
|
operand_bytes.append( QString( "%1" ).arg( vinstr.opcode, 0, 16 ) );
|
|
|
|
@ -220,6 +241,68 @@ void qvm_inspector::update_virtual_instructions( std::uintptr_t rtn_addr, QTreeW
|
|
|
|
|
virt_instr_entry->setText(
|
|
|
|
|
3, QString( "; vreg%1" ).arg( vinstr.operand.imm.u ? ( vinstr.operand.imm.u / 8 ) : 0u ) );
|
|
|
|
|
|
|
|
|
|
ui.virt_instrs->addTopLevelItem( virt_instr_entry );
|
|
|
|
|
if ( vinstr.mnemonic_t == vm::handler::JMP )
|
|
|
|
|
{
|
|
|
|
|
switch ( code_blk->jcc.type )
|
|
|
|
|
{
|
|
|
|
|
case vm::instrs::jcc_type::branching:
|
|
|
|
|
{
|
|
|
|
|
virt_instr_entry->setText( 3, QString( "; { 0x%1, 0x%2 }" )
|
|
|
|
|
.arg( code_blk->jcc.block_addr[ 0 ], 0, 16 )
|
|
|
|
|
.arg( code_blk->jcc.block_addr[ 1 ], 0, 16 ) );
|
|
|
|
|
|
|
|
|
|
auto entry_rva = vm_handler.address - module_base;
|
|
|
|
|
auto branch_entry1 = new QTreeWidgetItem(), branch_entry2 = new QTreeWidgetItem();
|
|
|
|
|
const auto block1_addr = code_blk->jcc.block_addr[ 0 ];
|
|
|
|
|
const auto block2_addr = code_blk->jcc.block_addr[ 1 ];
|
|
|
|
|
|
|
|
|
|
branch_entry1->setText( 0, QString( "0x%1" ).arg( block1_addr, 0, 16 ) );
|
|
|
|
|
branch_entry1->setText( 3, QString( "; blk_0x%1" ).arg( block1_addr, 0, 16 ) );
|
|
|
|
|
|
|
|
|
|
branch_entry2->setText( 0, QString( "0x%1" ).arg( block2_addr, 0, 16 ) );
|
|
|
|
|
branch_entry2->setText( 3, QString( "; blk_0x%1" ).arg( block2_addr, 0, 16 ) );
|
|
|
|
|
|
|
|
|
|
if ( g_vm_ctx )
|
|
|
|
|
delete g_vm_ctx;
|
|
|
|
|
|
|
|
|
|
if ( !( g_vm_ctx = new vm::ctx_t( module_base, img_base, img_size, entry_rva ) )->init() )
|
|
|
|
|
{
|
|
|
|
|
dbg_print( QString( "> failed to init vm::ctx_t for jmp at = %1..." )
|
|
|
|
|
.arg( QString::number( code_blk->vip_begin, 16 ) ) );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
update_virtual_instructions( rtn_addr, code_blk->jcc.block_addr[ 0 ], branch_entry1 );
|
|
|
|
|
update_virtual_instructions( rtn_addr, code_blk->jcc.block_addr[ 1 ], branch_entry2 );
|
|
|
|
|
virt_instr_entry->addChildren( { branch_entry1, branch_entry2 } );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case vm::instrs::jcc_type::absolute:
|
|
|
|
|
{
|
|
|
|
|
auto entry_rva = vm_handler.address - module_base;
|
|
|
|
|
virt_instr_entry->setText( 3, QString( "; { 0x%1 }" ).arg( code_blk->jcc.block_addr[ 0 ], 0, 16 ) );
|
|
|
|
|
|
|
|
|
|
if ( g_vm_ctx )
|
|
|
|
|
delete g_vm_ctx;
|
|
|
|
|
|
|
|
|
|
if ( !( g_vm_ctx = new vm::ctx_t( module_base, img_base, img_size, entry_rva ) )->init() )
|
|
|
|
|
{
|
|
|
|
|
dbg_print( QString( "> failed to init vm::ctx_t for jmp at = %1..." )
|
|
|
|
|
.arg( QString::number( code_blk->vip_begin, 16 ) ) );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
update_virtual_instructions( rtn_addr, code_blk->jcc.block_addr[ 0 ], parent );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant var;
|
|
|
|
|
var.setValue( vinstr );
|
|
|
|
|
virt_instr_entry->setData( 3, Qt::UserRole, var );
|
|
|
|
|
parent ? parent->addChild( virt_instr_entry ) : ui.virt_instrs->addTopLevelItem( virt_instr_entry );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|