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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
|
#pragma once
#include <Windows.h>
#include <winternl.h>
#include <inttypes.h>
#include <stdio.h>
#include <Psapi.h>
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <functional>
namespace tf2
{
namespace interfaces
{
// this interface linked list iteration code is tf2 specific !
// in the future i will write it game/engine version independent
// using a disassembly engine
struct regs {
void *( *m_CreateFn )( );
const char *m_pName;
regs *m_pNext;
};
static inline bool is_create_fn( uintptr_t m_createfn ) {
return( *( uint8_t * )( m_createfn ) == 0xB8
&& *( uint8_t * )( m_createfn + 5 ) == 0xC3 );
}
static inline bool is_createinterface_fn( uintptr_t m_createfn ) {
return( *( uint8_t * )( m_createfn + 4 ) == 0xE9
&& *( uint8_t * )( m_createfn + 9 ) == 0xCC );
}
static inline uintptr_t follow_createinterface_export( uintptr_t export_ ) {
if ( *( uint8_t * )( export_ + 4 ) != 0xE9 ) return 0;
return( export_ + 4 + *( uintptr_t * )( export_ + 5 ) + 5 );
}
static inline regs *reg_from_createinterface( uintptr_t ci ) {
if ( *( short * )( ci + 4 ) != 0x358B ) return nullptr;
return( **( regs *** )( ci + 6 ) );
}
static inline uintptr_t interface_from_reg( regs *reg ) {
uintptr_t reg_func = *( uintptr_t * )reg;
if ( is_create_fn( reg_func ) ) {
return( *( uintptr_t * )( reg_func + 1 ) );
}
return( 0 );
}
class interface_manager {
public:
struct interface_data {
public:
std::string name;
std::string module;
int version;
void *ptr;
template< typename T > inline T get( ) { return reinterpret_cast< T >( ptr ); }
interface_data( std::string name_T, std::string module_T, void *ptr_T, int version_T = 0 )
: name( name_T ), module( module_T ), ptr( ptr_T ), version( version_T ) {}
};
interface_manager() {
auto root = &get_peb( )->Ldr->InMemoryOrderModuleList;
for ( auto entry = root->Flink->Flink->Flink->Flink; entry != root; entry = entry->Flink ) {
auto data_table = reinterpret_cast< PLDR_DATA_TABLE_ENTRY >( entry );
auto module_base = reinterpret_cast< HMODULE >( data_table->Reserved2[ 0 ] );
auto export_ = reinterpret_cast< uintptr_t >( ::GetProcAddress( module_base, "CreateInterface" ) );
if ( !export_ || !interfaces::is_createinterface_fn( export_ ) ) {
continue;
}
auto CreateInterface = interfaces::follow_createinterface_export( export_ );
if ( !CreateInterface ) {
continue;
}
auto regs = interfaces::reg_from_createinterface( CreateInterface );
while ( regs ) {
std::string name( regs->m_pName ), temp_version( name );
name.erase( std::remove_if( name.begin( ), name.end( ), &isdigit ), name.end( ) );
temp_version.erase(
std::remove_if( temp_version.begin( ), temp_version.end( ),
[ ]( int i ) { return !isdigit( i ); }
), temp_version.end( )
);
unsigned int version{ };
std::stringstream( temp_version ) >> version;
sorted_list.push_back( interface_data( name, unicode_to_string( data_table->FullDllName ), reinterpret_cast< void * >( interfaces::interface_from_reg( regs ) ), version ) );
regs = regs->m_pNext;
}
}
std::sort( sorted_list.begin( ), sorted_list.end( ), [ ]( const interface_data &lhs, const interface_data &rhs ) {
return( lhs.version > rhs.version );
} );
}
public:
template< typename T = void * > T create( std::string name ) {
std::vector< interface_data >::iterator it = std::find_if( sorted_list.begin( ), sorted_list.end( ), [ & ]( const interface_data &data ) {
return ( !data.name.compare( name ) );
} );
if ( it == sorted_list.end( ) || !it->ptr ) {
return T{ };
}
printf( "%s\n -> 0x%X\n -> module: %s \n", name.c_str( ), reinterpret_cast< uintptr_t >( it->ptr ), it->module.c_str( ) );
return( ( T )( it->ptr ) );
}
template< typename T = void* > T create( std::string name, std::string module ) {
std::vector< interface_data >::iterator it = std::find_if( sorted_list.begin( ), sorted_list.end( ), [ & ]( const interface_data &data ) {
return ( !data.name.compare( name ) && data.module.find( module ) != std::string::npos );
} );
if ( it == sorted_list.end( ) || !it->ptr ) {
return T{ };
}
//#ifdef DEBUG_PRINT
printf( "%s\n -> 0x%x\n -> module: %s \n", name.c_str( ), reinterpret_cast< uintptr_t >( it->ptr ), it->module.c_str( ) );
//#endif
return( static_cast< T >( it->ptr ) );
}
template< typename T = void * > T create_from_hash( uint32_t hash ) {
std::vector< interface_data >::iterator it = std::find_if( sorted_list.begin( ), sorted_list.end( ), [ & ]( const interface_data &data )
{
return ( !data.name.compare( name ) );
} );
if ( it == sorted_list.end( ) || !it->ptr ) {
return T{ };
}
return( ( T )( it->ptr ) );
}
protected:
static inline PTEB get_teb( ) {
#if defined( _M_X64 )
auto teb = reinterpret_cast< PTEB >( __readgsqword( reinterpret_cast< uintptr_t >( &static_cast< NT_TIB * >( nullptr )->Self ) ) );
#else
auto teb = reinterpret_cast< PTEB >( __readfsdword( reinterpret_cast< uintptr_t >( &static_cast< NT_TIB * >( nullptr )->Self ) ) );
#endif
return teb;
}
static inline PPEB get_peb( ) {
return( get_teb( )->ProcessEnvironmentBlock );
}
static inline std::string unicode_to_string( UNICODE_STRING wide ) {
std::wstring wide_str( wide.Buffer, wide.Length );
return std::string( wide_str.begin( ), wide_str.end( ) );
}
std::vector< interface_data > sorted_list{ };
};
};
}
|