From c1a02769515abacde4ccc59158688a7dc17c1053 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sat, 1 Jul 2023 22:29:34 +0200 Subject: [PATCH] Fix unresolved external symbol errors for loader.dll Moved CModule statics to a separate translation unit, preventing the linker to link unused stuff into the loader module, thus allowing us to drop the linkage of unused libraries. --- r5dev/loader/CMakeLists.txt | 7 -- r5dev/tier0/CMakeLists.txt | 1 + r5dev/tier0/module.cpp | 131 ------------------------------ r5dev/tier0/module_statics.cpp | 141 +++++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 138 deletions(-) create mode 100644 r5dev/tier0/module_statics.cpp diff --git a/r5dev/loader/CMakeLists.txt b/r5dev/loader/CMakeLists.txt index 936833b0..dab69fab 100644 --- a/r5dev/loader/CMakeLists.txt +++ b/r5dev/loader/CMakeLists.txt @@ -20,14 +20,7 @@ target_link_libraries( ${PROJECT_NAME} PRIVATE "vpc" "tier0" - # TODO: these have to be removed, currently - # linked as it would otherwise throw linker - # errors due to undefined external symbols. "libdetours" - "liblzham" - "libprotobuf" - "libspdlog" - "SigCache_Pb" ) end_sources() diff --git a/r5dev/tier0/CMakeLists.txt b/r5dev/tier0/CMakeLists.txt index 8bf1dd8b..164f3b20 100644 --- a/r5dev/tier0/CMakeLists.txt +++ b/r5dev/tier0/CMakeLists.txt @@ -37,6 +37,7 @@ add_sources( SOURCE_GROUP "Runtime" "jobthread.cpp" "memaddr.cpp" "module.cpp" + "module_statics.cpp" "platform.cpp" "sigcache.cpp" "threadtools.cpp" diff --git a/r5dev/tier0/module.cpp b/r5dev/tier0/module.cpp index e2a3244c..173262c2 100644 --- a/r5dev/tier0/module.cpp +++ b/r5dev/tier0/module.cpp @@ -432,137 +432,6 @@ CMemory CModule::GetVirtualMethodTable(const char* szTableName, const size_t nRe return CMemory(); } -//----------------------------------------------------------------------------- -// Purpose: get address of imported function in target module -// Input : *szModuleName - -// *szSymbolName - -// bGetSymbolReference - -// Output : CMemory -//----------------------------------------------------------------------------- -CMemory CModule::GetImportedSymbol(QWORD pModuleBase, const char* szModuleName, - const char* szSymbolName, const bool bGetSymbolReference) -{ - IMAGE_DOS_HEADER* pDOSHeader = GetDOSHeader(pModuleBase); - IMAGE_NT_HEADERS64* pNTHeaders = GetNTHeaders(pModuleBase); - - if (!pDOSHeader || pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) - return nullptr; - - if (!pNTHeaders || pNTHeaders->Signature != IMAGE_NT_SIGNATURE) - return nullptr; - - // Get the location of IMAGE_IMPORT_DESCRIPTOR for this - // module by adding the IMAGE_DIRECTORY_ENTRY_IMPORT - // relative virtual address onto our module base address. - IMAGE_IMPORT_DESCRIPTOR* pImageImportDescriptors = reinterpret_cast - (pModuleBase + pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); - - if (!pImageImportDescriptors) - return nullptr; - - for (IMAGE_IMPORT_DESCRIPTOR* pIID = pImageImportDescriptors; pIID->Name != 0; pIID++) - { - // Get virtual relative Address of the imported module name. - // Then add module base Address to get the actual location. - const char* szImportedModuleName = reinterpret_cast(reinterpret_cast(pModuleBase + pIID->Name)); - - if (stricmp(szImportedModuleName, szModuleName) == NULL) - { - IMAGE_THUNK_DATA* pOgFirstThunk = reinterpret_cast(pModuleBase + pIID->OriginalFirstThunk); - - // To get actual function address. - IMAGE_THUNK_DATA* pFirstThunk = reinterpret_cast(pModuleBase + pIID->FirstThunk); - for (; pOgFirstThunk->u1.AddressOfData; ++pOgFirstThunk, ++pFirstThunk) - { - // Get image import by name. - const IMAGE_IMPORT_BY_NAME* pImageImportByName = reinterpret_cast( - pModuleBase + pOgFirstThunk->u1.AddressOfData); - - if (strcmp(pImageImportByName->Name, szSymbolName) == NULL) - { - // Grab function address from firstThunk. - QWORD* pFunctionAddress = &pFirstThunk->u1.Function; - - // Reference or address? - return bGetSymbolReference ? CMemory(pFunctionAddress) : CMemory(*pFunctionAddress); - } - } - } - } - return nullptr; -} - -//----------------------------------------------------------------------------- -// Purpose: get address of exported symbol in this module -// Input : *pModuleBase - -// szSymbolName - -// Output : CMemory -//----------------------------------------------------------------------------- -CMemory CModule::GetExportedSymbol(QWORD pModuleBase, const char* szSymbolName) -{ - IMAGE_DOS_HEADER* pDOSHeader = GetDOSHeader(pModuleBase); - IMAGE_NT_HEADERS64* pNTHeaders = GetNTHeaders(pModuleBase); - - if (!pDOSHeader || pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) - return nullptr; - - if (!pNTHeaders || pNTHeaders->Signature != IMAGE_NT_SIGNATURE) - return nullptr; - - // Get the location of IMAGE_EXPORT_DIRECTORY for this - // module by adding the IMAGE_DIRECTORY_ENTRY_EXPORT - // relative virtual address onto our module base address. - const IMAGE_EXPORT_DIRECTORY* pImageExportDirectory = - reinterpret_cast(pModuleBase - + pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); - - if (!pImageExportDirectory) - return nullptr; - - if (!pImageExportDirectory->NumberOfFunctions) - return nullptr; - - // Get the location of the functions. - const DWORD* pAddressOfFunctions = reinterpret_cast(pModuleBase - + pImageExportDirectory->AddressOfFunctions); - - if (!pAddressOfFunctions) - return nullptr; - - // Get the names of the functions. - const DWORD* pAddressOfName = reinterpret_cast(pModuleBase - + pImageExportDirectory->AddressOfNames); - - if (!pAddressOfName) - return nullptr; - - // Get the ordinals of the functions. - DWORD* pAddressOfOrdinals = reinterpret_cast(pModuleBase - + pImageExportDirectory->AddressOfNameOrdinals); - - if (!pAddressOfOrdinals) - return nullptr; - - for (DWORD i = 0; i < pImageExportDirectory->NumberOfFunctions; i++) - { - // Get virtual relative Address of the function name, - // then add module base Address to get the actual location. - const char* ExportFunctionName = - reinterpret_cast(reinterpret_cast( - pModuleBase + pAddressOfName[i])); - - if (strcmp(ExportFunctionName, szSymbolName) == NULL) - { - // Get the function ordinal, then grab the relative - // virtual address of our wanted function. Then add - // module base address so we get the actual location. - return pModuleBase - + pAddressOfFunctions[reinterpret_cast(pAddressOfOrdinals)[i]]; - } - } - return nullptr; -} - //----------------------------------------------------------------------------- // Purpose: unlink module from peb // Disclaimer: This does not bypass GetMappedFileName. That function calls diff --git a/r5dev/tier0/module_statics.cpp b/r5dev/tier0/module_statics.cpp new file mode 100644 index 00000000..9efe5d02 --- /dev/null +++ b/r5dev/tier0/module_statics.cpp @@ -0,0 +1,141 @@ +//===========================================================================// +// +// Purpose: Implementation of static methods in the CModule class. +// +// -------------------------------------------------------------------------- +// Static methods are implemented here to avoid linker errors, as the CModule +// class relies on a protobuf based caching implementation. This allows us to +// not link unnecessary libraries to modules using these methods. +//===========================================================================// +#include "tier0/module.h" + +//----------------------------------------------------------------------------- +// Purpose: get address of imported function in target module +// Input : *szModuleName - +// *szSymbolName - +// bGetSymbolReference - +// Output : CMemory +//----------------------------------------------------------------------------- +CMemory CModule::GetImportedSymbol(QWORD pModuleBase, const char* szModuleName, + const char* szSymbolName, const bool bGetSymbolReference) +{ + IMAGE_DOS_HEADER* pDOSHeader = GetDOSHeader(pModuleBase); + IMAGE_NT_HEADERS64* pNTHeaders = GetNTHeaders(pModuleBase); + + if (!pDOSHeader || pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) + return nullptr; + + if (!pNTHeaders || pNTHeaders->Signature != IMAGE_NT_SIGNATURE) + return nullptr; + + // Get the location of IMAGE_IMPORT_DESCRIPTOR for this + // module by adding the IMAGE_DIRECTORY_ENTRY_IMPORT + // relative virtual address onto our module base address. + IMAGE_IMPORT_DESCRIPTOR* pImageImportDescriptors = reinterpret_cast + (pModuleBase + pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + + if (!pImageImportDescriptors) + return nullptr; + + for (IMAGE_IMPORT_DESCRIPTOR* pIID = pImageImportDescriptors; pIID->Name != 0; pIID++) + { + // Get virtual relative Address of the imported module name. + // Then add module base Address to get the actual location. + const char* szImportedModuleName = reinterpret_cast(reinterpret_cast(pModuleBase + pIID->Name)); + + if (stricmp(szImportedModuleName, szModuleName) == NULL) + { + IMAGE_THUNK_DATA* pOgFirstThunk = reinterpret_cast(pModuleBase + pIID->OriginalFirstThunk); + + // To get actual function address. + IMAGE_THUNK_DATA* pFirstThunk = reinterpret_cast(pModuleBase + pIID->FirstThunk); + for (; pOgFirstThunk->u1.AddressOfData; ++pOgFirstThunk, ++pFirstThunk) + { + // Get image import by name. + const IMAGE_IMPORT_BY_NAME* pImageImportByName = reinterpret_cast( + pModuleBase + pOgFirstThunk->u1.AddressOfData); + + if (strcmp(pImageImportByName->Name, szSymbolName) == NULL) + { + // Grab function address from firstThunk. + QWORD* pFunctionAddress = &pFirstThunk->u1.Function; + + // Reference or address? + return bGetSymbolReference ? CMemory(pFunctionAddress) : CMemory(*pFunctionAddress); + } + } + } + } + return nullptr; +} + +//----------------------------------------------------------------------------- +// Purpose: get address of exported symbol in this module +// Input : *pModuleBase - +// szSymbolName - +// Output : CMemory +//----------------------------------------------------------------------------- +CMemory CModule::GetExportedSymbol(QWORD pModuleBase, const char* szSymbolName) +{ + IMAGE_DOS_HEADER* pDOSHeader = GetDOSHeader(pModuleBase); + IMAGE_NT_HEADERS64* pNTHeaders = GetNTHeaders(pModuleBase); + + if (!pDOSHeader || pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) + return nullptr; + + if (!pNTHeaders || pNTHeaders->Signature != IMAGE_NT_SIGNATURE) + return nullptr; + + // Get the location of IMAGE_EXPORT_DIRECTORY for this + // module by adding the IMAGE_DIRECTORY_ENTRY_EXPORT + // relative virtual address onto our module base address. + const IMAGE_EXPORT_DIRECTORY* pImageExportDirectory = + reinterpret_cast(pModuleBase + + pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + + if (!pImageExportDirectory) + return nullptr; + + if (!pImageExportDirectory->NumberOfFunctions) + return nullptr; + + // Get the location of the functions. + const DWORD* pAddressOfFunctions = reinterpret_cast(pModuleBase + + pImageExportDirectory->AddressOfFunctions); + + if (!pAddressOfFunctions) + return nullptr; + + // Get the names of the functions. + const DWORD* pAddressOfName = reinterpret_cast(pModuleBase + + pImageExportDirectory->AddressOfNames); + + if (!pAddressOfName) + return nullptr; + + // Get the ordinals of the functions. + DWORD* pAddressOfOrdinals = reinterpret_cast(pModuleBase + + pImageExportDirectory->AddressOfNameOrdinals); + + if (!pAddressOfOrdinals) + return nullptr; + + for (DWORD i = 0; i < pImageExportDirectory->NumberOfFunctions; i++) + { + // Get virtual relative Address of the function name, + // then add module base Address to get the actual location. + const char* ExportFunctionName = + reinterpret_cast(reinterpret_cast( + pModuleBase + pAddressOfName[i])); + + if (strcmp(ExportFunctionName, szSymbolName) == NULL) + { + // Get the function ordinal, then grab the relative + // virtual address of our wanted function. Then add + // module base address so we get the actual location. + return pModuleBase + + pAddressOfFunctions[reinterpret_cast(pAddressOfOrdinals)[i]]; + } + } + return nullptr; +}