From a2aeb3524e54db476b2636c1ec99e74da2388792 Mon Sep 17 00:00:00 2001 From: SlynxCZ Date: Tue, 21 Oct 2025 15:22:03 +0200 Subject: [PATCH 1/3] Fix: Give entrypoint pointer instead of RTII --- managed/CounterStrikeSharp.API/Core/API.cs | 2 +- src/core/memory.cpp | 127 ++++++++++++++++++++- 2 files changed, 123 insertions(+), 6 deletions(-) diff --git a/managed/CounterStrikeSharp.API/Core/API.cs b/managed/CounterStrikeSharp.API/Core/API.cs index 8d28d2a28..b65a4f675 100644 --- a/managed/CounterStrikeSharp.API/Core/API.cs +++ b/managed/CounterStrikeSharp.API/Core/API.cs @@ -1464,7 +1464,7 @@ public static IntPtr FindVirtualTable(string modulepath, string vtablename){ ScriptContext.GlobalScriptContext.Reset(); ScriptContext.GlobalScriptContext.Push(modulepath); ScriptContext.GlobalScriptContext.Push(vtablename); - ScriptContext.GlobalScriptContext.SetIdentifier(0xB4A0F13C); + ScriptContext.GlobalScriptContext.SetIdentifier(0xEA506CFF); ScriptContext.GlobalScriptContext.Invoke(); ScriptContext.GlobalScriptContext.CheckErrors(); return (IntPtr)ScriptContext.GlobalScriptContext.GetResult(typeof(IntPtr)); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index bb18fc3ba..502d5d1a9 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -20,11 +20,14 @@ */ #include "gameconfig.h" +#include "log.h" #include "memory_module.h" +using namespace counterstrikesharp::modules; + void* FindSignature(const char* moduleName, const char* bytesStr) { - auto module = counterstrikesharp::modules::GetModuleByName(moduleName); + auto module = GetModuleByName(moduleName); if (module == nullptr) { return nullptr; @@ -33,13 +36,127 @@ void* FindSignature(const char* moduleName, const char* bytesStr) return module->FindSignature(bytesStr); } -void* FindVirtualTable(const char* moduleName, const char* vtableName) +#ifdef _WIN32 +void* GetVirtualTable(CModule* module, const std::string& name) { - auto module = counterstrikesharp::modules::GetModuleByName(moduleName); - if (module == nullptr) + auto runTimeData = module->GetSection(".data"); + auto readOnlyData = module->GetSection(".rdata"); + + if (!runTimeData || !readOnlyData) + { + CSSHARP_CORE_ERROR("Failed to find .data or .rdata section"); + return nullptr; + } + + // Windows RTTI format: .?AVClassName@@ + std::string decoratedTableName = ".?AV" + name + "@@"; + + SignatureIterator sigIt(runTimeData->m_pBase, runTimeData->m_iSize, (const byte*)decoratedTableName.c_str(), + decoratedTableName.size() + 1); + + void* typeDescriptor = sigIt.FindNext(false); + if (!typeDescriptor) + { + CSSHARP_CORE_ERROR("Failed to find type descriptor for {}", name); + return nullptr; + } + + typeDescriptor = (void*)((uintptr_t)typeDescriptor - 0x10); + const uint32_t rttiTDRva = (uintptr_t)typeDescriptor - (uintptr_t)module->m_base; + + SignatureIterator sigIt2(readOnlyData->m_pBase, readOnlyData->m_iSize, (const byte*)&rttiTDRva, sizeof(uint32_t)); + + while (void* completeObjectLocator = sigIt2.FindNext(false)) + { + auto completeObjectLocatorHeader = (uintptr_t)completeObjectLocator - 0xC; + + // Verify RTTI Complete Object Locator header (always 0x1) + if (*(int32_t*)(completeObjectLocatorHeader) != 1) continue; + + // Verify RTTI vtable offset (always 0) + if (*(int32_t*)((uintptr_t)completeObjectLocator - 0x8) != 0) continue; + + // Find reference to Complete Object Locator inside .rdata + SignatureIterator sigIt3(readOnlyData->m_pBase, readOnlyData->m_iSize, (const byte*)&completeObjectLocatorHeader, sizeof(void*)); + + void* vtable = sigIt3.FindNext(false); + if (!vtable) + { + CSSHARP_CORE_ERROR("Failed to find vtable for {}", name + ); + return nullptr; + } + + // Return pointer after Complete Object Locator + // (vtable + 0x8) → start of first virtual function + return (void*)((uintptr_t)vtable + 0x8); + } + + CSSHARP_CORE_ERROR("Failed to find RTTI Complete Object Locator for {}", name); + return nullptr; +} +#else +void* GetVirtualTable(CModule* module, const std::string& name) +{ + auto readOnlyData = module->GetSection(".rodata"); + auto readOnlyRelocations = module->GetSection(".data.rel.ro"); + + if (!readOnlyData || !readOnlyRelocations) + { + CSSHARP_CORE_ERROR("Failed to find .rodata or .data.rel.ro section"); + return nullptr; + } + + // Linux RTTI format: "17CNavPhysicsInterface" etc. + std::string decoratedTableName = std::to_string(name.length()) + name; + + SignatureIterator sigIt(readOnlyData->m_pBase, readOnlyData->m_iSize, (const byte*)decoratedTableName.c_str(), + decoratedTableName.size() + 1); + void* classNameString = sigIt.FindNext(false); + if (!classNameString) { + CSSHARP_CORE_ERROR("Failed to find type descriptor for {}", name); return nullptr; } - return module->FindVirtualTable(vtableName); + // Find relocation referencing classNameString + SignatureIterator sigIt2(readOnlyRelocations->m_pBase, readOnlyRelocations->m_iSize, (const byte*)&classNameString, sizeof(void*)); + void* typeName = sigIt2.FindNext(false); + if (!typeName) + { + CSSHARP_CORE_ERROR("Failed to find type name for {}", name); + return nullptr; + } + + void* typeInfo = (void*)((uintptr_t)typeName - 0x8); + + // Check both local/global relocation tables + for (const auto& sectionName : { std::string_view(".data.rel.ro"), std::string_view(".data.rel.ro.local") }) + { + auto section = module->GetSection(sectionName); + if (!section) continue; + + SignatureIterator sigIt3(section->m_pBase, section->m_iSize, (const byte*)&typeInfo, sizeof(void*)); + + while (void* vtable = sigIt3.FindNext(false)) + { + // Verify offset-to-top == 0 + if (*(int64_t*)((uintptr_t)vtable - 0x8) == 0) + { + // Return start of actual virtual method table + // (vtable + 0x10) = skip RTTI + offset-to-top + return (void*)((uintptr_t)vtable + 0x10); + } + } + } + + CSSHARP_CORE_ERROR("Failed to find vtable for {}", name); + return nullptr; +} +#endif + +void* FindVirtualTable(const char* moduleName, const char* vtableName) +{ + CModule* module = GetModuleByName(moduleName); + return module ? GetVirtualTable(module, vtableName) : nullptr; } From b782234636c3d855d9e6bc176085e9db4dda23a4 Mon Sep 17 00:00:00 2001 From: SlynxCZ Date: Tue, 21 Oct 2025 15:24:08 +0200 Subject: [PATCH 2/3] Chore: Clang Format --- src/core/memory.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 502d5d1a9..a2bfa0bf7 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -82,8 +82,7 @@ void* GetVirtualTable(CModule* module, const std::string& name) void* vtable = sigIt3.FindNext(false); if (!vtable) { - CSSHARP_CORE_ERROR("Failed to find vtable for {}", name - ); + CSSHARP_CORE_ERROR("Failed to find vtable for {}", name); return nullptr; } From 3859dffb8ead6f1f0ae946c7d6497a3e6feedf6f Mon Sep 17 00:00:00 2001 From: SlynxCZ Date: Thu, 23 Oct 2025 20:31:25 +0200 Subject: [PATCH 3/3] Fix: Remove useless GetVirtualTable helpers --- src/core/memory.cpp | 121 ++------------------------------------------ 1 file changed, 4 insertions(+), 117 deletions(-) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index a2bfa0bf7..7e1ffa2b5 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -36,126 +36,13 @@ void* FindSignature(const char* moduleName, const char* bytesStr) return module->FindSignature(bytesStr); } -#ifdef _WIN32 -void* GetVirtualTable(CModule* module, const std::string& name) -{ - auto runTimeData = module->GetSection(".data"); - auto readOnlyData = module->GetSection(".rdata"); - - if (!runTimeData || !readOnlyData) - { - CSSHARP_CORE_ERROR("Failed to find .data or .rdata section"); - return nullptr; - } - - // Windows RTTI format: .?AVClassName@@ - std::string decoratedTableName = ".?AV" + name + "@@"; - - SignatureIterator sigIt(runTimeData->m_pBase, runTimeData->m_iSize, (const byte*)decoratedTableName.c_str(), - decoratedTableName.size() + 1); - - void* typeDescriptor = sigIt.FindNext(false); - if (!typeDescriptor) - { - CSSHARP_CORE_ERROR("Failed to find type descriptor for {}", name); - return nullptr; - } - - typeDescriptor = (void*)((uintptr_t)typeDescriptor - 0x10); - const uint32_t rttiTDRva = (uintptr_t)typeDescriptor - (uintptr_t)module->m_base; - - SignatureIterator sigIt2(readOnlyData->m_pBase, readOnlyData->m_iSize, (const byte*)&rttiTDRva, sizeof(uint32_t)); - - while (void* completeObjectLocator = sigIt2.FindNext(false)) - { - auto completeObjectLocatorHeader = (uintptr_t)completeObjectLocator - 0xC; - - // Verify RTTI Complete Object Locator header (always 0x1) - if (*(int32_t*)(completeObjectLocatorHeader) != 1) continue; - - // Verify RTTI vtable offset (always 0) - if (*(int32_t*)((uintptr_t)completeObjectLocator - 0x8) != 0) continue; - - // Find reference to Complete Object Locator inside .rdata - SignatureIterator sigIt3(readOnlyData->m_pBase, readOnlyData->m_iSize, (const byte*)&completeObjectLocatorHeader, sizeof(void*)); - - void* vtable = sigIt3.FindNext(false); - if (!vtable) - { - CSSHARP_CORE_ERROR("Failed to find vtable for {}", name); - return nullptr; - } - - // Return pointer after Complete Object Locator - // (vtable + 0x8) → start of first virtual function - return (void*)((uintptr_t)vtable + 0x8); - } - - CSSHARP_CORE_ERROR("Failed to find RTTI Complete Object Locator for {}", name); - return nullptr; -} -#else -void* GetVirtualTable(CModule* module, const std::string& name) +void* FindVirtualTable(const char* moduleName, const char* vtableName) { - auto readOnlyData = module->GetSection(".rodata"); - auto readOnlyRelocations = module->GetSection(".data.rel.ro"); - - if (!readOnlyData || !readOnlyRelocations) - { - CSSHARP_CORE_ERROR("Failed to find .rodata or .data.rel.ro section"); - return nullptr; - } - - // Linux RTTI format: "17CNavPhysicsInterface" etc. - std::string decoratedTableName = std::to_string(name.length()) + name; - - SignatureIterator sigIt(readOnlyData->m_pBase, readOnlyData->m_iSize, (const byte*)decoratedTableName.c_str(), - decoratedTableName.size() + 1); - void* classNameString = sigIt.FindNext(false); - if (!classNameString) - { - CSSHARP_CORE_ERROR("Failed to find type descriptor for {}", name); - return nullptr; - } - - // Find relocation referencing classNameString - SignatureIterator sigIt2(readOnlyRelocations->m_pBase, readOnlyRelocations->m_iSize, (const byte*)&classNameString, sizeof(void*)); - void* typeName = sigIt2.FindNext(false); - if (!typeName) + auto module = GetModuleByName(moduleName); + if (module == nullptr) { - CSSHARP_CORE_ERROR("Failed to find type name for {}", name); return nullptr; } - void* typeInfo = (void*)((uintptr_t)typeName - 0x8); - - // Check both local/global relocation tables - for (const auto& sectionName : { std::string_view(".data.rel.ro"), std::string_view(".data.rel.ro.local") }) - { - auto section = module->GetSection(sectionName); - if (!section) continue; - - SignatureIterator sigIt3(section->m_pBase, section->m_iSize, (const byte*)&typeInfo, sizeof(void*)); - - while (void* vtable = sigIt3.FindNext(false)) - { - // Verify offset-to-top == 0 - if (*(int64_t*)((uintptr_t)vtable - 0x8) == 0) - { - // Return start of actual virtual method table - // (vtable + 0x10) = skip RTTI + offset-to-top - return (void*)((uintptr_t)vtable + 0x10); - } - } - } - - CSSHARP_CORE_ERROR("Failed to find vtable for {}", name); - return nullptr; -} -#endif - -void* FindVirtualTable(const char* moduleName, const char* vtableName) -{ - CModule* module = GetModuleByName(moduleName); - return module ? GetVirtualTable(module, vtableName) : nullptr; + return module->FindVirtualTable(vtableName); }