diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..8063c5e
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,18 @@
+---
+BasedOnStyle: Microsoft
+AlignAfterOpenBracket: Align
+AllowAllArgumentsOnNextLine: 'true'
+AllowAllParametersOfDeclarationOnNextLine: 'true'
+AllowShortIfStatementsOnASingleLine: Never
+BreakBeforeBraces: Allman
+IndentWidth: '4'
+Language: Cpp
+NamespaceIndentation: All
+SpacesInAngles: 'true'
+SpacesInCStyleCastParentheses: 'true'
+SpacesInContainerLiterals: 'true'
+SpacesInParentheses: 'true'
+SpacesInSquareBrackets: 'true'
+UseTab: Never
+
+...
diff --git a/README.md b/README.md
index 333e6c2..4b13460 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,3 @@
-
-
-
-
-
-
# vmhook - VMProtect 2 Virtual Machine Hooking Library
-Vmhook is an execution environment agnostic VMProtect 2 virtual machine hooking framework designed for hooking virtual machine handlers. The project only supports x64 VMProtect 2 binaries. An example usage of this project can be seen at [um-hook](https://githacks.org/vmp2/um-hook).
\ No newline at end of file
+TODO - readme
\ No newline at end of file
diff --git a/include/vmhook.hpp b/include/vmhook.hpp
index 9b6c0a6..894fb03 100644
--- a/include/vmhook.hpp
+++ b/include/vmhook.hpp
@@ -7,112 +7,114 @@ using u16 = unsigned short;
using u32 = unsigned int;
using u64 = unsigned long long;
using u128 = __m128;
-extern "C" void __vtrap(void);
+extern "C" void __vtrap( void );
namespace vm
{
- typedef struct _registers
- {
- u128 xmm0;
- u128 xmm1;
- u128 xmm2;
- u128 xmm3;
- u128 xmm4;
- u128 xmm5;
- u128 xmm6;
- u128 xmm7;
- u128 xmm8;
- u128 xmm9;
- u128 xmm10;
- u128 xmm11;
- u128 xmm12;
- u128 xmm13;
- u128 xmm14;
- u128 xmm15;
-
- u64 gap0;
-
- u64 r15;
- u64 r14;
- u64 r13;
- u64 r12;
- u64 r11;
- u64 r10;
- u64 r9;
- u64 r8;
- u64 rbp;
- u64 rdi;
- u64 rsi;
- u64 rdx;
- u64 rcx;
- u64 rbx;
- u64 rax;
- u64 rflags;
- u64 vm_handler;
- } registers, * pregisters;
-
- using decrypt_handler_t = u64(*)(u64);
- using encrypt_handler_t = u64(*)(u64);
-
- namespace handler
- {
- // these lambdas handle page protections...
- using edit_entry_t = void (*)(u64*, u64);
- using entry_callback_t = void (*)(vm::registers* regs, u8 handler_idx);
-
- struct entry_t
- {
- u64 virt;
- u64 encrypted;
- u64 decrypted;
- entry_callback_t callback;
- };
-
- class table_t
- {
- public:
- explicit table_t(u64* table_addr, edit_entry_t edit_entry);
- u64 get_entry(u8 idx) const;
- entry_t get_meta_data(u8 idx) const;
-
- void set_entry(u8 idx, u64 entry);
- void set_meta_data(u8 idx, const entry_t& entry);
- void set_callback(u8 idx, entry_callback_t callback);
- private:
- u64* table_addr;
- edit_entry_t edit_entry;
- entry_t handlers[256];
- };
- }
-
- class hook_t
- {
- public:
- explicit hook_t(
- u64 module_base,
- u64 image_base,
- decrypt_handler_t decrypt_handler,
- encrypt_handler_t encrypt_handler,
- vm::handler::table_t* vm_handler_table
- );
-
- u64 encrypt(u64 val) const;
- u64 decrypt(u64 val) const;
- void set_trap(u64 val) const;
-
- void start() const;
- void stop() const;
-
- vm::handler::table_t* handler_table;
- private:
- const u64 module_base, image_base;
- u64 vtrap_encrypted;
-
- const decrypt_handler_t decrypt_handler;
- const encrypt_handler_t encrypt_handler;
- };
-
- inline vm::hook_t* g_vmctx = nullptr;
-}
-
-extern "C" void vtrap_wrapper(vm::registers * regs, u8 handler_idx);
\ No newline at end of file
+ typedef struct _registers
+ {
+ u128 xmm0;
+ u128 xmm1;
+ u128 xmm2;
+ u128 xmm3;
+ u128 xmm4;
+ u128 xmm5;
+ u128 xmm6;
+ u128 xmm7;
+ u128 xmm8;
+ u128 xmm9;
+ u128 xmm10;
+ u128 xmm11;
+ u128 xmm12;
+ u128 xmm13;
+ u128 xmm14;
+ u128 xmm15;
+
+ u64 gap0;
+
+ u64 r15;
+ u64 r14;
+ u64 r13;
+ u64 r12;
+ u64 r11;
+ u64 r10;
+ u64 r9;
+ u64 r8;
+ u64 rbp;
+ u64 rdi;
+ u64 rsi;
+ u64 rdx;
+ u64 rcx;
+ u64 rbx;
+ u64 rax;
+ u64 rflags;
+ u64 vm_handler;
+ } registers, *pregisters;
+
+ using decrypt_handler_t = u64 ( * )( u64 );
+ using encrypt_handler_t = u64 ( * )( u64 );
+
+ namespace handler
+ {
+ // these lambdas handle page protections...
+ using edit_entry_t = void ( * )( u64 *, u64 );
+ using entry_callback_t = void ( * )( vm::registers *regs, u8 handler_idx );
+
+ struct entry_t
+ {
+ u64 virt;
+ u64 encrypted;
+ u64 decrypted;
+ entry_callback_t callback;
+ };
+
+ // main table class focused around containing all of the information
+ // for a given virtual machine handler table... condusive for virtual instruction
+ // hooking... up to 10 of these can be created and stored in a vm::hook_t class...
+ class table_t
+ {
+ public:
+ explicit 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 );
+
+ u64 get_entry( u8 idx ) const;
+ entry_t get_meta_data( u8 idx ) const;
+
+ void set_entry( u8 idx, u64 entry );
+ void set_meta_data( u8 idx, const entry_t &entry );
+ void set_callback( u8 idx, entry_callback_t callback );
+ u64 decrypt( u8 idx );
+ u64 encrypt( u64 val );
+
+ const u32 table_rva;
+ const u64 module_base, image_base;
+ u64 *table_addr;
+
+ entry_t handlers[ 256 ];
+ edit_entry_t edit_entry;
+ vm::decrypt_handler_t decrypt_handler;
+ vm::encrypt_handler_t encrypt_handler;
+ };
+ } // namespace handler
+
+ // wrapper/container class which is purely for
+ // containing up to 10 virtual machine table(s) and
+ // doing basic operations on them like "start(ing)" all
+ // of the virtual machine hooks and "stop(ing)" all of them...
+ class hook_t
+ {
+ public:
+ explicit hook_t( void );
+ void add_table( vm::handler::table_t *table );
+
+ void start( void );
+ void stop( void );
+
+ u8 table_count;
+ vm::handler::table_t *handler_tables[ 10 ];
+ };
+
+ inline vm::hook_t *g_vmctx = nullptr;
+} // namespace vm
+
+extern "C" void vtrap_wrapper( vm::registers *regs, u8 handler_idx );
\ No newline at end of file
diff --git a/src/vmhook.cpp b/src/vmhook.cpp
index 298c0a9..6440008 100644
--- a/src/vmhook.cpp
+++ b/src/vmhook.cpp
@@ -2,113 +2,115 @@
namespace vm
{
- namespace handler
- {
- table_t::table_t(u64* table_addr, edit_entry_t edit_entry)
- :
- table_addr(table_addr),
- edit_entry(edit_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;
- }
- }
-
- hook_t::hook_t(
- u64 module_base,
- u64 image_base,
- decrypt_handler_t decrypt_handler,
- encrypt_handler_t encrypt_handler,
- vm::handler::table_t* vm_handler_table
- )
- :
- decrypt_handler(decrypt_handler),
- encrypt_handler(encrypt_handler),
- handler_table(vm_handler_table),
- module_base(module_base),
- image_base(image_base)
- {
- for (auto idx = 0u; idx < 256; ++idx)
- {
- vm::handler::entry_t entry =
- vm_handler_table->get_meta_data(idx);
-
- entry.encrypted = vm_handler_table->get_entry(idx);
- entry.decrypted = decrypt(entry.encrypted);
- entry.virt = (entry.decrypted - image_base) + module_base;
- vm_handler_table->set_meta_data(idx, entry);
- }
-
- vm::g_vmctx = this;
- vtrap_encrypted = encrypt(
- (reinterpret_cast(
- &__vtrap) - module_base) + image_base);
- }
-
- u64 hook_t::encrypt(u64 val) const
- {
- return encrypt_handler(val);
- }
-
- u64 hook_t::decrypt(u64 val) const
- {
- return decrypt_handler(val);
- }
-
- void hook_t::set_trap(u64 val) const
- {
- for (auto idx = 0u; idx < 256; ++idx)
- handler_table->set_entry(idx, val);
- }
-
- void hook_t::start() const
- {
- for (auto idx = 0u; idx < 256; ++idx)
- handler_table->set_entry(idx, vtrap_encrypted);
- }
-
- void hook_t::stop() const
- {
- for (auto idx = 0u; idx < 256; ++idx)
- {
- const auto handler_entry =
- handler_table->get_meta_data(idx).encrypted;
-
- handler_table->set_entry(idx, handler_entry);
- }
- }
-}
-
-void vtrap_wrapper(vm::registers* regs, u8 handler_idx)
+ 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 )
{
- regs->vm_handler = vm::g_vmctx->
- handler_table->get_meta_data(handler_idx).virt;
-
- const auto callback = vm::g_vmctx->
- handler_table->get_meta_data(handler_idx).callback;
-
- // per-virtual instruction callbacks...
- if (callback) callback(regs, 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;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/vmhook.vcxproj b/src/vmhook.vcxproj
index 21842b9..504b6fe 100644
--- a/src/vmhook.vcxproj
+++ b/src/vmhook.vcxproj
@@ -23,7 +23,7 @@
Win32Proj
{D257C9F6-C705-49D5-84ED-64C9C513C419}
vmtracer
- 10.0
+ 10.0.19041.0
vmhook
@@ -49,9 +49,10 @@
StaticLibrary
false
- v142
+ WindowsKernelModeDriver10.0
true
Unicode
+ false
@@ -134,6 +135,7 @@
NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
stdcpp17
+ false
Console
@@ -153,6 +155,9 @@
+
+
+
diff --git a/src/vmhook.vcxproj.filters b/src/vmhook.vcxproj.filters
index 3b17ab6..7779bd9 100644
--- a/src/vmhook.vcxproj.filters
+++ b/src/vmhook.vcxproj.filters
@@ -9,6 +9,9 @@
{93995380-89BD-4b04-88EB-625FBE52EBFB}
h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+ {78c77542-7fca-421e-9cad-b63f6494a87a}
+
@@ -25,4 +28,9 @@
Source Files
+
+
+ Resource
+
+
\ No newline at end of file