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