diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8835914..b89a94b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -59,24 +59,27 @@ set(vmprofiler-qt_SOURCES "")
list(APPEND vmprofiler-qt_SOURCES
"src/qvminspector.ui"
"src/qvminspector.qrc"
- "src/qvminspector.cpp"
- "src/qvirt_instrs.cpp"
- "src/qvirt_handlers.cpp"
- "src/main.cpp"
- "src/qvirt_handlers.h"
- "src/qvirt_instrs.h"
- "src/qvminspector.h"
- "src/icon.rc"
"src/darkstyle/DarkStyle.cpp"
"src/darkstyle/framelesswindow/framelesswindow.cpp"
"src/darkstyle/framelesswindow/windowdragger.cpp"
"src/darkstyle/mainwindow.cpp"
+ "src/main.cpp"
+ "src/qvm_handlers.cpp"
+ "src/qvm_inspector.cpp"
+ "src/qvm_virtual_instructions.cpp"
+ "src/qvm_virtual_routines.cpp"
"src/darkstyle/DarkStyle.h"
"src/darkstyle/framelesswindow/framelesswindow.h"
"src/darkstyle/framelesswindow/windowdragger.h"
"src/darkstyle/mainwindow.h"
+ "src/qvm_handlers.h"
+ "src/qvm_inspector.h"
+ "src/qvm_virtual_instructions.h"
+ "src/qvm_virtual_routines.h"
+ "src/icon.rc"
"src/darkstyle/mainwindow.ui"
"src/darkstyle/framelesswindow.qrc"
+ "src/darkstyle/framelesswindow/framelesswindow.ui"
"dependencies/ia32-doc/out/ia32.hpp"
)
diff --git a/cmake.toml b/cmake.toml
index 248c7a5..ea6f7af 100644
--- a/cmake.toml
+++ b/cmake.toml
@@ -19,16 +19,12 @@ compile-features = ["cxx_std_20"]
sources = [
"src/qvminspector.ui",
"src/qvminspector.qrc",
- "src/qvminspector.cpp",
- "src/qvirt_instrs.cpp",
- "src/qvirt_handlers.cpp",
- "src/main.cpp",
- "src/*.h",
+ "src/**.cpp",
+ "src/**.h",
"src/icon.rc",
- "src/darkstyle/**.cpp",
- "src/darkstyle/**.h",
"src/darkstyle/mainwindow.ui",
"src/darkstyle/framelesswindow.qrc",
+ "src/darkstyle/framelesswindow/framelesswindow.ui",
"dependencies/ia32-doc/out/ia32.hpp"
]
diff --git a/dependencies/vmprofiler b/dependencies/vmprofiler
index c231911..0511401 160000
--- a/dependencies/vmprofiler
+++ b/dependencies/vmprofiler
@@ -1 +1 @@
-Subproject commit c2319117a07d95794f54db970aa7f72e8726349a
+Subproject commit 051140175db16b38acee882cfca714b4a1000a41
diff --git a/src/darkstyle/framelesswindow/framelesswindow.ui b/src/darkstyle/framelesswindow/framelesswindow.ui
index 4bc3f0d..87648a2 100644
--- a/src/darkstyle/framelesswindow/framelesswindow.ui
+++ b/src/darkstyle/framelesswindow/framelesswindow.ui
@@ -6,8 +6,8 @@
0
0
- 1737
- 1157
+ 1404
+ 897
@@ -143,7 +143,7 @@
color:rgb(153,153,153);
- VMProtect 2 - Virtual Instruction Inspector (v1.8 BETA)
+ VMProtect 2 - Virtual Instruction Inspector - v2.0
Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
diff --git a/src/main.cpp b/src/main.cpp
index bb0ceab..9b282de 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -5,21 +5,24 @@
#include "darkstyle/DarkStyle.h"
#include "darkstyle/framelesswindow/framelesswindow.h"
-#include "qvirt_handlers.h"
-#include "qvirt_instrs.h"
-#include "qvminspector.h"
+#include "qvm_handlers.h"
+#include "qvm_inspector.h"
+#include "qvm_virtual_instructions.h"
+#include "qvm_virtual_routines.h"
int WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{
QApplication app( __argc, __argv );
QApplication::setStyle( new DarkStyle );
- FramelessWindow frameless_window;
- const auto window = new qvminspector_t;
- qvirt_instrs_t virt_instr( window );
- qvirt_handlers_t virt_handlers( window );
+ FramelessWindow FW;
- frameless_window.setContent( window );
- frameless_window.setWindowIcon( QIcon( "icon.ico" ) );
- frameless_window.show();
+ 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" ) );
+ FW.show();
return app.exec();
}
\ No newline at end of file
diff --git a/src/qvirt_instrs.h b/src/qvirt_instrs.h
deleted file mode 100644
index d09326f..0000000
--- a/src/qvirt_instrs.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#pragma once
-#define NOMINMAX
-#include "qvminspector.h"
-
-class qvirt_instrs_t : public QObject
-{
- Q_OBJECT
- public:
- explicit qvirt_instrs_t( qvminspector_t *vminspector );
-
- private:
- Ui::QVMProfilerClass *ui;
- qvminspector_t *vminspector;
- void update_native_regs( vm::instrs::virt_instr_t *virt_instr );
- void update_virtual_regs( vm::instrs::virt_instr_t *virt_instr );
- void update_virtual_stack( vm::instrs::virt_instr_t *virt_instr );
- void update_vm_handler_info( vm::instrs::virt_instr_t *virt_instr );
-
- private slots:
- void on_select();
-};
\ No newline at end of file
diff --git a/src/qvirt_handlers.cpp b/src/qvm_handlers.cpp
similarity index 71%
rename from src/qvirt_handlers.cpp
rename to src/qvm_handlers.cpp
index 00c412b..0d5117f 100644
--- a/src/qvirt_handlers.cpp
+++ b/src/qvm_handlers.cpp
@@ -1,11 +1,12 @@
-#include "qvirt_handlers.h"
+#include "qvm_handlers.h"
-qvirt_handlers_t::qvirt_handlers_t( qvminspector_t *vminspector ) : vminspector( vminspector ), ui( &vminspector->ui )
+qvm_handlers::qvm_handlers( qvm_inspector *g_main_window )
+ : g_main_window( g_main_window ), ui( &g_main_window->ui )
{
- connect( ui->virt_handlers_tree, &QTreeWidget::itemSelectionChanged, this, &qvirt_handlers_t::on_select );
+ connect( ui->virt_handlers_tree, &QTreeWidget::itemSelectionChanged, this, &qvm_handlers::on_select );
}
-void qvirt_handlers_t::update_transforms( vm::handler::handler_t &vm_handler )
+void qvm_handlers::update_transforms( vm::handler::handler_t &vm_handler )
{
char buffer[ 256 ];
ZydisFormatter formatter;
@@ -19,7 +20,7 @@ void qvirt_handlers_t::update_transforms( vm::handler::handler_t &vm_handler )
if ( transform_type == vm::transform::type::generic0 && transform_instr.mnemonic == ZYDIS_MNEMONIC_INVALID )
continue;
- auto new_transform_entry = new qtree_widget_item_t();
+ auto new_transform_entry = new QTreeWidgetItem();
switch ( transform_type )
{
@@ -52,7 +53,7 @@ void qvirt_handlers_t::update_transforms( vm::handler::handler_t &vm_handler )
}
}
-void qvirt_handlers_t::update_instrs( vm::handler::handler_t &vm_handler )
+void qvm_handlers::update_instrs( vm::handler::handler_t &vm_handler )
{
char buffer[ 256 ];
ZydisFormatter formatter;
@@ -64,19 +65,18 @@ void qvirt_handlers_t::update_instrs( vm::handler::handler_t &vm_handler )
// display vm handler instructions...
for ( const auto &instr : vm_handler_instrs )
{
- auto new_instr = new qtree_widget_item_t();
- new_instr->setText(
- 0, qstring_t::number( ( instr.addr - vminspector->module_base ) + vminspector->image_base, 16 ) );
+ auto new_instr = new QTreeWidgetItem();
+ 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 - vminspector->module_base ) + vminspector->image_base );
+ ( instr.addr - g_main_window->module_base ) + g_main_window->img_base );
new_instr->setText( 1, buffer );
ui->virt_handler_instrs_tree->addTopLevelItem( new_instr );
}
}
-void qvirt_handlers_t::on_select()
+void qvm_handlers::on_select()
{
if ( ui->virt_handlers_tree->selectedItems().empty() )
return;
@@ -86,10 +86,10 @@ void qvirt_handlers_t::on_select()
if ( !item )
return;
- if ( !vminspector->vmctx )
+ if ( !g_main_window->g_vm_ctx )
return;
const auto handler_idx = item->data( 0, Qt::UserRole ).value< std::uint8_t >();
- update_instrs( vminspector->vmctx->vm_handlers[ handler_idx ] );
- update_transforms( vminspector->vmctx->vm_handlers[ handler_idx ] );
+ update_instrs( g_main_window->g_vm_ctx->vm_handlers[ handler_idx ] );
+ update_transforms( g_main_window->g_vm_ctx->vm_handlers[ handler_idx ] );
}
\ No newline at end of file
diff --git a/src/qvirt_handlers.h b/src/qvm_handlers.h
similarity index 58%
rename from src/qvirt_handlers.h
rename to src/qvm_handlers.h
index 2022692..faf0805 100644
--- a/src/qvirt_handlers.h
+++ b/src/qvm_handlers.h
@@ -1,16 +1,15 @@
#pragma once
-#define NOMINMAX
-#include "qvminspector.h"
+#include "qvm_inspector.h"
-class qvirt_handlers_t : public QObject
+class qvm_handlers : public QObject
{
Q_OBJECT
public:
- explicit qvirt_handlers_t( qvminspector_t *vminspector );
+ explicit qvm_handlers( qvm_inspector *g_main_window );
private:
Ui::QVMProfilerClass *ui;
- qvminspector_t *vminspector;
+ qvm_inspector *g_main_window;
void update_transforms( vm::handler::handler_t &vm_handler );
void update_instrs( vm::handler::handler_t &vm_handler );
diff --git a/src/qvm_inspector.cpp b/src/qvm_inspector.cpp
new file mode 100644
index 0000000..4321662
--- /dev/null
+++ b/src/qvm_inspector.cpp
@@ -0,0 +1,348 @@
+#include "qvm_inspector.h"
+
+qvm_inspector::qvm_inspector( QWidget *parent ) : QMainWindow( parent ), file_header( nullptr ), g_vm_ctx( nullptr )
+{
+ ui.setupUi( this );
+ ui.virt_instrs->setColumnWidth( 0, 125 );
+ ui.virt_instrs->setColumnWidth( 1, 150 );
+ ui.virt_instrs->setColumnWidth( 2, 190 );
+ ui.virt_instrs->setColumnWidth( 3, 200 );
+ ui.virtual_machine_enters->setColumnWidth( 0, 180 );
+
+ connect( ui.action_open, &QAction::triggered, this, &qvm_inspector::on_open );
+ connect( ui.action_close, &QAction::triggered, this, &qvm_inspector::on_close );
+}
+
+void qvm_inspector::on_close()
+{
+ exit( 0 );
+}
+
+void qvm_inspector::on_open()
+{
+ if ( file_header )
+ free( file_header );
+
+ file_header = nullptr;
+ img_base = 0u, module_base = 0u;
+
+ auto file_path = QFileDialog::getOpenFileName(
+ this, tr( "open vmp2 file" ), std::filesystem::current_path().string().c_str(), tr( "vmp2 file (*.vmp2)" ) );
+
+ if ( file_path.isEmpty() )
+ {
+ dbg_msg( "invalid vmp2 file... no file selected..." );
+ return;
+ }
+
+ if ( !std::filesystem::exists( file_path.toStdString() ) )
+ {
+ dbg_msg( "vmp2 file does not exist..." );
+ return;
+ }
+
+ const auto file_size = std::filesystem::file_size( file_path.toStdString() );
+
+ if ( !file_size )
+ {
+ dbg_msg( "invalid vmp2 file size..." );
+ return;
+ }
+
+ QFile open_file( file_path );
+ file_header = reinterpret_cast< vmp2::v4::file_header * >( malloc( file_size ) );
+
+ if ( !open_file.open( QIODevice::ReadOnly ) )
+ {
+ dbg_msg( "failed to open vmp2 file..." );
+ return;
+ }
+
+ memcpy( file_header, open_file.readAll().data(), file_size );
+
+ if ( !init_data() )
+ {
+ dbg_msg( "failed to init vmp2 file data..." );
+ return;
+ }
+}
+
+void qvm_inspector::dbg_print( QString dbg_output )
+{
+ ui.dbg_output_window->appendPlainText( dbg_output );
+}
+
+void qvm_inspector::dbg_msg( QString dbg_output )
+{
+ QMessageBox msg_box;
+ msg_box.setText( dbg_output );
+ msg_box.exec();
+ dbg_print( dbg_output );
+}
+
+bool qvm_inspector::init_data()
+{
+ if ( file_header->magic != VMP_MAGIC )
+ {
+ dbg_msg( "invalid magic bytes for vmp2 file..." );
+
+ return false;
+ }
+
+ dbg_print( "valid magic bytes for vmp2 file..." );
+
+ if ( file_header->version != vmp2::version_t::v4 )
+ {
+ dbg_msg( "invalid vmp2 file version... "
+ "this vminspector is compiled for version 4...\n" );
+
+ return false;
+ }
+
+ img_base = file_header->image_base;
+ img_size = file_header->module_size;
+ module_base = reinterpret_cast< std::uintptr_t >( file_header ) + file_header->module_offset;
+
+ if ( !serialize_vmp2( virt_rtns ) )
+ {
+ dbg_msg( "failed to serialize vmp2 file format...\n" );
+ return false;
+ }
+
+ update_ui();
+ return true;
+}
+
+void qvm_inspector::update_ui()
+{
+ ui.virtual_machine_enters->clear();
+ for ( auto &[ rtn_rva, rtn_blks ] : virt_rtns )
+ {
+ auto new_item = new QTreeWidgetItem();
+ new_item->setText( 0, QString( "rtn_%1" ).arg( rtn_rva + file_header->image_base, 0, 16 ) );
+ new_item->setText( 1, QString( "%1" ).arg( rtn_rva + file_header->image_base, 0, 16 ) );
+ new_item->setText( 2, QString( "%1" ).arg( rtn_blks.size() ) );
+ new_item->setData( 0, Qt::UserRole, QVariant( rtn_rva ) );
+
+ std::for_each( rtn_blks.begin(), rtn_blks.end(), [ & ]( vm::instrs::code_block_t &code_blk ) {
+ auto new_child = new QTreeWidgetItem();
+ new_child->setText( 0, QString( "blk_%1" ).arg( code_blk.vip_begin, 0, 16 ) );
+ new_child->setText( 1, QString( "%1" ).arg( code_blk.vip_begin, 0, 16 ) );
+ new_child->setText( 2, QString( "%1" ).arg( code_blk.vinstrs.size() ) );
+ new_item->addChild( new_child );
+ } );
+
+ ui.virtual_machine_enters->addTopLevelItem( new_item );
+ }
+}
+
+bool qvm_inspector::serialize_vmp2( std::vector< rtn_data_t > &virt_rtns )
+{
+ if ( file_header->version != vmp2::version_t::v4 )
+ {
+ std::printf( "[!] invalid vmp2 file version... this build uses v3...\n" );
+ return false;
+ }
+
+ 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 ) )
+ {
+ 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 ) )
+ {
+ 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 );
+ }
+ }
+
+ return true;
+}
+
+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; } );
+
+ if ( _rtn == virt_rtns.end() )
+ return;
+
+ 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 );
+ 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 ) );
+
+ // if virt instruction has an imm... grab its bytes...
+ if ( vinstr.operand.has_imm )
+ {
+ operand_bytes.append( " - " );
+ for ( auto _idx = 0u; _idx < vinstr.operand.imm.imm_size / 8; ++_idx )
+ operand_bytes.append( QString( "%1 " ).arg(
+ reinterpret_cast< const std::uint8_t * >( &vinstr.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( vinstr.opcode, 0, 16 ) ) );
+
+ if ( vinstr.operand.has_imm ) // if there is a second operand (imm) put its value...
+ decoded_instr.append( QString( " %1" ).arg( vinstr.operand.imm.u, 0, 16 ) );
+
+ virt_instr_entry->setText( 2, decoded_instr );
+
+ // add comments to the virtual instruction... (colume 4)...
+ if ( vinstr.mnemonic_t == vm::handler::LREGQ || vinstr.mnemonic_t == vm::handler::SREGQ )
+ virt_instr_entry->setText(
+ 3, QString( "; vreg%1" ).arg( vinstr.operand.imm.u ? ( vinstr.operand.imm.u / 8 ) : 0u ) );
+
+ 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 = g_vm_ctx->vm_handlers[ vinstr.opcode ].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 );
+
+ 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[ 1 ], branch_entry2 );
+ virt_instr_entry->addChildren( { branch_entry1, branch_entry2 } );
+ break;
+ }
+ case vm::instrs::jcc_type::absolute:
+ {
+ auto entry_rva = g_vm_ctx->vm_handlers[ vinstr.opcode ].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;
+ }
+
+ auto branch_entry1 = new QTreeWidgetItem();
+ branch_entry1->setText( 0, QString( "0x%1" ).arg( code_blk->jcc.block_addr[ 0 ], 0, 16 ) );
+ branch_entry1->setText( 3, QString( "; blk_0x%1" ).arg( code_blk->jcc.block_addr[ 0 ], 0, 16 ) );
+ update_virtual_instructions( rtn_addr, code_blk->jcc.block_addr[ 0 ], branch_entry1 );
+ virt_instr_entry->addChild( branch_entry1 );
+ break;
+ }
+ case vm::instrs::jcc_type::switch_case:
+ {
+ auto entry_rva = g_vm_ctx->vm_handlers[ vinstr.opcode ].address - module_base;
+
+ 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;
+ }
+
+ for ( auto branch_addr : code_blk->jcc.block_addr )
+ {
+ virt_instr_entry->setText( 3, QString( "; switch case" ) );
+
+ auto branch_entry = new QTreeWidgetItem();
+ branch_entry->setText( 0, QString( "0x%1" ).arg( branch_addr, 0, 16 ) );
+
+ update_virtual_instructions( rtn_addr, branch_addr, branch_entry );
+ virt_instr_entry->addChild( branch_entry );
+ }
+ 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
new file mode 100644
index 0000000..1327e50
--- /dev/null
+++ b/src/qvm_inspector.h
@@ -0,0 +1,56 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "ui_qvminspector.h"
+#include
+#include
+
+#define ABS_TO_IMG( addr, mod_base, img_base ) ( addr - mod_base ) + img_base
+Q_DECLARE_METATYPE( vm::instrs::virt_instr_t )
+
+struct rtn_data_t
+{
+ std::uint32_t rtn_rva;
+ std::vector< vm::instrs::code_block_t > rtn_blks;
+};
+
+class qvm_inspector : public QMainWindow
+{
+ friend class qvm_virtual_instructions;
+ friend class qvm_handlers;
+ friend class qvm_virtual_routines;
+ Q_OBJECT
+ public:
+ qvm_inspector( QWidget *parent = Q_NULLPTR );
+
+ private slots:
+ void on_open();
+ void on_close();
+
+ private:
+ void dbg_print( QString DbgOutput );
+ 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, std::uintptr_t blk_addr = 0ull,
+ QTreeWidgetItem *parent = nullptr );
+ bool init_data();
+
+ Ui::QVMProfilerClass ui;
+ std::uint64_t img_base, module_base, img_size;
+ vm::ctx_t *g_vm_ctx;
+
+ 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/qvirt_instrs.cpp b/src/qvm_virtual_instructions.cpp
similarity index 69%
rename from src/qvirt_instrs.cpp
rename to src/qvm_virtual_instructions.cpp
index f8dbb8e..490121a 100644
--- a/src/qvirt_instrs.cpp
+++ b/src/qvm_virtual_instructions.cpp
@@ -1,11 +1,12 @@
-#include "qvirt_instrs.h"
+#include "qvm_virtual_instructions.h"
-qvirt_instrs_t::qvirt_instrs_t( qvminspector_t *vminspector ) : vminspector( vminspector ), ui( &vminspector->ui )
+qvm_virtual_instructions::qvm_virtual_instructions( qvm_inspector *g_main_window )
+ : g_main_window( g_main_window ), ui( &g_main_window->ui )
{
- connect( ui->virt_instrs, &QTreeWidget::itemSelectionChanged, this, &qvirt_instrs_t::on_select );
+ connect( ui->virt_instrs, &QTreeWidget::itemSelectionChanged, this, &qvm_virtual_instructions::on_select );
}
-void qvirt_instrs_t::on_select()
+void qvm_virtual_instructions::on_select()
{
if ( ui->virt_instrs->selectedItems().empty() )
return;
@@ -15,18 +16,14 @@ void qvirt_instrs_t::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_regs( virt_instr );
- update_virtual_regs( virt_instr );
- update_virtual_stack( virt_instr );
- update_vm_handler_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 qvirt_instrs_t::update_native_regs( vm::instrs::virt_instr_t *virt_instr )
+void qvm_virtual_instructions::update_native_registers( vm::instrs::virt_instr_t *virt_instr )
{
const auto &trace_data = virt_instr->trace_data;
@@ -52,15 +49,15 @@ void qvirt_instrs_t::update_native_regs( vm::instrs::virt_instr_t *virt_instr )
ui->native_regs->topLevelItem( 16 )->child( 8 )->setText( 1, QString::number( flags.interrupt_enable_flag ) );
}
-void qvirt_instrs_t::update_virtual_regs( vm::instrs::virt_instr_t *virt_instr )
+void qvm_virtual_instructions::update_virtual_registers( vm::instrs::virt_instr_t *virt_instr )
{
const auto &trace_data = virt_instr->trace_data;
// set VIP in virtual registers window...
ui->virt_regs->topLevelItem( 0 )->setText(
- 1,
- QString::number(
- ( trace_data.vip - vminspector->file_header->module_base ) + vminspector->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 ) );
@@ -73,38 +70,38 @@ void qvirt_instrs_t::update_virtual_regs( vm::instrs::virt_instr_t *virt_instr )
ui->virt_regs->topLevelItem( idx )->setText( 1, QString::number( trace_data.vregs.qword[ idx - 4 ], 16 ) );
}
-void qvirt_instrs_t::update_virtual_stack( vm::instrs::virt_instr_t *virt_instr )
+void qvm_virtual_instructions::update_virtual_stack( vm::instrs::virt_instr_t *virt_instr )
{
ui->virt_stack->clear();
const auto &trace_data = virt_instr->trace_data;
for ( auto idx = 0u; idx < sizeof( trace_data.vsp ) / 8; ++idx )
{
- auto new_stack_entry = new qtree_widget_item_t();
- new_stack_entry->setText( 0, qstring_t::number( trace_data.regs.rbp + ( idx * 8 ), 16 ) );
- new_stack_entry->setText( 1, qstring_t::number( trace_data.vsp.qword[ idx ], 16 ) );
+ auto new_stack_entry = new QTreeWidgetItem();
+ new_stack_entry->setText( 0, QString::number( trace_data.regs.rbp + ( idx * 8 ), 16 ) );
+ new_stack_entry->setText( 1, QString::number( trace_data.vsp.qword[ idx ], 16 ) );
ui->virt_stack->addTopLevelItem( new_stack_entry );
}
}
-void qvirt_instrs_t::update_vm_handler_info( vm::instrs::virt_instr_t *virt_instr )
+void qvm_virtual_instructions::update_vmhandler_info( vm::instrs::virt_instr_t *virt_instr )
{
char buffer[ 256 ];
ZydisFormatter formatter;
ZydisFormatterInit( &formatter, ZYDIS_FORMATTER_STYLE_INTEL );
ui->vm_handler_instrs->clear();
- const auto &vm_handler_instrs = vminspector->vmctx->vm_handlers[ virt_instr->opcode ].instrs;
+ const auto &vm_handler_instrs = g_main_window->g_vm_ctx->vm_handlers[ virt_instr->opcode ].instrs;
// display vm handler instructions...
for ( const auto &instr : vm_handler_instrs )
{
- auto new_instr = new qtree_widget_item_t();
+ auto new_instr = new QTreeWidgetItem();
new_instr->setText(
- 0, qstring_t::number( ( instr.addr - vminspector->module_base ) + vminspector->image_base, 16 ) );
+ 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 - vminspector->module_base ) + vminspector->image_base );
+ ( instr.addr - g_main_window->module_base ) + g_main_window->img_base );
new_instr->setText( 1, buffer );
ui->vm_handler_instrs->addTopLevelItem( new_instr );
@@ -112,14 +109,14 @@ void qvirt_instrs_t::update_vm_handler_info( vm::instrs::virt_instr_t *virt_inst
// display vm handler transformations...
ui->vm_handler_transforms->clear();
- const auto &vm_handler_transforms = vminspector->vmctx->vm_handlers[ virt_instr->opcode ].transforms;
+ const auto &vm_handler_transforms = g_main_window->g_vm_ctx->vm_handlers[ virt_instr->opcode ].transforms;
for ( auto [ transform_type, transform_instr ] : vm_handler_transforms )
{
if ( transform_type == vm::transform::type::generic0 && transform_instr.mnemonic == ZYDIS_MNEMONIC_INVALID )
continue;
- auto new_transform_entry = new qtree_widget_item_t();
+ auto new_transform_entry = new QTreeWidgetItem();
switch ( transform_type )
{
diff --git a/src/qvm_virtual_instructions.h b/src/qvm_virtual_instructions.h
new file mode 100644
index 0000000..890ce37
--- /dev/null
+++ b/src/qvm_virtual_instructions.h
@@ -0,0 +1,21 @@
+#pragma once
+#include "qvm_inspector.h"
+
+class qvm_virtual_instructions : public QObject
+{
+ Q_OBJECT
+ public:
+ explicit qvm_virtual_instructions( qvm_inspector *g_main_window );
+
+ private:
+ Ui::QVMProfilerClass *ui;
+ qvm_inspector *g_main_window;
+
+ void update_native_registers( vm::instrs::virt_instr_t *virt_instr );
+ void update_virtual_registers( vm::instrs::virt_instr_t *virt_instr );
+ void update_virtual_stack( vm::instrs::virt_instr_t *virt_instr );
+ void update_vmhandler_info( vm::instrs::virt_instr_t *virt_instr );
+
+ private slots:
+ void on_select();
+};
\ No newline at end of file
diff --git a/src/qvm_virtual_routines.cpp b/src/qvm_virtual_routines.cpp
new file mode 100644
index 0000000..a230dd5
--- /dev/null
+++ b/src/qvm_virtual_routines.cpp
@@ -0,0 +1,112 @@
+#include "qvm_virtual_routines.h"
+
+qvm_virtual_routines::qvm_virtual_routines( qvm_inspector *g_main_window )
+ : g_main_window( g_main_window ), ui( &g_main_window->ui )
+{
+ connect( ui->virtual_machine_enters, &QTreeWidget::itemSelectionChanged, this, &qvm_virtual_routines::on_select );
+}
+
+void qvm_virtual_routines::update_vm_enter( vm::ctx_t *g_vm_ctx )
+{
+ char buffer[ 256 ];
+ ZydisFormatter formatter;
+ ZydisFormatterInit( &formatter, ZYDIS_FORMATTER_STYLE_INTEL );
+
+ ui->virtual_machine_enter_instrs->clear();
+ for ( auto [ instr, raw, addr ] : g_vm_ctx->vm_entry )
+ {
+ ZydisFormatterFormatInstruction( &formatter, &instr, buffer, sizeof( buffer ),
+ ( addr - g_main_window->module_base ) + g_vm_ctx->image_base );
+
+ auto newItem = new QTreeWidgetItem();
+ newItem->setText( 0, QString::number( ( addr - g_main_window->module_base ) + g_vm_ctx->image_base, 16 ) );
+ newItem->setText( 1, buffer );
+ ui->virtual_machine_enter_instrs->addTopLevelItem( newItem );
+ }
+}
+
+void qvm_virtual_routines::update_calc_jmp( vm::ctx_t *g_vm_ctx )
+{
+ char buffer[ 256 ];
+ ZydisFormatter formatter;
+ ZydisFormatterInit( &formatter, ZYDIS_FORMATTER_STYLE_INTEL );
+
+ ui->virtual_machine_enter_calc_jmp->clear();
+ for ( auto [ instr, raw, addr ] : g_vm_ctx->calc_jmp )
+ {
+ ZydisFormatterFormatInstruction( &formatter, &instr, buffer, sizeof( buffer ),
+ ( addr - g_main_window->module_base ) + g_vm_ctx->image_base );
+
+ auto newItem = new QTreeWidgetItem();
+ newItem->setText( 0, QString::number( ( addr - g_main_window->module_base ) + g_vm_ctx->image_base, 16 ) );
+ newItem->setText( 1, buffer );
+ ui->virtual_machine_enter_calc_jmp->addTopLevelItem( newItem );
+ }
+}
+
+void qvm_virtual_routines::update_vm_handlers( vm::ctx_t *g_vm_ctx )
+{
+ ui->virt_handlers_tree->clear();
+ for ( auto idx = 0u; idx < g_vm_ctx->vm_handlers.size(); ++idx )
+ {
+ auto newItem = new QTreeWidgetItem;
+ newItem->setData( 0, Qt::UserRole, idx );
+ newItem->setText( 0, QString( "%1" ).arg( idx ) );
+ newItem->setText( 1,
+ QString( "%1" ).arg( ( g_vm_ctx->vm_handlers[ idx ].address - g_main_window->module_base ) +
+ g_main_window->img_base,
+ 0, 16 ) );
+
+ newItem->setText( 2, g_vm_ctx->vm_handlers[ idx ].profile ? g_vm_ctx->vm_handlers[ idx ].profile->name
+ : "UNDEFINED" );
+
+ newItem->setText( 3, QString( "%1" ).arg( g_vm_ctx->vm_handlers[ idx ].imm_size ) );
+
+ if ( g_vm_ctx->vm_handlers[ idx ].profile && g_vm_ctx->vm_handlers[ idx ].imm_size )
+ newItem->setText( 4,
+ g_vm_ctx->vm_handlers[ idx ].profile->extention == vm::handler::extention_t::sign_extend
+ ? "SIGN EXTENDED"
+ : "ZERO EXTENDED" );
+ else
+ newItem->setText( 4, "UNDEFINED" );
+
+ ui->virt_handlers_tree->addTopLevelItem( newItem );
+ }
+ ui->virt_handlers_tree->topLevelItem( 0 )->setSelected( true );
+}
+
+void qvm_virtual_routines::on_select()
+{
+ if ( ui->virtual_machine_enters->selectedItems().empty() )
+ return;
+
+ auto item = ui->virtual_machine_enters->selectedItems()[ 0 ];
+
+ if ( !item || !item->childCount() )
+ return;
+
+ auto entry_rva = item->data( 0, Qt::UserRole ).value< std::uint32_t >();
+
+ if ( !entry_rva )
+ return;
+
+ if ( g_main_window->g_vm_ctx )
+ delete g_main_window->g_vm_ctx;
+
+ g_main_window->g_vm_ctx =
+ new vm::ctx_t( g_main_window->module_base, g_main_window->img_base, g_main_window->img_size, entry_rva );
+
+ if ( !g_main_window->g_vm_ctx->init() )
+ {
+ g_main_window->dbg_msg( "[!] failed to init vm::ctx_t...\n" );
+ return;
+ }
+
+ 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/qvm_virtual_routines.h b/src/qvm_virtual_routines.h
new file mode 100644
index 0000000..39053d0
--- /dev/null
+++ b/src/qvm_virtual_routines.h
@@ -0,0 +1,19 @@
+#pragma once
+#include "qvm_inspector.h"
+
+class qvm_virtual_routines : public QObject
+{
+ Q_OBJECT
+ public:
+ explicit qvm_virtual_routines( qvm_inspector *g_main_window );
+
+ private:
+ Ui::QVMProfilerClass *ui;
+ qvm_inspector *g_main_window;
+
+ void update_vm_enter( vm::ctx_t *g_vm_ctx );
+ void update_calc_jmp( vm::ctx_t *g_vm_ctx );
+ void update_vm_handlers( vm::ctx_t *g_vm_ctx );
+ private slots:
+ void on_select();
+};
\ No newline at end of file
diff --git a/src/qvminspector.cpp b/src/qvminspector.cpp
deleted file mode 100644
index 3e0b151..0000000
--- a/src/qvminspector.cpp
+++ /dev/null
@@ -1,385 +0,0 @@
-#include "qvminspector.h"
-
-qvminspector_t::qvminspector_t( qwidget_t *parent ) : qmain_window_t( parent ), file_header( nullptr ), vmctx( nullptr )
-{
- ui.setupUi( this );
- ui.virt_instrs->setColumnWidth( 0, 180 );
- ui.virt_instrs->setColumnWidth( 1, 150 );
- ui.virt_instrs->setColumnWidth( 2, 190 );
- ui.virt_instrs->setColumnWidth( 3, 200 );
-
- connect( ui.action_open, &QAction::triggered, this, &qvminspector_t::on_open );
- connect( ui.action_close, &QAction::triggered, this, &qvminspector_t::on_close );
-}
-
-void qvminspector_t::on_close()
-{
- exit( 0 );
-}
-
-void qvminspector_t::on_open()
-{
- if ( file_header && vmctx )
- {
- free( file_header );
- delete vmctx;
- }
-
- file_header = nullptr, first_block = nullptr;
- code_block_addrs.clear();
- image_base = 0u, vm_entry_rva = 0u, module_base = 0u;
-
- file_path = QFileDialog::getOpenFileName(
- this, tr( "open vmp2 file" ), std::filesystem::current_path().string().c_str(), tr( "vmp2 file (*.vmp2)" ) );
-
- const auto &_file_path = file_path.toStdString();
-
- if ( file_path.isEmpty() )
- {
- dbg_msg( "invalid vmp2 file... no file selected..." );
- return;
- }
-
- if ( !std::filesystem::exists( _file_path ) )
- {
- dbg_msg( "vmp2 file does not exist..." );
- return;
- }
-
- const auto file_size = std::filesystem::file_size( _file_path );
-
- if ( !file_size )
- {
- dbg_msg( "invalid vmp2 file size..." );
- return;
- }
-
- qfile_t open_file( file_path );
- file_header = reinterpret_cast< vmp2::v3::file_header * >( malloc( file_size ) );
-
- if ( !open_file.open( QIODevice::ReadOnly ) )
- {
- dbg_msg( "failed to open vmp2 file..." );
- return;
- }
-
- memcpy( file_header, open_file.readAll().data(), file_size );
-
- if ( !init_data() )
- {
- dbg_msg( "failed to init vmp2 file data..." );
- return;
- }
-
- update_ui();
-}
-
-void qvminspector_t::dbg_print( qstring_t dbg_output )
-{
- ui.dbg_output_window->appendPlainText( dbg_output );
-}
-
-void qvminspector_t::dbg_msg( qstring_t dbg_output )
-{
- qmsg_box_t msg_box;
- msg_box.setText( dbg_output );
- msg_box.exec();
- dbg_print( dbg_output );
-}
-
-bool qvminspector_t::init_data()
-{
- if ( file_header->magic != VMP_MAGIC )
- {
- dbg_msg( "invalid magic bytes for vmp2 file..." );
-
- return false;
- }
-
- dbg_print( "valid magic bytes for vmp2 file..." );
-
- if ( file_header->version != vmp2::version_t::v3 )
- {
- dbg_msg( "invalid vmp2 file version... "
- "this vminspector is compiled for version 3...\n" );
-
- return false;
- }
-
- vm_entry_rva = file_header->vm_entry_rva;
- image_base = file_header->image_base;
- 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 ) );
-
- // 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()
-{
- // add vm handlers to the vm handler tree...
- ui.virt_handlers_tree->clear();
- for ( auto idx = 0u; idx < vmctx->vm_handlers.size(); ++idx )
- {
- 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 );
- }
- 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 )
- {
- 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 )
- {
- 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 );
- }
- }
-
-finish: // bad code...
- ui.virt_instrs->topLevelItem( 0 )->setSelected( true );
-}
\ No newline at end of file
diff --git a/src/qvminspector.h b/src/qvminspector.h
deleted file mode 100644
index 5f80b65..0000000
--- a/src/qvminspector.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#pragma once
-#define NOMINMAX
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-#include "ui_qvminspector.h"
-#include
-#include
-
-#define ABS_TO_IMG( addr, mod_base, img_base ) ( addr - mod_base ) + img_base
-Q_DECLARE_METATYPE( vm::instrs::virt_instr_t * )
-
-using qmain_window_t = QMainWindow;
-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
-{
- friend class qvirt_instrs_t;
- friend class qvirt_handlers_t;
- Q_OBJECT
- public:
- qvminspector_t( qwidget_t *parent = Q_NULLPTR );
-
- private slots:
- void on_open();
- void on_close();
-
- private:
- void dbg_print( qstring_t DbgOutput );
- void dbg_msg( qstring_t DbgOutput );
- void update_ui();
- void add_branch_children( qtree_widget_item_t *item, std::uintptr_t branch_addr );
- bool init_data();
-
- Ui::QVMProfilerClass ui;
- qstring_t file_path;
- 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;
-};
\ No newline at end of file
diff --git a/src/qvminspector.ui b/src/qvminspector.ui
index 1561742..e59fcfc 100644
--- a/src/qvminspector.ui
+++ b/src/qvminspector.ui
@@ -6,8 +6,8 @@
0
0
- 1496
- 1093
+ 1247
+ 849
@@ -27,7 +27,7 @@
-
- 0
+ 2
@@ -44,8 +44,8 @@
0
0
- 1452
- 854
+ 1203
+ 610
@@ -414,8 +414,8 @@
0
0
- 672
- 228
+ 556
+ 149
@@ -604,6 +604,96 @@
+
+
+ Virtual Routines
+
+
+ -
+
+
+ Virtual Machine Enters
+
+
+
-
+
+
+
+ Name
+
+
+
+
+ Address
+
+
+
+
+ Number Of Nodes
+
+
+
+
+
+
+
+ -
+
+
+ Virtual Machine Enter Information
+
+
+
-
+
+
+ Virtual Machine - Enter Instructions
+
+
+
-
+
+
+
+ Address
+
+
+
+
+ Instruction
+
+
+
+
+
+
+
+ -
+
+
+ Virtual Machine - Calc Jmp
+
+
+
-
+
+
+
+ Address
+
+
+
+
+ Instruction
+
+
+
+
+
+
+
+
+
+
+
+
@@ -613,7 +703,7 @@
0
0
- 1496
+ 1247
21