You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
vmhook/src/vmhook.cpp

116 lines
3.8 KiB

#include "vmhook.hpp"
namespace vm
{
namespace handler
{
table_t::table_t( u64 module_base, u64 image_base, u32 table_rva, vm::handler::edit_entry_t edit_entry,
vm::decrypt_handler_t decrypt_handler, vm::encrypt_handler_t encrypt_handler )
: module_base( module_base ), image_base( image_base ), table_rva( table_rva ), edit_entry( edit_entry ),
decrypt_handler( decrypt_handler ), encrypt_handler( encrypt_handler )
{
table_addr = reinterpret_cast< u64 * >( module_base + table_rva );
for ( auto idx = 0u; idx < 256; ++idx )
{
entry_t entry;
entry.decrypted = decrypt( idx );
entry.encrypted = get_entry( idx );
entry.virt = ( entry.decrypted - image_base ) + module_base;
entry.callback = nullptr;
handlers[ idx ] = entry;
}
}
u64 table_t::get_entry( u8 idx ) const
{
return table_addr[ idx ];
}
entry_t table_t::get_meta_data( u8 idx ) const
{
return handlers[ idx ];
}
void table_t::set_entry( u8 idx, u64 entry )
{
edit_entry( table_addr + idx, entry );
}
void table_t::set_meta_data( u8 idx, const entry_t &entry )
{
handlers[ idx ] = entry;
}
void table_t::set_callback( u8 idx, entry_callback_t callback )
{
handlers[ idx ].callback = callback;
}
u64 table_t::decrypt( u8 idx )
{
return decrypt_handler( get_entry( idx ) );
}
u64 table_t::encrypt( u64 val )
{
return encrypt_handler( val );
}
} // namespace handler
hook_t::hook_t( void ) : table_count( 0 )
{
for ( auto idx = 0u; idx < 10; ++idx )
handler_tables[ idx ] = nullptr;
}
void hook_t::add_table( vm::handler::table_t *table )
{
handler_tables[ table_count ] = table;
++table_count;
}
void hook_t::start( void )
{
for ( auto idx = 0u; idx < table_count; ++idx )
{
auto enc_trap_hndlr = handler_tables[ idx ]->encrypt(
( reinterpret_cast< std::uintptr_t >( &__vtrap ) - handler_tables[ idx ]->module_base ) +
handler_tables[ idx ]->image_base );
for ( auto table_idx = 0u; table_idx < 256; ++table_idx )
handler_tables[ idx ]->set_entry( table_idx, enc_trap_hndlr );
}
}
void hook_t::stop( void )
{
for ( auto idx = 0u; idx < table_count; ++idx )
for ( auto table_idx = 0u; table_idx < 256; ++table_idx )
handler_tables[ idx ]->set_entry( table_idx, // restore vm handler table encrypted values...
handler_tables[ idx ]->get_meta_data( table_idx ).encrypted );
}
} // namespace vm
void vtrap_wrapper( vm::registers *regs, u8 handler_idx )
{
// r12: vm handler linear virtual address
// r13: module base linear virtual address
auto table_rva = regs->r12 - ( regs->r13 + vm::g_vmctx->handler_tables[ 0 ]->image_base );
// can only be a max of 10 vms... so idx < 10...
for ( auto idx = 0u; idx < 10; ++idx )
{
if ( vm::g_vmctx->handler_tables[ idx ] && vm::g_vmctx->handler_tables[ idx ]->table_rva == table_rva )
{
regs->vm_handler = vm::g_vmctx->handler_tables[ idx ]->get_meta_data( handler_idx ).virt;
const auto callback = vm::g_vmctx->handler_tables[ idx ]->get_meta_data( handler_idx ).callback;
// per-virtual instruction callbacks...
if ( callback )
callback( regs, handler_idx );
return;
}
}
}