Compare commits

...

1 Commits

Author SHA1 Message Date
_xeroxz 74d9d2b687 init commit
3 years ago

@ -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
...

@ -1,9 +1,3 @@
<div align="center">
<div>
<img src="https://back.engineering/vmprotect-2/7.png"/>
</div>
</div>
# vmhook - VMProtect 2 Virtual Machine Hooking Library # 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). TODO - readme

@ -7,112 +7,114 @@ using u16 = unsigned short;
using u32 = unsigned int; using u32 = unsigned int;
using u64 = unsigned long long; using u64 = unsigned long long;
using u128 = __m128; using u128 = __m128;
extern "C" void __vtrap(void); extern "C" void __vtrap( void );
namespace vm namespace vm
{ {
typedef struct _registers typedef struct _registers
{ {
u128 xmm0; u128 xmm0;
u128 xmm1; u128 xmm1;
u128 xmm2; u128 xmm2;
u128 xmm3; u128 xmm3;
u128 xmm4; u128 xmm4;
u128 xmm5; u128 xmm5;
u128 xmm6; u128 xmm6;
u128 xmm7; u128 xmm7;
u128 xmm8; u128 xmm8;
u128 xmm9; u128 xmm9;
u128 xmm10; u128 xmm10;
u128 xmm11; u128 xmm11;
u128 xmm12; u128 xmm12;
u128 xmm13; u128 xmm13;
u128 xmm14; u128 xmm14;
u128 xmm15; u128 xmm15;
u64 gap0; u64 gap0;
u64 r15; u64 r15;
u64 r14; u64 r14;
u64 r13; u64 r13;
u64 r12; u64 r12;
u64 r11; u64 r11;
u64 r10; u64 r10;
u64 r9; u64 r9;
u64 r8; u64 r8;
u64 rbp; u64 rbp;
u64 rdi; u64 rdi;
u64 rsi; u64 rsi;
u64 rdx; u64 rdx;
u64 rcx; u64 rcx;
u64 rbx; u64 rbx;
u64 rax; u64 rax;
u64 rflags; u64 rflags;
u64 vm_handler; u64 vm_handler;
} registers, * pregisters; } registers, *pregisters;
using decrypt_handler_t = u64(*)(u64); using decrypt_handler_t = u64 ( * )( u64 );
using encrypt_handler_t = u64(*)(u64); using encrypt_handler_t = u64 ( * )( u64 );
namespace handler namespace handler
{ {
// these lambdas handle page protections... // these lambdas handle page protections...
using edit_entry_t = void (*)(u64*, u64); using edit_entry_t = void ( * )( u64 *, u64 );
using entry_callback_t = void (*)(vm::registers* regs, u8 handler_idx); using entry_callback_t = void ( * )( vm::registers *regs, u8 handler_idx );
struct entry_t struct entry_t
{ {
u64 virt; u64 virt;
u64 encrypted; u64 encrypted;
u64 decrypted; u64 decrypted;
entry_callback_t callback; entry_callback_t callback;
}; };
class table_t // main table class focused around containing all of the information
{ // for a given virtual machine handler table... condusive for virtual instruction
public: // hooking... up to 10 of these can be created and stored in a vm::hook_t class...
explicit table_t(u64* table_addr, edit_entry_t edit_entry); class table_t
u64 get_entry(u8 idx) const; {
entry_t get_meta_data(u8 idx) const; public:
explicit table_t( u64 module_base, u64 image_base, u32 table_rva, vm::handler::edit_entry_t edit_entry,
void set_entry(u8 idx, u64 entry); vm::decrypt_handler_t decrypt_handler, vm::encrypt_handler_t encrypt_handler );
void set_meta_data(u8 idx, const entry_t& entry);
void set_callback(u8 idx, entry_callback_t callback); u64 get_entry( u8 idx ) const;
private: entry_t get_meta_data( u8 idx ) const;
u64* table_addr;
edit_entry_t edit_entry; void set_entry( u8 idx, u64 entry );
entry_t handlers[256]; 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 );
class hook_t
{ const u32 table_rva;
public: const u64 module_base, image_base;
explicit hook_t( u64 *table_addr;
u64 module_base,
u64 image_base, entry_t handlers[ 256 ];
decrypt_handler_t decrypt_handler, edit_entry_t edit_entry;
encrypt_handler_t encrypt_handler, vm::decrypt_handler_t decrypt_handler;
vm::handler::table_t* vm_handler_table vm::encrypt_handler_t encrypt_handler;
); };
} // namespace handler
u64 encrypt(u64 val) const;
u64 decrypt(u64 val) const; // wrapper/container class which is purely for
void set_trap(u64 val) const; // containing up to 10 virtual machine table(s) and
// doing basic operations on them like "start(ing)" all
void start() const; // of the virtual machine hooks and "stop(ing)" all of them...
void stop() const; class hook_t
{
vm::handler::table_t* handler_table; public:
private: explicit hook_t( void );
const u64 module_base, image_base; void add_table( vm::handler::table_t *table );
u64 vtrap_encrypted;
void start( void );
const decrypt_handler_t decrypt_handler; void stop( void );
const encrypt_handler_t encrypt_handler;
}; u8 table_count;
vm::handler::table_t *handler_tables[ 10 ];
inline vm::hook_t* g_vmctx = nullptr; };
}
inline vm::hook_t *g_vmctx = nullptr;
extern "C" void vtrap_wrapper(vm::registers * regs, u8 handler_idx); } // namespace vm
extern "C" void vtrap_wrapper( vm::registers *regs, u8 handler_idx );

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

@ -23,7 +23,7 @@
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<ProjectGuid>{D257C9F6-C705-49D5-84ED-64C9C513C419}</ProjectGuid> <ProjectGuid>{D257C9F6-C705-49D5-84ED-64C9C513C419}</ProjectGuid>
<RootNamespace>vmtracer</RootNamespace> <RootNamespace>vmtracer</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
<ProjectName>vmhook</ProjectName> <ProjectName>vmhook</ProjectName>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@ -49,9 +49,10 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset> <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<Driver_SpectreMitigation>false</Driver_SpectreMitigation>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
@ -134,6 +135,7 @@
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard> <LanguageStandard>stdcpp17</LanguageStandard>
<TreatWarningAsError>false</TreatWarningAsError>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@ -153,6 +155,9 @@
<ItemGroup> <ItemGroup>
<ClInclude Include="..\include\vmhook.hpp" /> <ClInclude Include="..\include\vmhook.hpp" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="..\.clang-format" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" /> <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />

@ -9,6 +9,9 @@
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions> <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter> </Filter>
<Filter Include="Resource">
<UniqueIdentifier>{78c77542-7fca-421e-9cad-b63f6494a87a}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<MASM Include="vtrap.asm"> <MASM Include="vtrap.asm">
@ -25,4 +28,9 @@
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="..\.clang-format">
<Filter>Resource</Filter>
</None>
</ItemGroup>
</Project> </Project>
Loading…
Cancel
Save