├── .gitignore ├── LICENSE ├── README.md └── interface_factory ├── Project8.sln └── Project8 ├── Project8.vcxproj ├── Project8.vcxproj.filters ├── Source.cpp ├── factory.cpp ├── factory.hpp ├── util.hpp └── x86.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # interface-factory 2 | walks through modules and interfaces in the source engine 3 | -------------------------------------------------------------------------------- /interface_factory/Project8.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.15 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Project8", "Project8\Project8.vcxproj", "{103F0F2B-9DFD-4E28-9693-BAC1B6A83306}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {103F0F2B-9DFD-4E28-9693-BAC1B6A83306}.Debug|x64.ActiveCfg = Debug|x64 17 | {103F0F2B-9DFD-4E28-9693-BAC1B6A83306}.Debug|x64.Build.0 = Debug|x64 18 | {103F0F2B-9DFD-4E28-9693-BAC1B6A83306}.Debug|x86.ActiveCfg = Debug|Win32 19 | {103F0F2B-9DFD-4E28-9693-BAC1B6A83306}.Debug|x86.Build.0 = Debug|Win32 20 | {103F0F2B-9DFD-4E28-9693-BAC1B6A83306}.Release|x64.ActiveCfg = Release|x64 21 | {103F0F2B-9DFD-4E28-9693-BAC1B6A83306}.Release|x64.Build.0 = Release|x64 22 | {103F0F2B-9DFD-4E28-9693-BAC1B6A83306}.Release|x86.ActiveCfg = Release|Win32 23 | {103F0F2B-9DFD-4E28-9693-BAC1B6A83306}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {A47D7E12-B892-4555-8D21-BEC3CB980B61} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /interface_factory/Project8/Project8.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {103F0F2B-9DFD-4E28-9693-BAC1B6A83306} 24 | Project8 25 | 10.0.15063.0 26 | 27 | 28 | 29 | DynamicLibrary 30 | true 31 | v141 32 | MultiByte 33 | 34 | 35 | DynamicLibrary 36 | false 37 | v141 38 | true 39 | MultiByte 40 | 41 | 42 | DynamicLibrary 43 | true 44 | v141 45 | MultiByte 46 | 47 | 48 | DynamicLibrary 49 | false 50 | v141 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | Disabled 77 | true 78 | 79 | 80 | 81 | 82 | Level3 83 | Disabled 84 | true 85 | 86 | 87 | 88 | 89 | Level3 90 | MaxSpeed 91 | true 92 | true 93 | true 94 | 95 | 96 | true 97 | true 98 | 99 | 100 | 101 | 102 | Level3 103 | MaxSpeed 104 | true 105 | true 106 | true 107 | 108 | 109 | true 110 | true 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /interface_factory/Project8/Project8.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Source Files 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | -------------------------------------------------------------------------------- /interface_factory/Project8/Source.cpp: -------------------------------------------------------------------------------- 1 | #include "factory.hpp" 2 | 3 | bool __stdcall DllMain( HINSTANCE instance, ulong_t reason, void* reserved ) { 4 | switch ( reason ) { 5 | case DLL_PROCESS_ATTACH: 6 | DisableThreadLibraryCalls( instance ); 7 | g_factory.dump_interface_list( ); 8 | 9 | return true; 10 | break; 11 | 12 | default: 13 | return true; 14 | break; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /interface_factory/Project8/factory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "factory.hpp" 4 | 5 | NAMESPACE_REGION( interface_factory ) 6 | 7 | //iterate all exports inside of a module and find createinterface 8 | uintptr_t c_interface_manager::find_createinterface( void* module_ ) { 9 | IMAGE_DOS_HEADER* dos_header; 10 | IMAGE_NT_HEADERS* nt_headers; 11 | uintptr_t export_address; 12 | IMAGE_EXPORT_DIRECTORY* export_dir; 13 | const char* export_name; 14 | uintptr_t* names; 15 | uintptr_t* funcs; 16 | uint16_t* ords; 17 | 18 | dos_header = reinterpret_cast< decltype( dos_header ) >( uintptr_t( module_ ) ); 19 | nt_headers = reinterpret_cast< decltype( nt_headers ) >( uintptr_t( module_ ) + dos_header->e_lfanew ); 20 | 21 | export_address = nt_headers->OptionalHeader.DataDirectory[ 0 ].VirtualAddress; 22 | export_dir = reinterpret_cast< decltype( export_dir ) >( uintptr_t( module_ ) + export_address ); 23 | 24 | if ( !export_dir->NumberOfFunctions ) 25 | return uintptr_t{ }; 26 | 27 | names = reinterpret_cast< uintptr_t* >( uintptr_t( module_ ) + export_dir->AddressOfNames ); 28 | funcs = reinterpret_cast< uintptr_t* >( uintptr_t( module_ ) + export_dir->AddressOfFunctions ); 29 | 30 | ords = reinterpret_cast< uint16_t* >( uintptr_t( module_ ) + export_dir->AddressOfNameOrdinals ); 31 | 32 | if ( names && funcs && ords ) { 33 | for ( size_t i{ }; i < export_dir->NumberOfNames; ++i ) { 34 | export_name = reinterpret_cast< const char* >( uintptr_t( module_ ) + names[ i ] ); 35 | if ( !strcmp( export_name, "CreateInterface" ) ) { 36 | return uintptr_t( module_ ) + funcs[ ords[ i ] ]; 37 | } 38 | } 39 | } 40 | 41 | return uintptr_t{ }; 42 | } 43 | 44 | c_interface_manager::c_interface_manager( ) { 45 | auto teb = reinterpret_cast< PTEB >( __readfsdword( uintptr_t( &static_cast< NT_TIB* >( nullptr )->Self ) ) ); 46 | auto peb = teb->ProcessEnvironmentBlock; 47 | 48 | auto root = &peb->Ldr->InMemoryOrderModuleList; 49 | //iterate module list 50 | for ( auto entry = root->Flink->Flink->Flink->Flink; entry != root; entry = entry->Flink ) { 51 | PLDR_DATA_TABLE_ENTRY data_table; 52 | HMODULE module_base; 53 | uintptr_t create_interface_export; 54 | uintptr_t create_interface_; 55 | uintptr_t* list_iterator_ptr; 56 | interface_iterator_t* list_iterator; 57 | 58 | data_table = reinterpret_cast< PLDR_DATA_TABLE_ENTRY >( entry ); 59 | module_base = reinterpret_cast< HMODULE >( data_table->Reserved2[ 0 ] ); 60 | create_interface_export = find_createinterface( module_base ); 61 | 62 | if ( !create_interface_export || !is_createinterface_export( create_interface_export ) ) { 63 | continue; 64 | } 65 | 66 | //find the createinterface function 67 | create_interface_ = follow_createinterface_export( create_interface_export ); 68 | if ( !is_createinterface_fn( create_interface_ ) ) { 69 | continue; 70 | } 71 | 72 | //find the list iterator 73 | list_iterator_ptr = find_list_ptr( create_interface_ ); 74 | 75 | //iterate the interface list 76 | for ( list_iterator = reinterpret_cast< interface_iterator_t* >( 77 | list_iterator_ptr ); 78 | !!list_iterator; 79 | list_iterator = list_iterator->m_next 80 | ) { 81 | std::string name( list_iterator->m_name ); 82 | std::string module_name( util::unicode_to_ascii( 83 | std::wstring( data_table->FullDllName.Buffer, data_table->FullDllName.Length ) ) ); 84 | 85 | uintptr_t ptr = static_cast< uintptr_t( *)( ) >( list_iterator->m_create_fn )( ); 86 | 87 | size_t version = [ & ]( ) { 88 | std::string ret( name ); 89 | ret.erase( std::remove_if( ret.begin( ), ret.end( ), 90 | [ & ]( int i ) { return !::isdigit( i ); } 91 | ), ret.end( ) ); 92 | return atoi( ret.c_str( ) ); 93 | }( ); 94 | 95 | m_interfaces.emplace_back( interface_data_t{ name, module_name, version, ptr } ); 96 | } 97 | } 98 | } 99 | 100 | END_REGION 101 | interface_factory::c_interface_manager g_factory; 102 | -------------------------------------------------------------------------------- /interface_factory/Project8/factory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "util.hpp" 7 | #include "x86.hpp" 8 | 9 | NAMESPACE_REGION( interface_factory ) 10 | struct interface_iterator_t { 11 | void* m_create_fn; 12 | char* m_name; 13 | 14 | interface_iterator_t* m_next; 15 | }; 16 | 17 | inline auto follow_createinterface_export( uintptr_t export_ ) { 18 | /* 19 | .text:006F5F00 CreateInterface proc near 20 | .text:006F5F00 push ebp 21 | .text:006F5F01 mov ebp, esp 22 | .text:006F5F03 pop ebp 23 | .text:006F5F04 jmp sub_6F5E90 24 | */ 25 | uintptr_t jmp = export_ + 0x4; 26 | uintptr_t jmp_target = jmp + *( uintptr_t* ) ( jmp + 0x1 ) + 0x5; 27 | 28 | return jmp_target; 29 | } 30 | 31 | inline auto find_list_ptr( uintptr_t createinterface ) { 32 | /* 33 | .text:006F5E90 push ebp 34 | .text:006F5E91 mov ebp, esp 35 | .text:006F5E93 push esi 36 | .text:006F5E94 mov esi, dword_2EEFDE4 37 | .text:006F5E9A push edi 38 | */ 39 | auto iterator_ptr = **( uintptr_t*** ) ( createinterface + 0x6 ); 40 | 41 | return iterator_ptr; 42 | } 43 | 44 | inline bool is_createinterface_export( uintptr_t export_ ) { 45 | return ( *( uint8_t* ) ( export_ ) == x86::encode_push_reg( x86::reg::ebp ) 46 | && *( uint8_t* ) ( export_ + 4 ) == 0xe9 47 | && *( uint8_t* ) ( export_ + 9 ) == 0xcc 48 | && *( uint8_t* ) ( export_ + 10 ) == 0xcc ); 49 | } 50 | 51 | inline bool is_createinterface_fn( uintptr_t fn_ ) { 52 | return ( *( uint8_t* ) ( fn_ ) == x86::encode_push_reg( x86::reg::ebp ) 53 | && *( uint8_t* ) ( fn_ + 4 ) == 0x8b 54 | && *( uint8_t* ) ( fn_ + 10 ) == x86::encode_push_reg( x86::reg::edi ) ); 55 | } 56 | 57 | class c_interface_manager { 58 | public: 59 | struct interface_data_t { 60 | std::string m_name; 61 | std::string m_module; 62 | size_t m_version; 63 | uintptr_t m_ptr; 64 | 65 | template < typename t > __forceinline t get( ) { 66 | return reinterpret_cast< t >( m_ptr ); 67 | } 68 | }; 69 | 70 | c_interface_manager( ); 71 | 72 | //iterate the interface list to find our desired version 73 | template < typename t = void* > 74 | t find_interface( const std::string& module_, std::string name ) { 75 | //avoid finding interfaces with matching names 76 | if ( !::isdigit( name[ name.length() ] ) ) 77 | name += "0"; 78 | 79 | for ( auto& it : m_interfaces ) { 80 | if ( !it.m_module.compare( module_ ) 81 | && !it.m_name.compare( name ) ) { 82 | printf( "%s version %u found in %s at 0x%08x\n", 83 | it.m_name.c_str(), 84 | it.m_version, 85 | it.m_module.c_str( ), 86 | it.m_ptr ); 87 | 88 | return it.get< t >( ); 89 | } 90 | } 91 | 92 | return t{ }; 93 | } 94 | 95 | template < typename t = void* > 96 | t find_interface( std::string name ) { 97 | //avoid finding interfaces with matching names 98 | if ( !::isdigit( name[ name.length( ) ] ) ) 99 | name += "0"; 100 | 101 | for ( auto& it : m_interfaces ) { 102 | if ( strstr( it.m_name.c_str( ), name.c_str( ) ) ) { 103 | printf( "%s version %u found in %s at 0x%08x\n", 104 | it.m_name.c_str(), 105 | it.m_version, 106 | it.m_module.c_str( ), 107 | it.m_ptr ); 108 | 109 | return it.get< t >( ); 110 | } 111 | } 112 | 113 | return t{ }; 114 | } 115 | 116 | void dump_interface_list( ) { 117 | std::fstream f( "dump.txt" ); 118 | for ( auto& it : m_interfaces ) { 119 | char buf[ 200 ]; 120 | sprintf_s( buf, 200, "%s version %u in %s at 0x%08x\n", 121 | it.m_name.c_str( ), 122 | it.m_version, 123 | it.m_module.c_str( ), 124 | it.m_ptr ); 125 | 126 | f << buf; 127 | } 128 | } 129 | 130 | private: 131 | uintptr_t find_createinterface( void* module_ ); 132 | 133 | std::vector< interface_data_t > m_interfaces; 134 | }; 135 | 136 | END_REGION 137 | 138 | extern HMODULE g_dll; 139 | extern interface_factory::c_interface_manager g_factory; 140 | -------------------------------------------------------------------------------- /interface_factory/Project8/util.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NAMESPACE_REGION( x ) namespace x { 4 | #define END_REGION } 5 | 6 | //WEE WOO WEE WOO ITS THE DWORD POLICE 7 | using ulong_t = unsigned long; 8 | using uword_t = unsigned short; 9 | 10 | NAMESPACE_REGION( util ) 11 | 12 | template < typename fn > __forceinline fn get_vfunc( void* classbase, int index ) { 13 | if ( !classbase ) return fn{ }; 14 | return ( fn )( ( uintptr_t* )*( uintptr_t** )classbase )[ index ]; 15 | } 16 | 17 | static __forceinline std::string unicode_to_ascii( const std::wstring& unicode ) { 18 | std::string ascii_str( unicode.begin( ), unicode.end( ) ); 19 | return ascii_str; 20 | } 21 | 22 | static __forceinline std::wstring ascii_to_unicode( const std::string& ascii ) { 23 | std::wstring unicode_str( ascii.begin( ), ascii.end( ) ); 24 | return unicode_str; 25 | } 26 | 27 | END_REGION 28 | -------------------------------------------------------------------------------- /interface_factory/Project8/x86.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace x86 4 | { 5 | enum class reg : size_t { 6 | eax = 0, 7 | ecx, 8 | edx, 9 | ebx, 10 | esp, 11 | ebp, 12 | esi, 13 | edi 14 | 15 | /* 16 | x64: 17 | r8, 18 | r9, 19 | r10, 20 | r11, 21 | r12, 22 | r13, 23 | r14, 24 | r15*/ 25 | }; 26 | 27 | enum instruction : uint8_t { 28 | retn_imm16 = 0xc2, 29 | retn = 0xc3, 30 | fs = 0x64, 31 | //its big nigga season 32 | call = 0xff 33 | }; 34 | 35 | __forceinline static uint32_t encode_mov_imm32( x86::reg dreg ) { 36 | return ( 0xb8 + ( size_t( dreg ) ) ); 37 | } 38 | 39 | __forceinline static uint32_t encode_push_reg( x86::reg dreg ) { 40 | return ( 0x50 | ( ( size_t( dreg ) ) & 7 ) ); 41 | } 42 | 43 | __forceinline static uint32_t encode_pop_reg( x86::reg dreg ) { 44 | return ( 0x58 | ( ( size_t( dreg ) ) & 7 ) ); 45 | } 46 | }; 47 | --------------------------------------------------------------------------------