summaryrefslogtreecommitdiff
path: root/cheat/tf2/factory.cpp
blob: f8dfd428dab45737823dc8ac841f883b25c563b9 (plain)
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
#include "factory.h"
#ifndef IFACE_DLLMAIN
#include "fnv.hpp"

#include <algorithm>

NAMESPACE_REGION( tf2 )
NAMESPACE_REGION( interfaces )

//iterate all exports inside of a module and find createinterface
uintptr_t c_interface_manager::find_createinterface( void* module_ ) {
	IMAGE_DOS_HEADER*		dos_header;
	IMAGE_NT_HEADERS*		nt_headers;
	uintptr_t				export_address;
	IMAGE_EXPORT_DIRECTORY*	export_dir;
	const char*				export_name;
	uintptr_t*				names;
	uintptr_t*				funcs;
	uint16_t*				ords;
	uint32_t				export_hash;

	dos_header = reinterpret_cast< decltype( dos_header ) >( uintptr_t( module_ ) );
	nt_headers = reinterpret_cast< decltype( nt_headers ) >( uintptr_t( module_ ) + dos_header->e_lfanew );

	//find addresses of functions from nt headers
	export_address = nt_headers->OptionalHeader.DataDirectory[ 0 ].VirtualAddress;
	export_dir = reinterpret_cast< decltype( export_dir ) >( uintptr_t( module_ ) + export_address );

	if( !export_dir->NumberOfFunctions )
		return uintptr_t{ };

	names = reinterpret_cast< uintptr_t* >( uintptr_t( module_ ) + export_dir->AddressOfNames );
	funcs = reinterpret_cast< uintptr_t* >( uintptr_t( module_ ) + export_dir->AddressOfFunctions );

	ords = reinterpret_cast< uint16_t* >( uintptr_t( module_ ) + export_dir->AddressOfNameOrdinals );

	if( names && funcs && ords ) {
		//iterate the exports
		for( size_t i{ }; i < export_dir->NumberOfNames; ++i ) {
			export_name = reinterpret_cast< const char* >( uintptr_t( module_ ) + names[ i ] );
			export_hash = hash::fnv1a( export_name );

			if( export_hash == fnv( "CreateInterface" ) ) {
				return uintptr_t( module_ ) + funcs[ ords[ i ] ];
			}
		}
	}

	return uintptr_t{ };
}

c_interface_manager::c_interface_manager( ) {
	auto teb = reinterpret_cast< PTEB >( __readfsdword( uintptr_t( &static_cast< NT_TIB* >( nullptr )->Self ) ) );
	auto peb = teb->ProcessEnvironmentBlock;

	auto root = &peb->Ldr->InMemoryOrderModuleList;
	//iterate module list
	for( auto entry = root->Flink->Flink->Flink->Flink; entry != root; entry = entry->Flink ) {
		PLDR_DATA_TABLE_ENTRY	data_table;
		HMODULE					module_base;
		uintptr_t				create_interface_export;
		uintptr_t				create_interface_;
		uintptr_t*				list_iterator_ptr;
		interface_iterator_t*	list_iterator;

		data_table = reinterpret_cast< PLDR_DATA_TABLE_ENTRY >( entry );
		module_base = reinterpret_cast< HMODULE >( data_table->Reserved2[ 0 ] );
		create_interface_export = find_createinterface( module_base );

		if( !create_interface_export || !is_createinterface_export( create_interface_export ) ) {
			continue;
		}

		//find the createinterface function
		create_interface_ = follow_createinterface_export( create_interface_export );
		if( !is_createinterface_fn( create_interface_ ) ) {
			continue;
		}

		//find the list iterator
		list_iterator_ptr = find_list_ptr( create_interface_ );

		//iterate the interface list
		for( list_iterator = reinterpret_cast< interface_iterator_t* >(
			list_iterator_ptr );
			!!list_iterator;
			list_iterator = list_iterator->m_next
			) {
			std::string name( list_iterator->m_name );
			std::string module_name( util::unicode_to_ascii(
				std::wstring( data_table->FullDllName.Buffer, data_table->FullDllName.Length ) ) );

			uintptr_t ptr = static_cast< uintptr_t( *)( ) >( list_iterator->m_create_fn )( );

			size_t version = [ & ]( ) {
				std::string ret( name );
				ret.erase( std::remove_if( ret.begin( ), ret.end( ),
					[ & ]( int i ) { return !::isdigit( i ); }
				), ret.end( ) );
				return atoi( ret.c_str( ) );
			}( );

			m_interfaces.emplace_back( interface_data_t{ name, module_name, version, ptr } );
		}
	}
}

END_REGION
END_REGION
#endif