parent
c44d49534e
commit
6e8bf93445
@ -1 +1 @@
|
||||
Subproject commit e58c23c40e13528f5d9b84feb7e23b62a886ed5a
|
||||
Subproject commit e95ef2537184639e89a4dbbd38355a11ffc46bac
|
@ -1,300 +0,0 @@
|
||||
#include "QVMProfiler.h"
|
||||
|
||||
QVMProfiler::QVMProfiler( QWidget *parent ) : QMainWindow( parent ), TraceFileBlob( nullptr ), VMCtx( nullptr )
|
||||
{
|
||||
ui.setupUi( this );
|
||||
}
|
||||
|
||||
void QVMProfiler::on_actionCloseProgram_triggered()
|
||||
{
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
void QVMProfiler::on_actionOpen_VMTrace_triggered()
|
||||
{
|
||||
if ( TraceFileBlob && VMCtx )
|
||||
{
|
||||
free( TraceFileBlob );
|
||||
TraceFileBlob = nullptr;
|
||||
TraceFileHeader = nullptr;
|
||||
TraceEntryList = nullptr;
|
||||
VMHandlerTable = nullptr;
|
||||
|
||||
ImageBase = NULL;
|
||||
VMEntryRva = NULL;
|
||||
ModuleBase = NULL;
|
||||
|
||||
VMHandlers.clear();
|
||||
VMEntry.clear();
|
||||
delete VMCtx;
|
||||
}
|
||||
|
||||
TraceFilePath = QFileDialog::getOpenFileName( this, tr( "Open Trace" ), "C:\\", tr( "VMTrace Files (*.vmp2)" ) );
|
||||
|
||||
if ( TraceFilePath.isEmpty() )
|
||||
{
|
||||
DbgMessage( "Invalid Trace File... No File Selected..." );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !std::filesystem::exists( TraceFilePath.toStdString().c_str() ) )
|
||||
{
|
||||
DbgMessage( "Trace File Doesnt Exist..." );
|
||||
return;
|
||||
}
|
||||
|
||||
const auto TraceFileSize = std::filesystem::file_size( TraceFilePath.toStdString().c_str() );
|
||||
|
||||
if ( !TraceFileSize )
|
||||
{
|
||||
DbgMessage( "Invalid Trace File Size..." );
|
||||
return;
|
||||
}
|
||||
|
||||
QFile File( TraceFilePath );
|
||||
TraceFileBlob = malloc( TraceFileSize );
|
||||
DbgMessage( QString( "Loading Trace File %1..." ).arg( TraceFilePath ) );
|
||||
|
||||
if(!File.open( QIODevice::ReadOnly ))
|
||||
{
|
||||
DbgMessage( "Failed To Open Trace File..." );
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy( TraceFileBlob, File.readAll().data(), TraceFileSize );
|
||||
|
||||
if ( !InitTraceData() )
|
||||
{
|
||||
DbgMessage( "Failed To Init Trace Data..." );
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
void QVMProfiler::DbgPrint( QString DbgOutput )
|
||||
{
|
||||
ui.DbgOutputWindow->appendPlainText( DbgOutput );
|
||||
}
|
||||
|
||||
void QVMProfiler::DbgMessage( QString DbgOutput )
|
||||
{
|
||||
QMessageBox MsgBox;
|
||||
MsgBox.setText( DbgOutput );
|
||||
MsgBox.exec();
|
||||
DbgPrint( DbgOutput );
|
||||
}
|
||||
|
||||
bool QVMProfiler::InitTraceData()
|
||||
{
|
||||
TraceFileHeader = reinterpret_cast< vmp2::v2::file_header * >( TraceFileBlob );
|
||||
TraceEntryList = reinterpret_cast< vmp2::v2::entry_t * >( reinterpret_cast< std::uintptr_t >( TraceFileBlob ) +
|
||||
TraceFileHeader->entry_offset );
|
||||
|
||||
const auto TraceMagicBytes = &TraceFileHeader->magic;
|
||||
if ( memcmp( TraceMagicBytes, "VMP2", sizeof "VMP2" - 1 ) != 0 )
|
||||
{
|
||||
DbgMessage( "Trace File Magic Bytes Are Invalid...\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
VMEntryRva = TraceFileHeader->vm_entry_rva;
|
||||
ImageBase = TraceFileHeader->image_base;
|
||||
ModuleBase = reinterpret_cast< std::uintptr_t >( TraceFileHeader ) + TraceFileHeader->module_offset;
|
||||
|
||||
DbgPrint( "Trace File Magic Bytes Are Valid...." );
|
||||
if ( !vm::util::flatten( VMEntry, VMEntryRva + ModuleBase ) )
|
||||
{
|
||||
DbgMessage( "Failed To Flatten VMEntry...\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
vm::util::deobfuscate( VMEntry );
|
||||
DbgPrint( "Flattened VMEntry..." );
|
||||
DbgPrint( "Deobfuscated VMEntry..." );
|
||||
|
||||
char buffer[ 256 ];
|
||||
ZydisFormatter formatter;
|
||||
ZydisFormatterInit( &formatter, ZYDIS_FORMATTER_STYLE_INTEL );
|
||||
|
||||
for ( auto &Instr : VMEntry )
|
||||
{
|
||||
ZydisFormatterFormatInstruction( &formatter, &Instr.instr, buffer, sizeof( buffer ),
|
||||
( Instr.addr - TraceFileHeader->module_base ) + ImageBase );
|
||||
|
||||
DbgPrint( QString( "> %1 %2" )
|
||||
.arg( QString::number( ( Instr.addr - TraceFileHeader->module_base ) + ImageBase, 16 ) )
|
||||
.arg( buffer ) );
|
||||
}
|
||||
|
||||
VMHandlerTable = vm::handler::table::get( VMEntry );
|
||||
if ( !vm::handler::get_all( ModuleBase, ImageBase, VMEntry, VMHandlerTable, VMHandlers ) )
|
||||
{
|
||||
DbgMessage( "Failed To Get All VM Handler Meta Data...\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
DbgPrint( "Located All VM Handlers..." );
|
||||
VMCtx = new vm::vmctx_t( TraceFileHeader, TraceEntryList, VMHandlers, ModuleBase, ImageBase );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QVMProfiler::UpdateUI()
|
||||
{
|
||||
ui.VirtualInstructionTree->clear();
|
||||
for ( auto [ VirtInstr, TraceEntry ] = VMCtx->step(); TraceEntry && !VirtInstr.empty();
|
||||
std::tie( VirtInstr, TraceEntry ) = VMCtx->step() )
|
||||
{
|
||||
auto InstructionTraceData = new QTreeWidgetItem();
|
||||
InstructionTraceData->setText(
|
||||
0, QString::number( ( TraceEntry->vip - TraceFileHeader->module_base ) + ImageBase, 16 ) );
|
||||
|
||||
if ( VMHandlers[ TraceEntry->handler_idx ].imm_size )
|
||||
{
|
||||
QString SecondOperandBytes;
|
||||
auto numByteOperand = VMHandlers[ TraceEntry->handler_idx ].imm_size / 8;
|
||||
auto spaceIdx = VirtInstr.find( " " ) + 1;
|
||||
auto ImmValue =
|
||||
QString( VirtInstr.substr( spaceIdx, VirtInstr.size() - spaceIdx ).c_str() ).toULongLong( nullptr, 16 );
|
||||
|
||||
for ( auto idx = 0u; idx < numByteOperand; ++idx )
|
||||
{
|
||||
SecondOperandBytes.append(
|
||||
QString::number( *( reinterpret_cast< std::uint8_t * >( &ImmValue ) + idx ), 16 ) );
|
||||
|
||||
SecondOperandBytes.append( " " );
|
||||
}
|
||||
|
||||
InstructionTraceData->setText(
|
||||
1, QString::number( TraceEntry->handler_idx, 16 ).append( " - " ).append( SecondOperandBytes ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// else we just put the first operand byte (vm handler index)...
|
||||
InstructionTraceData->setText( 1, QString::number( TraceEntry->handler_idx, 16 ) );
|
||||
}
|
||||
|
||||
InstructionTraceData->setText( 2, VirtInstr.c_str() );
|
||||
ui.VirtualInstructionTree->addTopLevelItem( InstructionTraceData );
|
||||
}
|
||||
ui.VirtualInstructionTree->topLevelItem( 0 )->setSelected( true );
|
||||
}
|
||||
|
||||
void QVMProfiler::on_VirtualInstructionTree_itemSelectionChanged()
|
||||
{
|
||||
auto SelectedItem = ui.VirtualInstructionTree->selectedItems()[ 0 ];
|
||||
auto VIPAddr = SelectedItem->data( 0, 0 ).toString().toULongLong( nullptr, 16 );
|
||||
vmp2::v2::entry_t *Entry = nullptr;
|
||||
|
||||
for ( auto idx = 0u; idx < TraceFileHeader->entry_count; ++idx )
|
||||
{
|
||||
if ( ( TraceEntryList[ idx ].vip - TraceFileHeader->module_base ) + ImageBase == VIPAddr )
|
||||
{
|
||||
Entry = &TraceEntryList[ idx ];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ui.VirtualRegisterTree->topLevelItem( 0 )->setText(
|
||||
1, QString::number( ( Entry->vip - TraceFileHeader->module_base ) + ImageBase, 16 ) );
|
||||
|
||||
ui.VirtualRegisterTree->topLevelItem( 1 )->setText( 1, QString::number( Entry->regs.rbp, 16 ) );
|
||||
|
||||
ui.VirtualRegisterTree->topLevelItem( 2 )->setText( 1, QString::number( Entry->decrypt_key, 16 ) );
|
||||
|
||||
for ( auto idx = 4; idx < 28; ++idx )
|
||||
ui.VirtualRegisterTree->topLevelItem( idx )->setText( 1, QString::number( Entry->vregs.qword[ idx - 4 ], 16 ) );
|
||||
|
||||
for ( auto idx = 0u; idx < 15; ++idx )
|
||||
ui.NativeRegisterTree->topLevelItem( idx )->setText( 1, QString::number( Entry->regs.raw[ idx ], 16 ) );
|
||||
|
||||
ui.NativeRegisterTree->topLevelItem( 16 )->setText( 1, QString::number( Entry->regs.rflags, 16 ) );
|
||||
|
||||
rflags flags;
|
||||
flags.flags = Entry->regs.rflags;
|
||||
ui.NativeRegisterTree->topLevelItem( 16 )->child( 0 )->setText( 1, QString::number( flags.zero_flag ) );
|
||||
|
||||
ui.NativeRegisterTree->topLevelItem( 16 )->child( 1 )->setText( 1, QString::number( flags.parity_flag ) );
|
||||
|
||||
ui.NativeRegisterTree->topLevelItem( 16 )->child( 2 )->setText( 1, QString::number( flags.auxiliary_carry_flag ) );
|
||||
|
||||
ui.NativeRegisterTree->topLevelItem( 16 )->child( 3 )->setText( 1, QString::number( flags.overflow_flag ) );
|
||||
|
||||
ui.NativeRegisterTree->topLevelItem( 16 )->child( 4 )->setText( 1, QString::number( flags.sign_flag ) );
|
||||
|
||||
ui.NativeRegisterTree->topLevelItem( 16 )->child( 5 )->setText( 1, QString::number( flags.direction_flag ) );
|
||||
|
||||
ui.NativeRegisterTree->topLevelItem( 16 )->child( 6 )->setText( 1, QString::number( flags.carry_flag ) );
|
||||
|
||||
ui.NativeRegisterTree->topLevelItem( 16 )->child( 7 )->setText( 1, QString::number( flags.trap_flag ) );
|
||||
|
||||
ui.NativeRegisterTree->topLevelItem( 16 )->child( 8 )->setText( 1, QString::number( flags.interrupt_enable_flag ) );
|
||||
|
||||
ui.VirtualStackTree->clear();
|
||||
for ( auto idx = 0u; idx < sizeof( Entry->vsp ) / 8; ++idx )
|
||||
{
|
||||
auto newEntry = new QTreeWidgetItem();
|
||||
newEntry->setText( 0, QString::number( Entry->regs.rbp - ( idx * 8 ), 16 ) );
|
||||
newEntry->setText( 1, QString::number( Entry->vsp.qword[ idx ], 16 ) );
|
||||
ui.VirtualStackTree->addTopLevelItem( newEntry );
|
||||
}
|
||||
|
||||
ui.VMHandlerInstructionsTree->clear();
|
||||
auto InstrVec = &VMHandlers[ Entry->handler_idx ].instrs;
|
||||
|
||||
char buffer[ 256 ];
|
||||
ZydisFormatter formatter;
|
||||
ZydisFormatterInit( &formatter, ZYDIS_FORMATTER_STYLE_INTEL );
|
||||
|
||||
for ( auto idx = 0u; idx < InstrVec->size(); ++idx )
|
||||
{
|
||||
auto newEntry = new QTreeWidgetItem();
|
||||
newEntry->setText( 0, QString::number( ( InstrVec->at( idx ).addr - ModuleBase ) + ImageBase, 16 ) );
|
||||
|
||||
ZydisFormatterFormatInstruction( &formatter, &InstrVec->at( idx ).instr, buffer, sizeof( buffer ),
|
||||
( InstrVec->at( idx ).addr - ModuleBase ) + ImageBase );
|
||||
|
||||
newEntry->setText( 1, buffer );
|
||||
ui.VMHandlerInstructionsTree->addTopLevelItem( newEntry );
|
||||
}
|
||||
|
||||
ui.VMHandlerTransformationsTree->clear();
|
||||
auto HandlerTransforms = &VMHandlers[ Entry->handler_idx ].transforms;
|
||||
|
||||
for ( auto [ TransformType, TransformInstr ] : *HandlerTransforms )
|
||||
{
|
||||
if ( TransformType == vm::transform::type::generic0 && TransformInstr.mnemonic == ZYDIS_MNEMONIC_INVALID )
|
||||
continue;
|
||||
|
||||
auto newEntry = new QTreeWidgetItem();
|
||||
switch ( TransformType )
|
||||
{
|
||||
case vm::transform::type::rolling_key:
|
||||
{
|
||||
newEntry->setText( 0, "Key Transform" );
|
||||
break;
|
||||
}
|
||||
case vm::transform::type::generic0:
|
||||
case vm::transform::type::generic1:
|
||||
case vm::transform::type::generic2:
|
||||
case vm::transform::type::generic3:
|
||||
{
|
||||
newEntry->setText( 0, "Generic" );
|
||||
break;
|
||||
}
|
||||
case vm::transform::type::update_key:
|
||||
{
|
||||
newEntry->setText( 0, "Update Key" );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::invalid_argument( "invalid transformation type..." );
|
||||
}
|
||||
|
||||
ZydisFormatterFormatInstruction( &formatter, &TransformInstr, buffer, sizeof( buffer ), NULL );
|
||||
|
||||
newEntry->setText( 1, buffer );
|
||||
ui.VMHandlerTransformationsTree->addTopLevelItem( newEntry );
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
#pragma once
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QInputDialog.h>
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <QtWidgets/QMessageBox.h>
|
||||
#include <Windows.h>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <vmprofiler.hpp>
|
||||
|
||||
#include "ia32.hpp"
|
||||
#include "ui_QVMProfiler.h"
|
||||
#include "vmctx.h"
|
||||
#include "vmp2.hpp"
|
||||
|
||||
class QVMProfiler : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QVMProfiler( QWidget *parent = Q_NULLPTR );
|
||||
|
||||
private slots:
|
||||
void on_actionOpen_VMTrace_triggered();
|
||||
void on_actionCloseProgram_triggered();
|
||||
void on_VirtualInstructionTree_itemSelectionChanged();
|
||||
|
||||
private:
|
||||
void DbgPrint( QString DbgOutput );
|
||||
void DbgMessage( QString DbgOutput );
|
||||
void UpdateUI();
|
||||
bool InitTraceData();
|
||||
|
||||
Ui::QVMProfilerClass ui;
|
||||
QString TraceFilePath;
|
||||
QString VMProtectedFilePath;
|
||||
std::uint64_t ImageBase, VMEntryRva, ModuleBase;
|
||||
|
||||
std::vector< vm::handler::handler_t > VMHandlers;
|
||||
zydis_routine_t VMEntry;
|
||||
|
||||
std::uintptr_t *VMHandlerTable;
|
||||
vm::vmctx_t *VMCtx;
|
||||
|
||||
void *TraceFileBlob;
|
||||
vmp2::v2::file_header *TraceFileHeader;
|
||||
vmp2::v2::entry_t *TraceEntryList;
|
||||
};
|
@ -0,0 +1,146 @@
|
||||
#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, 100 );
|
||||
ui.virt_instrs->setColumnWidth( 1, 125 );
|
||||
ui.virt_instrs->setColumnWidth( 2, 250 );
|
||||
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;
|
||||
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 ) );
|
||||
dbg_msg( QString( "loading vmp2 file %1..." ).arg( file_path ) );
|
||||
|
||||
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 )
|
||||
{
|
||||
QMessageBox MsgBox;
|
||||
MsgBox.setText( dbg_output );
|
||||
MsgBox.exec();
|
||||
dbg_print( dbg_output );
|
||||
}
|
||||
|
||||
bool qvminspector_t::init_data()
|
||||
{
|
||||
if ( file_header->magic != VMP_MAGIC )
|
||||
{
|
||||
dbg_msg( "invalid magic bytes for vmp2 file...\n" );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
dbg_print( "valid magic bytes for vmp2 file...\n" );
|
||||
|
||||
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;
|
||||
|
||||
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 );
|
||||
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;
|
||||
code_block = reinterpret_cast< vmp2::v3::code_block_t * >( reinterpret_cast< std::uintptr_t >( code_block ) +
|
||||
code_block->next_block_offset ), ++idx)
|
||||
{
|
||||
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()
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QInputDialog.h>
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <QtWidgets/QMessageBox.h>
|
||||
#include <Windows.h>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <vmprofiler.hpp>
|
||||
|
||||
#include "ia32.hpp"
|
||||
#include "vmp2.hpp"
|
||||
#include "ui_qvminspector.h"
|
||||
|
||||
using qmain_window_t = QMainWindow;
|
||||
using qwidget_t = QWidget;
|
||||
using qstring_t = QString;
|
||||
using qfile_t = QFile;
|
||||
using qtree_widget_item_t = QTreeWidgetItem;
|
||||
|
||||
class qvminspector_t : public qmain_window_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();
|
||||
bool init_data();
|
||||
|
||||
Ui::QVMProfilerClass ui;
|
||||
qstring_t file_path;
|
||||
qstring_t VMProtectedFilePath;
|
||||
std::uint64_t image_base, vm_entry_rva, module_base;
|
||||
vm::ctx_t *vmctx;
|
||||
|
||||
vmp2::v3::file_header *file_header;
|
||||
vmp2::v3::code_block_t *first_block;
|
||||
};
|
@ -1,87 +0,0 @@
|
||||
#include "vmctx.h"
|
||||
|
||||
namespace vm
|
||||
{
|
||||
vmctx_t::vmctx_t( vmp2::v2::file_header *file_header, vmp2::v2::entry_t *entry_list,
|
||||
std::vector< vm::handler::handler_t > &vm_handlers, std::uintptr_t module_base, std::uintptr_t image_base )
|
||||
: module_base( module_base ), image_base( image_base ), entry_list( entry_list ), file_header( file_header ),
|
||||
vm_handlers( vm_handlers ), idx( 0 )
|
||||
{}
|
||||
|
||||
std::pair< std::string, const vmp2::v2::entry_t * > vmctx_t::step() const
|
||||
{
|
||||
if ( idx >= file_header->entry_count )
|
||||
return {};
|
||||
|
||||
auto vm_handler = vm_handlers[ entry_list[ idx ].handler_idx ];
|
||||
|
||||
if ( vm_handler.imm_size )
|
||||
{
|
||||
const auto operand = get_imm( file_header->advancement, entry_list[ idx ].vip, vm_handler.imm_size / 8 );
|
||||
|
||||
auto [ decrypted_operand, rolling_key ] =
|
||||
vm::instrs::decrypt_operand( vm_handler.transforms, operand, entry_list[ idx ].decrypt_key );
|
||||
|
||||
if ( vm_handler.profile )
|
||||
{
|
||||
if ( vm_handler.profile->extention == vm::handler::extention_t::sign_extend )
|
||||
{
|
||||
switch ( vm_handler.imm_size )
|
||||
{
|
||||
case 8:
|
||||
if ( ( u8 )( decrypted_operand >> 7 ) )
|
||||
decrypted_operand += ~0xFFull;
|
||||
break;
|
||||
case 16:
|
||||
if ( ( u16 )( decrypted_operand >> 15 ) )
|
||||
decrypted_operand += ~0xFFFFull;
|
||||
break;
|
||||
case 32:
|
||||
if ( ( u32 )( decrypted_operand >> 31 ) )
|
||||
decrypted_operand += ~0xFFFFFFFFull;
|
||||
break;
|
||||
default:
|
||||
throw std::invalid_argument( "invalid imm size for sign extention...\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char buff[ 256 ];
|
||||
if ( vm_handler.profile )
|
||||
snprintf( buff, sizeof buff, "%s 0x%p", vm_handler.profile->name, decrypted_operand );
|
||||
else
|
||||
snprintf( buff, sizeof buff, "UNK(%d) 0x%p", entry_list[ idx ].handler_idx, decrypted_operand );
|
||||
|
||||
return { buff, &entry_list[ idx++ ] };
|
||||
}
|
||||
|
||||
if ( vm_handler.profile )
|
||||
return { vm_handler.profile->name, &entry_list[ idx++ ] };
|
||||
|
||||
char buff[ 256 ];
|
||||
snprintf( buff, sizeof buff, "UNK(%d)", entry_list[ idx ].handler_idx );
|
||||
return { buff, &entry_list[ idx++ ] };
|
||||
}
|
||||
|
||||
std::uintptr_t vmctx_t::get_imm( vmp2::exec_type_t exec_type_t, std::uint32_t vip_offset,
|
||||
std::uint8_t imm_size ) const
|
||||
{
|
||||
std::uintptr_t operand = 0u;
|
||||
if ( file_header->advancement == vmp2::exec_type_t::forward )
|
||||
{
|
||||
const auto operand_ptr =
|
||||
reinterpret_cast< void * >( ( entry_list[ idx ].vip - file_header->module_base ) + module_base );
|
||||
|
||||
memcpy( &operand, operand_ptr, imm_size );
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto operand_ptr = reinterpret_cast< void * >(
|
||||
( ( entry_list[ idx ].vip - file_header->module_base ) + module_base ) - imm_size );
|
||||
|
||||
memcpy( &operand, operand_ptr, imm_size );
|
||||
}
|
||||
|
||||
return operand;
|
||||
}
|
||||
} // namespace vm
|
@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
#include <vmprofiler.hpp>
|
||||
|
||||
namespace vm
|
||||
{
|
||||
class vmctx_t
|
||||
{
|
||||
public:
|
||||
explicit vmctx_t( vmp2::v2::file_header *file_header, vmp2::v2::entry_t *entry_list,
|
||||
std::vector< vm::handler::handler_t > &vm_handlers, std::uintptr_t module_base,
|
||||
std::uintptr_t image_base );
|
||||
|
||||
std::pair< std::string, const vmp2::v2::entry_t * > step() const;
|
||||
|
||||
private:
|
||||
std::uintptr_t get_imm( vmp2::exec_type_t exec_type_t, std::uint32_t vip_offset, std::uint8_t imm_size ) const;
|
||||
|
||||
mutable std::uint32_t idx;
|
||||
const std::uintptr_t image_base, module_base;
|
||||
const vmp2::v2::entry_t *entry_list;
|
||||
const vmp2::v2::file_header *file_header;
|
||||
std::vector< vm::handler::handler_t > vm_handlers;
|
||||
};
|
||||
} // namespace vm
|
Loading…
Reference in new issue