-
Notifications
You must be signed in to change notification settings - Fork 0
/
mstl_vmt.hpp
99 lines (77 loc) · 2.61 KB
/
mstl_vmt.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#pragma once
class VMT : public Address {
private:
using saved_method_t = std::pair< size_t, Address >;
Address m_orig_vmt;
std::unique_ptr< Address[] > m_clone;
std::vector< saved_method_t > m_original_methods;
public:
// c/dtor
__forceinline VMT( ) : Address{}, m_clone{}, m_original_methods{} {}
__forceinline ~VMT( ) {
unhook_all( );
}
__forceinline VMT( Address this_ptr,
bool clone_table = false,
bool preserve_rtti = false ) :
Address( this_ptr ) {
init( clone_table, preserve_rtti );
}
__forceinline void init( bool clone_table, bool preserve_rtti ) {
uintptr_t clone;
size_t methods{};
// get orig table vmt
m_orig_vmt = *as< Address* >( );
// if not cloning, we're done here.
if ( !clone_table )
return;
// count methods in orig obj vmt
count_methods( methods );
// if preserving rtti, make space for one more ptr
if ( preserve_rtti )
methods += 1;
// alloc space for a clone table and rtti ptr if we want
m_clone = std::make_unique< Address[] >( methods );
// make a cast cuz i dont want to keep casting this
clone = ( uintptr_t )m_clone.get( );
// copy over all methods
util::copy(
preserve_rtti ? clone + sizeof( Address ) : clone,
m_orig_vmt,
methods * sizeof( Address )
);
// check if we should preserve rtti and do a little hack to fix it
if ( preserve_rtti )
m_clone[ 0 ] = m_orig_vmt.as< Address* >( )[ -1 ];
// then set the original objects vmt pointer to our cloned table
set( preserve_rtti ? clone + sizeof( Address ) : clone );
}
__forceinline void count_methods( size_t& methods ) {
while ( safe( m_orig_vmt.as< Address* >( )[ methods ] ) )
methods++;
}
__forceinline void unhook_all( ) {
for ( const auto& m : m_original_methods )
to< Address* >( )[ std::get< size_t >( m ) ] = std::get< Address >( m );
}
__forceinline void unhook_method( size_t index ) {
to< Address* >( )[ index ] = std::get< Address >( m_original_methods[ index ] );
}
__forceinline void hook_method( void* method, size_t index ) {
hook_method( ( uintptr_t )method, index );
}
__forceinline void hook_method( Address hook_method, size_t index ) {
m_original_methods.push_back( saved_method_t{ index, to< Address* >( )[ index ] } );
to< Address* >( )[ index ] = hook_method;
}
template <typename t = Address>
__forceinline t get_method( size_t index ) const {
return m_orig_vmt.as< Address* >( )[ index ].as< t >( );
}
};
namespace util {
template <typename t = Address>
__forceinline static t get_method( Address this_ptr, size_t index ) {
return ( t )this_ptr.to< t* >( )[ index ];
}
};