diff --git a/src/darkstyle/framelesswindow/framelesswindow.ui b/src/darkstyle/framelesswindow/framelesswindow.ui
index 2421768..7751a56 100644
--- a/src/darkstyle/framelesswindow/framelesswindow.ui
+++ b/src/darkstyle/framelesswindow/framelesswindow.ui
@@ -6,7 +6,7 @@
0
0
- 1311
+ 1404
897
diff --git a/src/main.cpp b/src/main.cpp
index 8c375a0..9b282de 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -3,12 +3,12 @@
#include
#include
-#include "qvm_inspector.h"
+#include "darkstyle/DarkStyle.h"
+#include "darkstyle/framelesswindow/framelesswindow.h"
#include "qvm_handlers.h"
+#include "qvm_inspector.h"
#include "qvm_virtual_instructions.h"
#include "qvm_virtual_routines.h"
-#include "darkstyle/DarkStyle.h"
-#include "darkstyle/framelesswindow/framelesswindow.h"
int WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{
@@ -16,10 +16,10 @@ int WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int
QApplication::setStyle( new DarkStyle );
FramelessWindow FW;
- const auto g_main_window = new qvm_inspector;
- qvm_virtual_instructions VirtInstrsPanel( g_main_window );
- qvm_handlers VirtHandlerPanel( g_main_window );
- qvm_virtual_routines VirtualRoutinesPanel( g_main_window );
+ auto g_main_window = new qvm_inspector;
+ qvm_virtual_instructions virt_instrs_panel( g_main_window );
+ qvm_handlers virt_handler_panel( g_main_window );
+ qvm_virtual_routines virt_routine_panel( g_main_window );
FW.setContent( g_main_window );
FW.setWindowIcon( QIcon( "icon.ico" ) );
diff --git a/src/qvm_inspector.cpp b/src/qvm_inspector.cpp
index 45b73a2..8e66589 100644
--- a/src/qvm_inspector.cpp
+++ b/src/qvm_inspector.cpp
@@ -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 );
}
}
diff --git a/src/qvm_inspector.h b/src/qvm_inspector.h
index 59b6131..1327e50 100644
--- a/src/qvm_inspector.h
+++ b/src/qvm_inspector.h
@@ -16,7 +16,7 @@
#include
#define ABS_TO_IMG( addr, mod_base, img_base ) ( addr - mod_base ) + img_base
-Q_DECLARE_METATYPE( vm::instrs::virt_instr_t * )
+Q_DECLARE_METATYPE( vm::instrs::virt_instr_t )
struct rtn_data_t
{
@@ -42,7 +42,8 @@ class qvm_inspector : public QMainWindow
void dbg_msg( QString DbgOutput );
void update_ui();
bool serialize_vmp2( std::vector< rtn_data_t > &virt_rtns );
- void update_virtual_instructions( std::uintptr_t rtn_addr, QTreeWidgetItem *parent = nullptr );
+ void update_virtual_instructions( std::uintptr_t rtn_addr, std::uintptr_t blk_addr = 0ull,
+ QTreeWidgetItem *parent = nullptr );
bool init_data();
Ui::QVMProfilerClass ui;
@@ -51,4 +52,5 @@ class qvm_inspector : public QMainWindow
vmp2::v4::file_header *file_header;
std::vector< rtn_data_t > virt_rtns;
+ std::vector< std::uintptr_t > code_block_addrs;
};
\ No newline at end of file
diff --git a/src/qvm_virtual_instructions.cpp b/src/qvm_virtual_instructions.cpp
index 4058a2a..490121a 100644
--- a/src/qvm_virtual_instructions.cpp
+++ b/src/qvm_virtual_instructions.cpp
@@ -16,15 +16,11 @@ void qvm_virtual_instructions::on_select()
if ( !item )
return;
- const auto virt_instr = item->data( 3, Qt::UserRole ).value< vm::instrs::virt_instr_t * >();
-
- if ( !virt_instr )
- return;
-
- update_native_registers( virt_instr );
- update_virtual_registers( virt_instr );
- update_virtual_stack( virt_instr );
- update_vmhandler_info( virt_instr );
+ auto virt_instr = item->data( 3, Qt::UserRole ).value< vm::instrs::virt_instr_t >();
+ update_native_registers( &virt_instr );
+ update_virtual_registers( &virt_instr );
+ update_virtual_stack( &virt_instr );
+ update_vmhandler_info( &virt_instr );
}
void qvm_virtual_instructions::update_native_registers( vm::instrs::virt_instr_t *virt_instr )
@@ -59,8 +55,9 @@ void qvm_virtual_instructions::update_virtual_registers( vm::instrs::virt_instr_
// set VIP in virtual registers window...
ui->virt_regs->topLevelItem( 0 )->setText(
- 1, QString::number(
- ( trace_data.vip - g_main_window->file_header->module_base ) + g_main_window->file_header->image_base, 16 ) );
+ 1, QString::number( ( trace_data.vip - g_main_window->file_header->module_base ) +
+ g_main_window->file_header->image_base,
+ 16 ) );
// set VSP in virtual registers window...
ui->virt_regs->topLevelItem( 1 )->setText( 1, QString::number( trace_data.regs.rbp, 16 ) );
@@ -100,7 +97,8 @@ void qvm_virtual_instructions::update_vmhandler_info( vm::instrs::virt_instr_t *
for ( const auto &instr : vm_handler_instrs )
{
auto new_instr = new QTreeWidgetItem();
- new_instr->setText( 0, QString::number( ( instr.addr - g_main_window->module_base ) + g_main_window->img_base, 16 ) );
+ new_instr->setText(
+ 0, QString::number( ( instr.addr - g_main_window->module_base ) + g_main_window->img_base, 16 ) );
ZydisFormatterFormatInstruction( &formatter, &instr.instr, buffer, sizeof( buffer ),
( instr.addr - g_main_window->module_base ) + g_main_window->img_base );
diff --git a/src/qvm_virtual_routines.cpp b/src/qvm_virtual_routines.cpp
index efab1d3..ca64e63 100644
--- a/src/qvm_virtual_routines.cpp
+++ b/src/qvm_virtual_routines.cpp
@@ -101,5 +101,8 @@ void qvm_virtual_routines::on_select()
update_vm_enter( g_main_window->g_vm_ctx );
update_calc_jmp( g_main_window->g_vm_ctx );
update_vm_handlers( g_main_window->g_vm_ctx );
+
+ ui->virt_instrs->clear();
+ g_main_window->code_block_addrs.clear();
g_main_window->update_virtual_instructions( entry_rva );
}
\ No newline at end of file
diff --git a/src/qvminspector.ui b/src/qvminspector.ui
index 3c08ead..e59fcfc 100644
--- a/src/qvminspector.ui
+++ b/src/qvminspector.ui
@@ -27,7 +27,7 @@
-
- 1
+ 2