init commit

multi-vm
_xeroxz 3 years ago
parent aec227a091
commit 74d9d2b687

@ -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 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 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);
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 );

@ -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<std::uintptr_t>(
&__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;
}
}
}

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

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