From 975c40876a8711761cbaa842815e52228b72d67e Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 12 Jun 2023 18:40:16 +0200 Subject: [PATCH] CModule and CMemory class improvements This commit significantly reduces output code size, and a noticeable increase in performance. Changes are: - Removed all extraneous std::string and std::vector copy constructions; use raw pointers instead to boost performance. - Marked simple getters in CModule inline. - Marked several functions in CModule const. - Slightly reordered CModule class. - 'CMemory::CheckOpCodes' and 'CMemory::Patch' now take a const reference. --- r5dev/common/pseudodefs.h | 2 +- r5dev/pluginsystem/pluginsystem.cpp | 2 +- r5dev/public/tier0/memaddr.h | 16 +- r5dev/public/tier0/module.h | 61 +++--- r5dev/public/tier0/sigcache.h | 4 +- r5dev/public/tier0/utility.h | 8 +- r5dev/public/tier0/vtable.h | 6 +- r5dev/tier0/CMakeLists.txt | 4 + r5dev/tier0/memaddr.cpp | 120 ++++++----- r5dev/tier0/module.cpp | 305 ++++++++++++++++------------ r5dev/tier0/sigcache.cpp | 22 +- r5dev/tier0/utility.cpp | 49 ++--- r5dev/tier0/vtable.cpp | 9 +- r5dev/windows/tebpeb64.h | 267 ++++++++++++++++++++++++ 14 files changed, 617 insertions(+), 258 deletions(-) create mode 100644 r5dev/windows/tebpeb64.h diff --git a/r5dev/common/pseudodefs.h b/r5dev/common/pseudodefs.h index f0734d07..1c54da24 100644 --- a/r5dev/common/pseudodefs.h +++ b/r5dev/common/pseudodefs.h @@ -85,7 +85,7 @@ typedef int32 DWORD; typedef int32 LONG; typedef int BOOL; // uppercase BOOL is usually 4 bytes #endif -typedef int64 QWORD; +//typedef int64 QWORD; #ifndef __cplusplus typedef int bool; // we want to use bool in our C programs #endif diff --git a/r5dev/pluginsystem/pluginsystem.cpp b/r5dev/pluginsystem/pluginsystem.cpp index 0af98558..ecf72224 100644 --- a/r5dev/pluginsystem/pluginsystem.cpp +++ b/r5dev/pluginsystem/pluginsystem.cpp @@ -54,7 +54,7 @@ bool CPluginSystem::LoadPluginInstance(PluginInstance_t& pluginInst) if (loadedPlugin == INVALID_HANDLE_VALUE || loadedPlugin == 0) return false; - CModule pluginModule = CModule(pluginInst.m_svPluginName); + CModule pluginModule = CModule(pluginInst.m_svPluginName.c_str()); // Pass selfModule here on load function, we have to do this because local listen/dedi/client dll's are called different, refer to a comment on the pluginsdk. auto onLoadFn = pluginModule.GetExportedFunction("PluginInstance_OnLoad").RCast(); diff --git a/r5dev/public/tier0/memaddr.h b/r5dev/public/tier0/memaddr.h index dcb54f5a..6223fe73 100644 --- a/r5dev/public/tier0/memaddr.h +++ b/r5dev/public/tier0/memaddr.h @@ -115,17 +115,21 @@ public: return *this; } - bool CheckOpCodes(const vector vOpcodeArray) const; - void Patch(const vector vOpcodeArray) const; - void PatchString(const string& svString) const; - CMemory FindPattern(const string& svPattern, const Direction searchDirect = Direction::DOWN, const int opCodesToScan = 512, const ptrdiff_t occurrence = 1) const; - CMemory FindPatternSelf(const string& svPattern, const Direction searchDirect = Direction::DOWN, const int opCodesToScan = 512, const ptrdiff_t occurrence = 1); + bool CheckOpCodes(const vector& vOpcodeArray) const; + void Patch(const vector& vOpcodeArray) const; + void PatchString(const char* szString) const; + + CMemory FindPattern(const char* szPattern, const Direction searchDirect = Direction::DOWN, const int opCodesToScan = 512, const ptrdiff_t occurrence = 1) const; + CMemory FindPatternSelf(const char* szPattern, const Direction searchDirect = Direction::DOWN, const int opCodesToScan = 512, const ptrdiff_t occurrence = 1); + vector FindAllCallReferences(const uintptr_t sectionBase, const size_t sectionSize); + CMemory FollowNearCall(const ptrdiff_t opcodeOffset = 0x1, const ptrdiff_t nextInstructionOffset = 0x5) const; CMemory FollowNearCallSelf(const ptrdiff_t opcodeOffset = 0x1, const ptrdiff_t nextInstructionOffset = 0x5); CMemory ResolveRelativeAddress(const ptrdiff_t registerOffset = 0x0, const ptrdiff_t nextInstructionOffset = 0x4) const; CMemory ResolveRelativeAddressSelf(const ptrdiff_t registerOffset = 0x0, const ptrdiff_t nextInstructionOffset = 0x4); - vector FindAllCallReferences(const uintptr_t sectionBase, const size_t sectionSize); + static void HookVirtualMethod(const uintptr_t virtualTable, const void* pHookMethod, const ptrdiff_t methodIndex, void** ppOriginalMethod); + static void HookImportedFunction(const uintptr_t pImportedMethod, const void* pHookMethod, void** ppOriginalMethod); private: uintptr_t ptr = 0; diff --git a/r5dev/public/tier0/module.h b/r5dev/public/tier0/module.h index 4eec0087..2e4cdbf0 100644 --- a/r5dev/public/tier0/module.h +++ b/r5dev/public/tier0/module.h @@ -7,42 +7,44 @@ public: struct ModuleSections_t { ModuleSections_t(void) = default; - ModuleSections_t(const string& svSectionName, uintptr_t pSectionBase, size_t nSectionSize) : - m_svSectionName(svSectionName), m_pSectionBase(pSectionBase), m_nSectionSize(nSectionSize) {} + ModuleSections_t(const char* sectionName, uintptr_t pSectionBase, size_t nSectionSize) : + m_SectionName(sectionName), m_pSectionBase(pSectionBase), m_nSectionSize(nSectionSize) {} - bool IsSectionValid(void) const - { - return m_nSectionSize != 0; - } + inline bool IsSectionValid(void) const { return m_nSectionSize != 0; } - string m_svSectionName; // Name of section. - uintptr_t m_pSectionBase{}; // Start address of section. - size_t m_nSectionSize{}; // Size of section. + string m_SectionName; // Name of section. + uintptr_t m_pSectionBase; // Start address of section. + size_t m_nSectionSize; // Size of section. }; CModule(void) = default; - CModule(const string& moduleName); - CModule(const uintptr_t nModuleBase, const string& svModuleName); + CModule(const char* szModuleName); + CModule(const char* szModuleName, const uintptr_t nModuleBase); void Init(); void LoadSections(); #ifndef PLUGINSDK - CMemory FindPatternSIMD(const string& svPattern, const ModuleSections_t* moduleSection = nullptr) const; - CMemory FindString(const string& string, const ptrdiff_t occurrence = 1, bool nullTerminator = false) const; - CMemory FindStringReadOnly(const string& svString, bool nullTerminator) const; + CMemory FindPatternSIMD(const char* szPattern, const ModuleSections_t* moduleSection = nullptr) const; + CMemory FindString(const char* szString, const ptrdiff_t occurrence = 1, bool nullTerminator = false) const; + CMemory FindStringReadOnly(const char* szString, bool nullTerminator) const; + CMemory FindFreeDataPage(const size_t nSize) const; - CMemory GetVirtualMethodTable(const string& svTableName, const size_t nRefIndex = 0); + CMemory GetVirtualMethodTable(const char* szTableName, const size_t nRefIndex = 0); #endif // !PLUGINSDK - CMemory GetImportedFunction(const string& svModuleName, const string& svFunctionName, const bool bGetFunctionReference) const; - CMemory GetExportedFunction(const string& svFunctionName) const; - ModuleSections_t GetSectionByName(const string& svSectionName) const; - uintptr_t GetModuleBase(void) const; - DWORD GetModuleSize(void) const; - string GetModuleName(void) const; - uintptr_t GetRVA(const uintptr_t nAddress) const; + CMemory GetImportedFunction(const char* szModuleName, const char* szFunctionName, const bool bGetFunctionReference) const; + CMemory GetExportedFunction(const char* szFunctionName) const; + ModuleSections_t GetSectionByName(const char* szSectionName) const; - IMAGE_NT_HEADERS64* m_pNTHeaders = nullptr; - IMAGE_DOS_HEADER* m_pDOSHeader = nullptr; + inline const vector& GetSections() const { return m_ModuleSections; } + inline uintptr_t GetModuleBase(void) const { return m_pModuleBase; } + inline DWORD GetModuleSize(void) const { return m_nModuleSize; } + inline const string& GetModuleName(void) const { return m_ModuleName; } + inline uintptr_t GetRVA(const uintptr_t nAddress) const { return (nAddress - GetModuleBase()); } + + void UnlinkFromPEB(void) const; + + IMAGE_NT_HEADERS64* m_pNTHeaders; + IMAGE_DOS_HEADER* m_pDOSHeader; ModuleSections_t m_ExecutableCode; ModuleSections_t m_ExceptionTable; @@ -50,12 +52,13 @@ public: ModuleSections_t m_ReadOnlyData; private: - CMemory FindPatternSIMD(const uint8_t* szPattern, const char* szMask, const ModuleSections_t* moduleSection = nullptr, const size_t nOccurrence = 0) const; + CMemory FindPatternSIMD(const uint8_t* pPattern, const char* szMask, + const ModuleSections_t* moduleSection = nullptr, const size_t nOccurrence = 0) const; - string m_svModuleName; - uintptr_t m_pModuleBase{}; - DWORD m_nModuleSize{}; - vector m_vModuleSections; + string m_ModuleName; + uintptr_t m_pModuleBase; + DWORD m_nModuleSize; + vector m_ModuleSections; }; #endif // MODULE_H \ No newline at end of file diff --git a/r5dev/public/tier0/sigcache.h b/r5dev/public/tier0/sigcache.h index 51679138..47a338ca 100644 --- a/r5dev/public/tier0/sigcache.h +++ b/r5dev/public/tier0/sigcache.h @@ -26,8 +26,8 @@ public: void SetDisabled(const bool bDisabled); void InvalidateMap(); - void AddEntry(const string& svPattern, const uint64_t nRVA); - bool FindEntry(const string& svPattern, uint64_t& nRVA) const; + void AddEntry(const char* szPattern, const uint64_t nRVA); + bool FindEntry(const char* szPattern, uint64_t& nRVA); bool LoadCache(const string& svCacheFile); bool WriteCache(const string& svCacheFile) const; diff --git a/r5dev/public/tier0/utility.h b/r5dev/public/tier0/utility.h index 0a8bbae1..4e21dc8d 100644 --- a/r5dev/public/tier0/utility.h +++ b/r5dev/public/tier0/utility.h @@ -66,10 +66,10 @@ string FourCCToString(int n); ///////////////////////////////////////////////////////////////////////////// // Bytes -vector StringToBytes(const string& svInput, bool bNullTerminator); -pair, string> StringToMaskedBytes(const string& svInput, bool bNullTerminator); -vector PatternToBytes(const string& svInput); -pair, string> PatternToMaskedBytes(const string& svInput); +vector StringToBytes(const char* szInput, bool bNullTerminator); +pair, string> StringToMaskedBytes(const char* szInput, bool bNullTerminator); +vector PatternToBytes(const char* szInput); +pair, string> PatternToMaskedBytes(const char* szInput); vector IntToDigits(int iValue); ///////////////////////////////////////////////////////////////////////////// diff --git a/r5dev/public/tier0/vtable.h b/r5dev/public/tier0/vtable.h index f2240554..fc91b261 100644 --- a/r5dev/public/tier0/vtable.h +++ b/r5dev/public/tier0/vtable.h @@ -5,9 +5,9 @@ class CVTableHelper public: CVTableHelper(void) = default; - CVTableHelper(CModule* module, const string& tableName = "", uint32_t refIndex = 0); - CVTableHelper(uintptr_t virtualTable, const string& tableName = ""); - CVTableHelper(void* virtualTable, const string& tableName = ""); + CVTableHelper(CModule* module, const char* tableName = "", uint32_t refIndex = 0); + CVTableHelper(uintptr_t virtualTable, const char* tableName = ""); + CVTableHelper(void* virtualTable, const char* tableName = ""); inline operator uintptr_t(void) const { diff --git a/r5dev/tier0/CMakeLists.txt b/r5dev/tier0/CMakeLists.txt index c0b1f42c..6e872c5e 100644 --- a/r5dev/tier0/CMakeLists.txt +++ b/r5dev/tier0/CMakeLists.txt @@ -34,6 +34,10 @@ add_sources( SOURCE_GROUP "Runtime" "binstream.cpp" ) +add_sources( SOURCE_GROUP "Windows" + "${ENGINE_SOURCE_DIR}/windows/tebpeb64.h" +) + file( GLOB TIER0_PUBLIC_HEADERS "${ENGINE_SOURCE_DIR}/public/tier0/*" ) diff --git a/r5dev/tier0/memaddr.cpp b/r5dev/tier0/memaddr.cpp index 75343a59..ceeb1e7c 100644 --- a/r5dev/tier0/memaddr.cpp +++ b/r5dev/tier0/memaddr.cpp @@ -7,10 +7,10 @@ //----------------------------------------------------------------------------- // Purpose: check array of opcodes starting from current address -// Input : vOpcodeArray - +// Input : &vOpcodeArray - // Output : true if equal, false otherwise //----------------------------------------------------------------------------- -bool CMemory::CheckOpCodes(const vector vOpcodeArray) const +bool CMemory::CheckOpCodes(const vector& vOpcodeArray) const { uintptr_t ref = ptr; @@ -29,9 +29,9 @@ bool CMemory::CheckOpCodes(const vector vOpcodeArray) const //----------------------------------------------------------------------------- // Purpose: patch array of opcodes starting from current address -// Input : vOpcodeArray - +// Input : &vOpcodeArray - //----------------------------------------------------------------------------- -void CMemory::Patch(const vector vOpcodeArray) const +void CMemory::Patch(const vector& vOpcodeArray) const { DWORD oldProt = NULL; @@ -49,23 +49,20 @@ void CMemory::Patch(const vector vOpcodeArray) const //----------------------------------------------------------------------------- // Purpose: patch string constant at current address -// Input : &svString - +// Input : *szString - //----------------------------------------------------------------------------- -void CMemory::PatchString(const string& svString) const +void CMemory::PatchString(const char* szString) const { DWORD oldProt = NULL; - - SIZE_T dwSize = svString.size(); - const vector bytes(svString.begin(), svString.end()); + SIZE_T dwSize = strlen(szString); VirtualProtect(reinterpret_cast(ptr), dwSize, PAGE_EXECUTE_READWRITE, &oldProt); // Patch page to be able to read and write to it. - for (size_t i = 0; i < svString.size(); i++) + for (size_t i = 0; i < dwSize; i++) { - *reinterpret_cast(ptr + i) = bytes[i]; // Write string to Address. + *reinterpret_cast(ptr + i) = szString[i]; // Write string to Address. } - dwSize = svString.size(); VirtualProtect(reinterpret_cast(ptr), dwSize, oldProt, &oldProt); // Restore protection. } @@ -77,11 +74,11 @@ void CMemory::PatchString(const string& svString) const // occurrence - // Output : CMemory //----------------------------------------------------------------------------- -CMemory CMemory::FindPattern(const string& svPattern, const Direction searchDirect, const int opCodesToScan, const ptrdiff_t occurrence) const +CMemory CMemory::FindPattern(const char* szPattern, const Direction searchDirect, const int opCodesToScan, const ptrdiff_t occurrence) const { uint8_t* pScanBytes = reinterpret_cast(ptr); // Get the base of the module. - const vector PatternBytes = PatternToBytes(svPattern); // Convert our pattern to a byte array. + const vector PatternBytes = PatternToBytes(szPattern); // Convert our pattern to a byte array. const pair bytesInfo = std::make_pair(PatternBytes.size(), PatternBytes.data()); // Get the size and data of our bytes. ptrdiff_t occurrences = 0; @@ -124,11 +121,11 @@ CMemory CMemory::FindPattern(const string& svPattern, const Direction searchDire // occurrence - // Output : CMemory //----------------------------------------------------------------------------- -CMemory CMemory::FindPatternSelf(const string& svPattern, const Direction searchDirect, const int opCodesToScan, const ptrdiff_t occurrence) +CMemory CMemory::FindPatternSelf(const char* szPattern, const Direction searchDirect, const int opCodesToScan, const ptrdiff_t occurrence) { uint8_t* pScanBytes = reinterpret_cast(ptr); // Get the base of the module. - const vector PatternBytes = PatternToBytes(svPattern); // Convert our pattern to a byte array. + const vector PatternBytes = PatternToBytes(szPattern); // Convert our pattern to a byte array. const pair bytesInfo = std::make_pair(PatternBytes.size(), PatternBytes.data()); // Get the size and data of our bytes. ptrdiff_t occurrences = 0; @@ -165,6 +162,34 @@ CMemory CMemory::FindPatternSelf(const string& svPattern, const Direction search return *this; } +//----------------------------------------------------------------------------- +// Purpose: resolve all 'call' references to ptr +// (This is very slow only use for mass patching.) +// Input : sectionBase - +// sectionSize - +// Output : vector +//----------------------------------------------------------------------------- +vector CMemory::FindAllCallReferences(const uintptr_t sectionBase, const size_t sectionSize) +{ + vector referencesInfo = {}; + + uint8_t* pTextStart = reinterpret_cast(sectionBase); + for (size_t i = 0ull; i < sectionSize - 0x5; i++, _mm_prefetch(reinterpret_cast(pTextStart + 64), _MM_HINT_NTA)) + { + if (pTextStart[i] == CALL) + { + CMemory memAddr = CMemory(&pTextStart[i]); + if (!memAddr.Offset(0x1).CheckOpCodes({ 0x00, 0x00, 0x00, 0x00 })) // Check if its not a dynamic resolved call. + { + if (memAddr.FollowNearCall() == *this) + referencesInfo.push_back(memAddr); + } + } + } + + return referencesInfo; +} + //----------------------------------------------------------------------------- // Purpose: ResolveRelativeAddress wrapper // Input : opcodeOffset - @@ -230,40 +255,12 @@ CMemory CMemory::ResolveRelativeAddressSelf(const ptrdiff_t registerOffset, cons return *this; } -//----------------------------------------------------------------------------- -// Purpose: resolve all 'call' references to ptr -// (This is very slow only use for mass patching.) -// Input : sectionBase - -// sectionSize - -// Output : vector -//----------------------------------------------------------------------------- -vector CMemory::FindAllCallReferences(const uintptr_t sectionBase, const size_t sectionSize) -{ - vector referencesInfo = {}; - - uint8_t* pTextStart = reinterpret_cast(sectionBase); - for (size_t i = 0ull; i < sectionSize - 0x5; i++, _mm_prefetch(reinterpret_cast(pTextStart + 64), _MM_HINT_NTA)) - { - if (pTextStart[i] == CALL) - { - CMemory memAddr = CMemory(&pTextStart[i]); - if (!memAddr.Offset(0x1).CheckOpCodes({ 0x00, 0x00, 0x00, 0x00 })) // Check if its not a dynamic resolved call. - { - if (memAddr.FollowNearCall() == *this) - referencesInfo.push_back(memAddr); - } - } - } - - return referencesInfo; -} - //----------------------------------------------------------------------------- // Purpose: patch virtual method to point to a user set function -// Input : virtualTable - -// pHookMethod - -// methodIndex - -// pOriginalMethod - +// Input : virtualTable - +// *pHookMethod - +// methodIndex - +// **pOriginalMethod - // Output : void** via pOriginalMethod //----------------------------------------------------------------------------- void CMemory::HookVirtualMethod(const uintptr_t virtualTable, const void* pHookMethod, const ptrdiff_t methodIndex, void** ppOriginalMethod) @@ -285,6 +282,33 @@ void CMemory::HookVirtualMethod(const uintptr_t virtualTable, const void* pHookM // Restore original page. VirtualProtect(reinterpret_cast(virtualMethod), sizeof(virtualMethod), oldProt, &oldProt); + // Move original function into argument. + *ppOriginalMethod = reinterpret_cast(originalFunction); +} + +//----------------------------------------------------------------------------- +// Purpose: patch iat entry to point to a user set function +// Input : pImportedMethod - +// pHookMethod - +// ppOriginalMethod - +// Output : void** via ppOriginalMethod +//----------------------------------------------------------------------------- +void CMemory::HookImportedFunction(const uintptr_t pImportedMethod, const void* pHookMethod, void** ppOriginalMethod) +{ + DWORD oldProt = NULL; + + // Preserve original function. + const uintptr_t originalFunction = *reinterpret_cast(pImportedMethod); + + // Set page for current iat entry to execute n read n write. + VirtualProtect(reinterpret_cast(pImportedMethod), sizeof(void*), PAGE_EXECUTE_READWRITE, &oldProt); + + // Set method to our hook. + *reinterpret_cast(pImportedMethod) = reinterpret_cast(pHookMethod); + + // Restore original page. + VirtualProtect(reinterpret_cast(pImportedMethod), sizeof(void*), oldProt, &oldProt); + // Move original function into argument. *ppOriginalMethod = reinterpret_cast(originalFunction); } \ No newline at end of file diff --git a/r5dev/tier0/module.cpp b/r5dev/tier0/module.cpp index b9f06b83..cbcba990 100644 --- a/r5dev/tier0/module.cpp +++ b/r5dev/tier0/module.cpp @@ -5,15 +5,16 @@ //===========================================================================// #include "tier0/memaddr.h" #include "tier0/sigcache.h" +#include "windows/tebpeb64.h" //----------------------------------------------------------------------------- // Purpose: constructor -// Input : *svModuleName +// Input : *szModuleName - //----------------------------------------------------------------------------- -CModule::CModule(const string& svModuleName) - : m_svModuleName(svModuleName) +CModule::CModule(const char* szModuleName) + : m_ModuleName(szModuleName) { - m_pModuleBase = reinterpret_cast(GetModuleHandleA(svModuleName.c_str())); + m_pModuleBase = reinterpret_cast(GetModuleHandleA(szModuleName)); Init(); LoadSections(); @@ -21,10 +22,11 @@ CModule::CModule(const string& svModuleName) //----------------------------------------------------------------------------- // Purpose: constructor -// Input : nModuleBase +// Input : *szModuleName - +// nModuleBase - //----------------------------------------------------------------------------- -CModule::CModule(const uintptr_t nModuleBase, const string& svModuleName) - : m_svModuleName(svModuleName) +CModule::CModule(const char* szModuleName, const uintptr_t nModuleBase) + : m_ModuleName(szModuleName) , m_pModuleBase(nModuleBase) { Init(); @@ -45,7 +47,7 @@ void CModule::Init() for (WORD i = 0; i < m_pNTHeaders->FileHeader.NumberOfSections; i++) // Loop through the sections. { const IMAGE_SECTION_HEADER& hCurrentSection = hSection[i]; // Get current section. - m_vModuleSections.push_back(ModuleSections_t(reinterpret_cast(hCurrentSection.Name), + m_ModuleSections.push_back(ModuleSections_t(reinterpret_cast(hCurrentSection.Name), static_cast(m_pModuleBase + hCurrentSection.VirtualAddress), hCurrentSection.SizeOfRawData)); // Push back a struct with the section data. } } @@ -64,11 +66,14 @@ void CModule::LoadSections() #ifndef PLUGINSDK //----------------------------------------------------------------------------- // Purpose: find array of bytes in process memory using SIMD instructions -// Input : *szPattern - -// *szMask - +// Input : *pPattern - +// *szMask - +// *moduleSection - +// nOccurrence - // Output : CMemory //----------------------------------------------------------------------------- -CMemory CModule::FindPatternSIMD(const uint8_t* szPattern, const char* szMask, const ModuleSections_t* moduleSection, const size_t nOccurrence) const +CMemory CModule::FindPatternSIMD(const uint8_t* pPattern, const char* szMask, + const ModuleSections_t* moduleSection, const size_t nOccurrence) const { if (!m_ExecutableCode.IsSectionValid()) return CMemory(); @@ -97,11 +102,11 @@ CMemory CModule::FindPatternSIMD(const uint8_t* szPattern, const char* szMask, c } } } - const __m128i xmm1 = _mm_loadu_si128(reinterpret_cast(szPattern)); + const __m128i xmm1 = _mm_loadu_si128(reinterpret_cast(pPattern)); __m128i xmm2, xmm3, msks; for (; pData != pEnd; _mm_prefetch(reinterpret_cast(++pData + 64), _MM_HINT_NTA)) { - if (szPattern[0] == pData[0]) + if (pPattern[0] == pData[0]) { xmm2 = _mm_loadu_si128(reinterpret_cast(pData)); msks = _mm_cmpeq_epi8(xmm1, xmm2); @@ -110,7 +115,7 @@ CMemory CModule::FindPatternSIMD(const uint8_t* szPattern, const char* szMask, c for (uintptr_t i = 1; i < static_cast(iNumMasks); ++i) { xmm2 = _mm_loadu_si128(reinterpret_cast((pData + i * 16))); - xmm3 = _mm_loadu_si128(reinterpret_cast((szPattern + i * 16))); + xmm3 = _mm_loadu_si128(reinterpret_cast((pPattern + i * 16))); msks = _mm_cmpeq_epi8(xmm2, xmm3); if ((_mm_movemask_epi8(msks) & nMasks[i]) == nMasks[i]) { @@ -139,97 +144,47 @@ CMemory CModule::FindPatternSIMD(const uint8_t* szPattern, const char* szMask, c return CMemory(); } - //----------------------------------------------------------------------------- // Purpose: find a string pattern in process memory using SIMD instructions -// Input : &svPattern -// &moduleSection +// Input : *szPattern - +// *moduleSection - // Output : CMemory //----------------------------------------------------------------------------- -CMemory CModule::FindPatternSIMD(const string& svPattern, const ModuleSections_t* moduleSection) const +CMemory CModule::FindPatternSIMD(const char* szPattern, const ModuleSections_t* moduleSection) const { uint64_t nRVA; - if (g_SigCache.FindEntry(svPattern, nRVA)) + if (g_SigCache.FindEntry(szPattern, nRVA)) { return CMemory(nRVA + GetModuleBase()); } - const pair, string> patternInfo = PatternToMaskedBytes(svPattern); + const pair, string> patternInfo = PatternToMaskedBytes(szPattern); const CMemory memory = FindPatternSIMD(patternInfo.first.data(), patternInfo.second.c_str(), moduleSection); - g_SigCache.AddEntry(svPattern, GetRVA(memory.GetPtr())); + g_SigCache.AddEntry(szPattern, GetRVA(memory.GetPtr())); return memory; } -//----------------------------------------------------------------------------- -// Purpose: find address of input string constant in read only memory -// Input : *svString - -// bNullTerminator - -// Output : CMemory -//----------------------------------------------------------------------------- -CMemory CModule::FindStringReadOnly(const string& svString, bool bNullTerminator) const -{ - if (!m_ReadOnlyData.IsSectionValid()) - return CMemory(); - - uint64_t nRVA; - if (g_SigCache.FindEntry(svString, nRVA)) - { - return CMemory(nRVA + GetModuleBase()); - } - - const vector vBytes = StringToBytes(svString, bNullTerminator); // Convert our string to a byte array. - const pair bytesInfo = std::make_pair(vBytes.size(), vBytes.data()); // Get the size and data of our bytes. - - const uint8_t* pBase = reinterpret_cast(m_ReadOnlyData.m_pSectionBase); // Get start of .rdata section. - - for (size_t i = 0ull; i < m_ReadOnlyData.m_nSectionSize - bytesInfo.first; i++) - { - bool bFound = true; - - // If either the current byte equals to the byte in our pattern or our current byte in the pattern is a wildcard - // our if clause will be false. - for (size_t j = 0ull; j < bytesInfo.first; j++) - { - if (pBase[i + j] != bytesInfo.second[j] && bytesInfo.second[j] != -1) - { - bFound = false; - break; - } - } - - if (bFound) - { - CMemory result = CMemory(&pBase[i]); - g_SigCache.AddEntry(svString, GetRVA(result.GetPtr())); - - return result; - } - } - - return CMemory(); -} - //----------------------------------------------------------------------------- // Purpose: find address of reference to string constant in executable memory -// Input : *svString - +// Input : *szString - // bNullTerminator - // Output : CMemory //----------------------------------------------------------------------------- -CMemory CModule::FindString(const string& svString, const ptrdiff_t nOccurrence, bool bNullTerminator) const +CMemory CModule::FindString(const char* szString, const ptrdiff_t nOccurrence, bool bNullTerminator) const { if (!m_ExecutableCode.IsSectionValid()) return CMemory(); uint64_t nRVA; - string svPackedString = svString + std::to_string(nOccurrence); + string svPackedString = szString + std::to_string(nOccurrence); - if (g_SigCache.FindEntry(svPackedString, nRVA)) + if (g_SigCache.FindEntry(svPackedString.c_str(), nRVA)) { return CMemory(nRVA + GetModuleBase()); } - const CMemory stringAddress = FindStringReadOnly(svString, bNullTerminator); // Get Address for the string in the .rdata section. + const CMemory stringAddress = FindStringReadOnly(szString, bNullTerminator); // Get Address for the string in the .rdata section. if (!stringAddress) return CMemory(); @@ -255,7 +210,7 @@ CMemory CModule::FindString(const string& svString, const ptrdiff_t nOccurrence, if (nOccurrence == dOccurrencesFound) { resultAddress = CMemory(&pTextStart[i]); - g_SigCache.AddEntry(svPackedString, GetRVA(resultAddress.GetPtr())); + g_SigCache.AddEntry(svPackedString.c_str(), GetRVA(resultAddress.GetPtr())); return resultAddress; } @@ -266,30 +221,127 @@ CMemory CModule::FindString(const string& svString, const ptrdiff_t nOccurrence, } resultAddress = CMemory(pLatestOccurrence); - g_SigCache.AddEntry(svPackedString, GetRVA(resultAddress.GetPtr())); + g_SigCache.AddEntry(svPackedString.c_str(), GetRVA(resultAddress.GetPtr())); return resultAddress; } //----------------------------------------------------------------------------- -// Purpose: get address of a virtual method table by rtti type descriptor name. -// Input : *svTableName - -// nRefIndex - -// Output : address of virtual method table, null if not found. +// Purpose: find address of input string constant in read only memory +// Input : *szString - +// bNullTerminator - +// Output : CMemory //----------------------------------------------------------------------------- -CMemory CModule::GetVirtualMethodTable(const string& svTableName, const size_t nRefIndex) +CMemory CModule::FindStringReadOnly(const char* szString, bool bNullTerminator) const { - uint64_t nRVA; // Packed together as we can have multiple VFTable searches, but with different ref indexes. - string svPackedTableName = svTableName + std::to_string(nRefIndex); + if (!m_ReadOnlyData.IsSectionValid()) + return CMemory(); - if (g_SigCache.FindEntry(svPackedTableName, nRVA)) + uint64_t nRVA; + if (g_SigCache.FindEntry(szString, nRVA)) { return CMemory(nRVA + GetModuleBase()); } - ModuleSections_t moduleSection = { ".data", m_RunTimeData.m_pSectionBase, m_RunTimeData.m_nSectionSize }; + const vector vBytes = StringToBytes(szString, bNullTerminator); // Convert our string to a byte array. + const pair bytesInfo = std::make_pair(vBytes.size(), vBytes.data()); // Get the size and data of our bytes. - const auto tableNameInfo = StringToMaskedBytes(svTableName, false); + const uint8_t* pBase = reinterpret_cast(m_ReadOnlyData.m_pSectionBase); // Get start of .rdata section. + + for (size_t i = 0ull; i < m_ReadOnlyData.m_nSectionSize - bytesInfo.first; i++) + { + bool bFound = true; + + // If either the current byte equals to the byte in our pattern or our current byte in the pattern is a wildcard + // our if clause will be false. + for (size_t j = 0ull; j < bytesInfo.first; j++) + { + if (pBase[i + j] != bytesInfo.second[j] && bytesInfo.second[j] != -1) + { + bFound = false; + break; + } + } + + if (bFound) + { + CMemory result = CMemory(&pBase[i]); + g_SigCache.AddEntry(szString, GetRVA(result.GetPtr())); + + return result; + } + } + + return CMemory(); +} + +//----------------------------------------------------------------------------- +// Purpose: find 'free' page in r/w/x sections +// Input : nSize - +// Output : CMemory +//----------------------------------------------------------------------------- +CMemory CModule::FindFreeDataPage(const size_t nSize) const +{ + auto checkDataSection = [](const void* address, const std::size_t size) + { + MEMORY_BASIC_INFORMATION membInfo = { 0 }; + + VirtualQuery(address, &membInfo, sizeof(membInfo)); + + if (membInfo.AllocationBase && membInfo.BaseAddress && membInfo.State == MEM_COMMIT && !(membInfo.Protect & PAGE_GUARD) && membInfo.Protect != PAGE_NOACCESS) + { + if ((membInfo.Protect & (PAGE_EXECUTE_READWRITE | PAGE_READWRITE)) && membInfo.RegionSize >= size) + { + return ((membInfo.Protect & (PAGE_EXECUTE_READWRITE | PAGE_READWRITE)) && membInfo.RegionSize >= size) ? true : false; + } + } + return false; + }; + + // This is very unstable, this doesn't check for the actual 'page' sizes. + // Also can be optimized to search per 'section'. + const uintptr_t endOfModule = m_pModuleBase + m_pNTHeaders->OptionalHeader.SizeOfImage - sizeof(uintptr_t); + for (uintptr_t currAddr = endOfModule; m_pModuleBase < currAddr; currAddr -= sizeof(uintptr_t)) + { + if (*reinterpret_cast(currAddr) == 0 && checkDataSection(reinterpret_cast(currAddr), nSize)) + { + bool bIsGoodPage = true; + uint32_t nPageCount = 0; + + for (; nPageCount < nSize && bIsGoodPage; nPageCount += sizeof(uintptr_t)) + { + const uintptr_t pageData = *reinterpret_cast(currAddr + nPageCount); + if (pageData != 0) + bIsGoodPage = false; + } + + if (bIsGoodPage && nPageCount >= nSize) + return currAddr; + } + } + + return CMemory(); +} + +//----------------------------------------------------------------------------- +// Purpose: get address of a virtual method table by rtti type descriptor name. +// Input : *szTableName - +// nRefIndex - +// Output : address of virtual method table, null if not found. +//----------------------------------------------------------------------------- +CMemory CModule::GetVirtualMethodTable(const char* szTableName, const size_t nRefIndex) +{ + uint64_t nRVA; // Packed together as we can have multiple VFTable searches, but with different ref indexes. + string svPackedTableName = szTableName + std::to_string(nRefIndex); + + if (g_SigCache.FindEntry(svPackedTableName.c_str(), nRVA)) + { + return CMemory(nRVA + GetModuleBase()); + } + + ModuleSections_t moduleSection(".data", m_RunTimeData.m_pSectionBase, m_RunTimeData.m_nSectionSize); + + const auto tableNameInfo = StringToMaskedBytes(szTableName, false); CMemory rttiTypeDescriptor = FindPatternSIMD(tableNameInfo.first.data(), tableNameInfo.second.c_str(), &moduleSection).OffsetSelf(-0x10); if (!rttiTypeDescriptor) return CMemory(); @@ -314,7 +366,7 @@ CMemory CModule::GetVirtualMethodTable(const string& svTableName, const size_t n moduleSection = { ".rdata", m_ReadOnlyData.m_pSectionBase, m_ReadOnlyData.m_nSectionSize }; CMemory vfTable = FindPatternSIMD(reinterpret_cast(&referenceOffset), "xxxxxxxx", &moduleSection).OffsetSelf(0x8); - g_SigCache.AddEntry(svPackedTableName, GetRVA(vfTable.GetPtr())); + g_SigCache.AddEntry(svPackedTableName.c_str(), GetRVA(vfTable.GetPtr())); return vfTable; } @@ -323,7 +375,14 @@ CMemory CModule::GetVirtualMethodTable(const string& svTableName, const size_t n } #endif // !PLUGINSDK -CMemory CModule::GetImportedFunction(const string& svModuleName, const string& svFunctionName, const bool bGetFunctionReference) const +//----------------------------------------------------------------------------- +// Purpose: get address of imported function in target module +// Input : *szModuleName - +// *szFunctionName - +// bGetFunctionReference - +// Output : CMemory +//----------------------------------------------------------------------------- +CMemory CModule::GetImportedFunction(const char* szModuleName, const char* szFunctionName, const bool bGetFunctionReference) const { if (!m_pDOSHeader || m_pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) // Is dosHeader valid? return CMemory(); @@ -339,9 +398,9 @@ CMemory CModule::GetImportedFunction(const string& svModuleName, const string& s 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. - string svImportedModuleName = reinterpret_cast(reinterpret_cast(m_pModuleBase + pIID->Name)); + const char* szImportedModuleName = reinterpret_cast(reinterpret_cast(m_pModuleBase + pIID->Name)); - if (IsEqualNoCase(svImportedModuleName, svModuleName)) // Is this our wanted imported module?. + if (stricmp(szImportedModuleName, szModuleName) == 0) // Is this our wanted imported module?. { // Original First Thunk to get function name. IMAGE_THUNK_DATA* pOgFirstThunk = reinterpret_cast(m_pModuleBase + pIID->OriginalFirstThunk); @@ -353,9 +412,7 @@ CMemory CModule::GetImportedFunction(const string& svModuleName, const string& s // Get image import by name. const IMAGE_IMPORT_BY_NAME* pImageImportByName = reinterpret_cast(m_pModuleBase + pOgFirstThunk->u1.AddressOfData); - // Get import function name. - const string svImportedFunctionName = pImageImportByName->Name; - if (svImportedFunctionName.compare(svFunctionName) == 0) // Is this our wanted imported function? + if (strcmp(pImageImportByName->Name, szFunctionName) == 0) // Is this our wanted imported function? { // Grab function address from firstThunk. uintptr_t* pFunctionAddress = &pFirstThunk->u1.Function; @@ -371,11 +428,11 @@ CMemory CModule::GetImportedFunction(const string& svModuleName, const string& s //----------------------------------------------------------------------------- // Purpose: get address of exported function in this module -// Input : *svFunctionName - +// Input : *szFunctionName - // bNullTerminator - // Output : CMemory //----------------------------------------------------------------------------- -CMemory CModule::GetExportedFunction(const string& svFunctionName) const +CMemory CModule::GetExportedFunction(const char* szFunctionName) const { if (!m_pDOSHeader || m_pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) // Is dosHeader valid? return CMemory(); @@ -410,9 +467,9 @@ CMemory CModule::GetExportedFunction(const string& svFunctionName) const for (DWORD i = 0; i < pImageExportDirectory->NumberOfFunctions; i++) // Iterate through all the functions. { // Get virtual relative Address of the function name. Then add module base Address to get the actual location. - string ExportFunctionName = reinterpret_cast(reinterpret_cast(m_pModuleBase + pAddressOfName[i])); + const char* ExportFunctionName = reinterpret_cast(reinterpret_cast(m_pModuleBase + pAddressOfName[i])); - if (ExportFunctionName.compare(svFunctionName) == 0) // Is this our wanted exported function? + if (strcmp(ExportFunctionName, szFunctionName) == 0) // Is this our wanted exported function? { // 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 CMemory(m_pModuleBase + pAddressOfFunctions[reinterpret_cast(pAddressOfOrdinals)[i]]); // Return as CMemory class. @@ -423,14 +480,14 @@ CMemory CModule::GetExportedFunction(const string& svFunctionName) const //----------------------------------------------------------------------------- // Purpose: get the module section by name (example: '.rdata', '.text') -// Input : *svModuleName - +// Input : *szSectionName - // Output : ModuleSections_t //----------------------------------------------------------------------------- -CModule::ModuleSections_t CModule::GetSectionByName(const string& svSectionName) const +CModule::ModuleSections_t CModule::GetSectionByName(const char* szSectionName) const { - for (const ModuleSections_t& section : m_vModuleSections) + for (const ModuleSections_t& section : m_ModuleSections) { - if (section.m_svSectionName == svSectionName) + if (section.m_SectionName.compare(szSectionName) == 0) return section; } @@ -438,33 +495,29 @@ CModule::ModuleSections_t CModule::GetSectionByName(const string& svSectionName) } //----------------------------------------------------------------------------- -// Purpose: returns the module base +// Purpose: unlink module from peb //----------------------------------------------------------------------------- -uintptr_t CModule::GetModuleBase(void) const +void CModule::UnlinkFromPEB() const // Disclaimer: This does not bypass GetMappedFileName. That function calls NtQueryVirtualMemory which does a syscall to ntoskrnl for getting info on a section. { - return m_pModuleBase; -} +#define UNLINK_FROM_PEB(entry) \ + (entry).Flink->Blink = (entry).Blink; \ + (entry).Blink->Flink = (entry).Flink; -//----------------------------------------------------------------------------- -// Purpose: returns the module size -//----------------------------------------------------------------------------- -DWORD CModule::GetModuleSize(void) const -{ - return m_nModuleSize; -} + const PEB64* processEnvBlock = reinterpret_cast(__readgsqword(0x60)); // https://en.wikipedia.org/wiki/Win32_Thread_Information_Block + const LIST_ENTRY* inLoadOrderList = &processEnvBlock->Ldr->InLoadOrderModuleList; -//----------------------------------------------------------------------------- -// Purpose: returns the module name -//----------------------------------------------------------------------------- -string CModule::GetModuleName(void) const -{ - return m_svModuleName; -} + for (LIST_ENTRY* entry = inLoadOrderList->Flink; entry != inLoadOrderList; entry = entry->Flink) + { + const PLDR_DATA_TABLE_ENTRY pldrEntry = reinterpret_cast(entry->Flink); + const std::uintptr_t baseAddr = reinterpret_cast(pldrEntry->DllBase); -//----------------------------------------------------------------------------- -// Purpose: returns the RVA of given address -//----------------------------------------------------------------------------- -uintptr_t CModule::GetRVA(const uintptr_t nAddress) const -{ - return (nAddress - GetModuleBase()); + if (baseAddr != m_pModuleBase) + continue; + + UNLINK_FROM_PEB(pldrEntry->InInitializationOrderLinks); + UNLINK_FROM_PEB(pldrEntry->InMemoryOrderLinks); + UNLINK_FROM_PEB(pldrEntry->InLoadOrderLinks); + break; + } +#undef UNLINK_FROM_PEB } diff --git a/r5dev/tier0/sigcache.cpp b/r5dev/tier0/sigcache.cpp index 0570afc5..56cc56c1 100644 --- a/r5dev/tier0/sigcache.cpp +++ b/r5dev/tier0/sigcache.cpp @@ -38,38 +38,38 @@ void CSigCache::InvalidateMap() return; } - (*m_Cache.mutable_smap()).clear(); + m_Cache.mutable_smap()->clear(); } //----------------------------------------------------------------------------- // Purpose: creates a map of a pattern and relative virtual address -// Input : &svPattern - (key) -// nRVA - (value) +// Input : *szPattern - (key) +// nRVA - (value) //----------------------------------------------------------------------------- -void CSigCache::AddEntry(const string& svPattern, const uint64_t nRVA) +void CSigCache::AddEntry(const char* szPattern, const uint64_t nRVA) { if (m_bDisabled) { return; } - (*m_Cache.mutable_smap())[svPattern] = nRVA; + (*m_Cache.mutable_smap())[szPattern] = nRVA; } //----------------------------------------------------------------------------- // Purpose: finds a pattern key in the cache map and sets its value to nRVA -// Input : &svPattern - -// &nRVA - +// Input : &szPattern - +// &nRVA - // Output : true if key is found, false otherwise //----------------------------------------------------------------------------- -bool CSigCache::FindEntry(const string& svPattern, uint64_t& nRVA) const +bool CSigCache::FindEntry(const char* szPattern, uint64_t& nRVA) { if (!m_bDisabled && m_bInitialized) { - google::protobuf::Map sMap = m_Cache.smap(); - auto p = sMap.find(svPattern); + google::protobuf::Map* sMap = m_Cache.mutable_smap(); + auto p = sMap->find(szPattern); - if (p != sMap.end()) + if (p != sMap->end()) { nRVA = p->second; return true; diff --git a/r5dev/tier0/utility.cpp b/r5dev/tier0/utility.cpp index cb2b7a7b..1f1ea68c 100644 --- a/r5dev/tier0/utility.cpp +++ b/r5dev/tier0/utility.cpp @@ -864,13 +864,13 @@ string& StringTrim(string& svInput, const char* pszToTrim, bool bTrimAll) /////////////////////////////////////////////////////////////////////////////// // For converting a string to an array of bytes. -vector StringToBytes(const string& svInput, bool bNullTerminator) +vector StringToBytes(const char* szInput, bool bNullTerminator) { - char* pszStringStart = const_cast(svInput.c_str()); - char* pszStringEnd = pszStringStart + strlen(svInput.c_str()); - vector vBytes = vector{ }; + const char* pszStringStart = const_cast(szInput); + const char* pszStringEnd = pszStringStart + strlen(szInput); + vector vBytes; - for (char* pszCurrentByte = pszStringStart; pszCurrentByte < pszStringEnd; ++pszCurrentByte) + for (const char* pszCurrentByte = pszStringStart; pszCurrentByte < pszStringEnd; ++pszCurrentByte) { // Dereference character and push back the byte. vBytes.push_back(*pszCurrentByte); @@ -885,14 +885,14 @@ vector StringToBytes(const string& svInput, bool bNullTerminator) /////////////////////////////////////////////////////////////////////////////// // For converting a string to an array of bytes. -pair, string> StringToMaskedBytes(const string& svInput, bool bNullTerminator) +pair, string> StringToMaskedBytes(const char* szInput, bool bNullTerminator) { - char* pszStringStart = const_cast(svInput.c_str()); - char* pszStringEnd = pszStringStart + strlen(svInput.c_str()); - vector vBytes = vector{ }; - string svMask = string(); + const char* pszStringStart = const_cast(szInput); + const char* pszStringEnd = pszStringStart + strlen(szInput); + vector vBytes; + string svMask; - for (char* pszCurrentByte = pszStringStart; pszCurrentByte < pszStringEnd; ++pszCurrentByte) + for (const char* pszCurrentByte = pszStringStart; pszCurrentByte < pszStringEnd; ++pszCurrentByte) { // Dereference character and push back the byte. vBytes.push_back(*pszCurrentByte); @@ -921,13 +921,13 @@ string FourCCToString(int n) /////////////////////////////////////////////////////////////////////////////// // For converting a string pattern with wildcards to an array of bytes. -vector PatternToBytes(const string& svInput) +vector PatternToBytes(const char* szInput) { - char* pszPatternStart = const_cast(svInput.c_str()); - char* pszPatternEnd = pszPatternStart + strlen(svInput.c_str()); - vector vBytes = vector{ }; + const char* pszPatternStart = const_cast(szInput); + const char* pszPatternEnd = pszPatternStart + strlen(szInput); + vector vBytes; - for (char* pszCurrentByte = pszPatternStart; pszCurrentByte < pszPatternEnd; ++pszCurrentByte) + for (const char* pszCurrentByte = pszPatternStart; pszCurrentByte < pszPatternEnd; ++pszCurrentByte) { if (*pszCurrentByte == '?') { @@ -940,7 +940,7 @@ vector PatternToBytes(const string& svInput) } else { - vBytes.push_back(strtoul(pszCurrentByte, &pszCurrentByte, 16)); + vBytes.push_back(strtoul(pszCurrentByte, const_cast(&pszCurrentByte), 16)); } } return vBytes; @@ -948,14 +948,15 @@ vector PatternToBytes(const string& svInput) /////////////////////////////////////////////////////////////////////////////// // For converting a string pattern with wildcards to an array of bytes and mask. -pair, string> PatternToMaskedBytes(const string& svInput) +pair, string> PatternToMaskedBytes(const char* szInput) { - char* pszPatternStart = const_cast(svInput.c_str()); - char* pszPatternEnd = pszPatternStart + strlen(svInput.c_str()); - vector vBytes = vector{ }; - string svMask = string(); + const char* pszPatternStart = const_cast(szInput); + const char* pszPatternEnd = pszPatternStart + strlen(szInput); - for (char* pszCurrentByte = pszPatternStart; pszCurrentByte < pszPatternEnd; ++pszCurrentByte) + vector vBytes; + string svMask; + + for (const char* pszCurrentByte = pszPatternStart; pszCurrentByte < pszPatternEnd; ++pszCurrentByte) { if (*pszCurrentByte == '?') { @@ -969,7 +970,7 @@ pair, string> PatternToMaskedBytes(const string& svInput) } else { - vBytes.push_back(uint8_t(strtoul(pszCurrentByte, &pszCurrentByte, 16))); + vBytes.push_back(uint8_t(strtoul(pszCurrentByte, const_cast(&pszCurrentByte), 16))); svMask += 'x'; } } diff --git a/r5dev/tier0/vtable.cpp b/r5dev/tier0/vtable.cpp index 196f9485..044e6c3f 100644 --- a/r5dev/tier0/vtable.cpp +++ b/r5dev/tier0/vtable.cpp @@ -13,7 +13,8 @@ // const std::string& - // uint32_t //----------------------------------------------------------------------------- -CVTableHelper::CVTableHelper(CModule* module, const string& tableName, uint32_t refIndex) : m_svVirtualTableName(tableName) +CVTableHelper::CVTableHelper(CModule* module, const char* tableName, uint32_t refIndex) + : m_svVirtualTableName(tableName) { m_pVirtualTable = module->GetVirtualMethodTable(tableName, refIndex); m_nVirtualFunctionCount = GetVTableLength(); @@ -26,7 +27,8 @@ CVTableHelper::CVTableHelper(CModule* module, const string& tableName, uint32_t // Input : uintptr_t - // const std::string& - //----------------------------------------------------------------------------- -CVTableHelper::CVTableHelper(uintptr_t virtualTable, const string& tableName) : m_pVirtualTable(virtualTable), m_svVirtualTableName(tableName) +CVTableHelper::CVTableHelper(uintptr_t virtualTable, const char* tableName) + : m_pVirtualTable(virtualTable), m_svVirtualTableName(tableName) { m_nVirtualFunctionCount = GetVTableLength(); GetAllVTableFunctions(); @@ -38,7 +40,8 @@ CVTableHelper::CVTableHelper(uintptr_t virtualTable, const string& tableName) : // Input : void* - // const std::string& - //----------------------------------------------------------------------------- -CVTableHelper::CVTableHelper(void* virtualTable, const string& tableName) : m_pVirtualTable(uintptr_t(virtualTable)), m_svVirtualTableName(tableName) +CVTableHelper::CVTableHelper(void* virtualTable, const char* tableName) + : m_pVirtualTable(uintptr_t(virtualTable)), m_svVirtualTableName(tableName) { m_nVirtualFunctionCount = GetVTableLength(); GetAllVTableFunctions(); diff --git a/r5dev/windows/tebpeb64.h b/r5dev/windows/tebpeb64.h new file mode 100644 index 00000000..4a9f8f41 --- /dev/null +++ b/r5dev/windows/tebpeb64.h @@ -0,0 +1,267 @@ +// +// [TEB/PEB UNDER 64-BIT WINDOWS] +// This file represents the 64-bit PEB and associated data structures for 64-bit Windows +// This PEB is allegedly valid between XP thru [at least] Windows 8 +// +// [REFERENCES] +// http://terminus.rewolf.pl/terminus/structures/ntdll/_PEB_x64.html +// http://terminus.rewolf.pl/terminus/structures/ntdll/_TEB64_x86.html +// https://github.com/giampaolo/psutil/commit/babd2b73538fcb6f3931f0ab6d9c100df6f37bcb (RTL_USER_PROCESS_PARAMETERS) +// https://redplait.blogspot.com/2011/09/w8-64bit-teb-peb.html (TEB) +// +// [CHANGELIST] +// 2018-05-02: -now can be compiled alongside windows.h (without changes) or by defining WANT_ALL_WINDOWS_H_DEFINITIONS so this file can be used standalone +// -this file may also be included alongside tebpeb32.h which can be found at http://bytepointer.com/resources/tebpeb32.h +// -64-bit types no longer clash with the 32-bit ones; e.g. UNICODE_STRING64, RTL_USER_PROCESS_PARAMETERS64, PEB64 (same result whether 32 or 64-bit compiler is used) +// -added more QWORD aliases (i.e. HANDLE64 and PTR64) so underlying types are clearer, however most PEB members remain generic QWORD placeholders for now +// -fixed missing semicolon bug in UNICODE_STRING64 +// -added prliminary RTL_USER_PROCESS_PARAMETERS64 and TEB64 with offsets +// -included byte offsets for PEB64 +// +// 2017-08-25: initial public release +// + + +// +// base types +// + +#include "Windows.h" + +typedef struct _PEB_LDR_DATA +{ + ULONG Length; + BOOLEAN Initialized; + HANDLE SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID EntryInProgress; + BOOLEAN ShutdownInProgress; + HANDLE ShutdownThreadId; +} PEB_LDR_DATA, * PPEB_LDR_DATA; + +//always declare 64-bit types +#ifdef _MSC_VER + //Visual C++ + typedef unsigned __int64 QWORD; + typedef __int64 INT64; +#else + //GCC + typedef unsigned long long QWORD; + typedef long long INT64; +#endif +typedef QWORD PTR64; + +//UNCOMMENT line below if you are not including windows.h +//#define WANT_ALL_WINDOWS_H_DEFINITIONS +#ifdef WANT_ALL_WINDOWS_H_DEFINITIONS + +//base types +typedef unsigned char BYTE; +typedef char CHAR; +typedef unsigned short WORD; +typedef short INT16; +typedef unsigned long DWORD; +typedef long INT32; +typedef unsigned __int64 QWORD; +typedef __int64 INT64; +typedef void* HANDLE; +typedef unsigned short WCHAR; + +//base structures +union LARGE_INTEGER +{ + struct + { + DWORD LowPart; + INT32 HighPart; + } u; + INT64 QuadPart; +}; + +union ULARGE_INTEGER +{ + struct + { + DWORD LowPart; + DWORD HighPart; + } u; + QWORD QuadPart; +}; + +#endif //#ifdef WANT_ALL_WINDOWS_H_DEFINITIONS + +struct UNICODE_STRING64 +{ + union + { + struct + { + WORD Length; + WORD MaximumLength; + } u; + QWORD dummyalign; + }; + QWORD Buffer; +}; + +typedef struct _CLIENT_ID64 +{ + QWORD ProcessId; + QWORD ThreadId; +} CLIENT_ID64; + +typedef struct _LDR_DATA_TABLE_ENTRY +{ + LIST_ENTRY InLoadOrderLinks; + LIST_ENTRY InMemoryOrderLinks; + union + { + LIST_ENTRY InInitializationOrderLinks; + LIST_ENTRY InProgressLinks; + }; + PVOID DllBase; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING64 FullDllName; + UNICODE_STRING64 BaseDllName; +} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;// [ PIXIE ]: Narrowed down version, don't need full. + +//NOTE: the members of this structure are not yet complete +typedef struct _RTL_USER_PROCESS_PARAMETERS64 +{ + BYTE Reserved1[16]; //0x00 + QWORD Reserved2[5]; //0x10 + UNICODE_STRING64 CurrentDirectoryPath; //0x38 + QWORD CurrentDirectoryHandle; //0x48 + UNICODE_STRING64 DllPath; //0x50 + UNICODE_STRING64 ImagePathName; //0x60 + UNICODE_STRING64 CommandLine; //0x70 + PTR64 Environment; //0x80 +} RTL_USER_PROCESS_PARAMETERS64; + +// +// PEB64 structure - TODO: comb more through http://terminus.rewolf.pl/terminus/structures/ntdll/_PEB_x64.html and add OS delineations and Windows 10 updates +// +// The structure represented here is a work-in-progress as only members thru offset 0x320 are listed; the actual sizes per OS are: +// 0x0358 XP/WS03 +// 0x0368 Vista +// 0x037C Windows 7 +// 0x0388 Windows 8 +// 0x07A0 Windows 10 +// +struct PEB64 +{ + union + { + struct + { + BYTE InheritedAddressSpace; //0x000 + BYTE ReadImageFileExecOptions; //0x001 + BYTE BeingDebugged; //0x002 + BYTE _SYSTEM_DEPENDENT_01; //0x003 + } flags; + QWORD dummyalign; + } dword0; + QWORD Mutant; //0x0008 + QWORD ImageBaseAddress; //0x0010 + PPEB_LDR_DATA Ldr; //0x0018 + PTR64 ProcessParameters; //0x0020 / pointer to RTL_USER_PROCESS_PARAMETERS64 + QWORD SubSystemData; //0x0028 + QWORD ProcessHeap; //0x0030 + QWORD FastPebLock; //0x0038 + QWORD _SYSTEM_DEPENDENT_02; //0x0040 + QWORD _SYSTEM_DEPENDENT_03; //0x0048 + QWORD _SYSTEM_DEPENDENT_04; //0x0050 + union + { + QWORD KernelCallbackTable; //0x0058 + QWORD UserSharedInfoPtr; //0x0058 + }; + DWORD SystemReserved; //0x0060 + DWORD _SYSTEM_DEPENDENT_05; //0x0064 + QWORD _SYSTEM_DEPENDENT_06; //0x0068 + QWORD TlsExpansionCounter; //0x0070 + QWORD TlsBitmap; //0x0078 + DWORD TlsBitmapBits[2]; //0x0080 + QWORD ReadOnlySharedMemoryBase; //0x0088 + QWORD _SYSTEM_DEPENDENT_07; //0x0090 + QWORD ReadOnlyStaticServerData; //0x0098 + QWORD AnsiCodePageData; //0x00A0 + QWORD OemCodePageData; //0x00A8 + QWORD UnicodeCaseTableData; //0x00B0 + DWORD NumberOfProcessors; //0x00B8 + union + { + DWORD NtGlobalFlag; //0x00BC + DWORD dummy02; //0x00BC + }; + LARGE_INTEGER CriticalSectionTimeout; //0x00C0 + QWORD HeapSegmentReserve; //0x00C8 + QWORD HeapSegmentCommit; //0x00D0 + QWORD HeapDeCommitTotalFreeThreshold; //0x00D8 + QWORD HeapDeCommitFreeBlockThreshold; //0x00E0 + DWORD NumberOfHeaps; //0x00E8 + DWORD MaximumNumberOfHeaps; //0x00EC + QWORD ProcessHeaps; //0x00F0 + QWORD GdiSharedHandleTable; //0x00F8 + QWORD ProcessStarterHelper; //0x0100 + QWORD GdiDCAttributeList; //0x0108 + QWORD LoaderLock; //0x0110 + DWORD OSMajorVersion; //0x0118 + DWORD OSMinorVersion; //0x011C + WORD OSBuildNumber; //0x0120 + WORD OSCSDVersion; //0x0122 + DWORD OSPlatformId; //0x0124 + DWORD ImageSubsystem; //0x0128 + DWORD ImageSubsystemMajorVersion; //0x012C + QWORD ImageSubsystemMinorVersion; //0x0130 + union + { + QWORD ImageProcessAffinityMask; //0x0138 + QWORD ActiveProcessAffinityMask; //0x0138 + }; + QWORD GdiHandleBuffer[30]; //0x0140 + QWORD PostProcessInitRoutine; //0x0230 + QWORD TlsExpansionBitmap; //0x0238 + DWORD TlsExpansionBitmapBits[32]; //0x0240 + QWORD SessionId; //0x02C0 + ULARGE_INTEGER AppCompatFlags; //0x02C8 + ULARGE_INTEGER AppCompatFlagsUser; //0x02D0 + QWORD pShimData; //0x02D8 + QWORD AppCompatInfo; //0x02E0 + UNICODE_STRING64 CSDVersion; //0x02E8 + QWORD ActivationContextData; //0x02F8 + QWORD ProcessAssemblyStorageMap; //0x0300 + QWORD SystemDefaultActivationContextData; //0x0308 + QWORD SystemAssemblyStorageMap; //0x0310 + QWORD MinimumStackCommit; //0x0318 + +}; //struct PEB64 + +// +// TEB64 structure - preliminary structure; the portion listed current at least as of Windows 8 +// +struct TEB64 +{ + BYTE NtTib[56]; //0x0000 / NT_TIB64 structure + PTR64 EnvironmentPointer; //0x0038 + CLIENT_ID64 ClientId; //0x0040 + PTR64 ActiveRpcHandle; //0x0050 + PTR64 ThreadLocalStoragePointer; //0x0058 + PTR64 ProcessEnvironmentBlock; //0x0060 / ptr to PEB64 + DWORD LastErrorValue; //0x0068 + DWORD CountOfOwnedCriticalSections; //0x006C + PTR64 CsrClientThread; //0x0070 + PTR64 Win32ThreadInfo; //0x0078 + DWORD User32Reserved[26]; //0x0080 + DWORD UserReserved[6]; //0x00E8 + PTR64 WOW32Reserved; //0x0100 + DWORD CurrentLocale; //0x0108 + DWORD FpSoftwareStatusRegister; //0x010C + PTR64 SystemReserved1[54]; //0x0110 + DWORD ExceptionCode; //0x02C0 + PTR64 ActivationContextStackPointer; //0x02C8 + +}; //struct TEB64