#pragma once #include "pch.h" #define IS_WINDOWS 1 class InterfaceReg; // Pointer arithmetic utility class. struct UTILPtr { public: template UTILPtr(T val) { m_val = (uintptr_t)(val); } template T Get(const char* variableName = nullptr) { #ifdef CS2_SDK_ENABLE_LOGGING if (variableName) LOG("%s found at -> %llX\n", variableName, m_val); #endif return (T)(m_val); } template void Get(T& dst, const char* variableName = nullptr) { dst = Get(variableName); } UTILPtr& AddOffset(int offset) { if (m_val) m_val += offset; return *this; } UTILPtr& ToAbsolute(int preOffset, int postOffset) { if (m_val) { AddOffset(preOffset); m_val = m_val + sizeof(int) + *(int*)(m_val); AddOffset(postOffset); } return *this; } UTILPtr& Dereference(int dereferences) { if (m_val) while (dereferences-- != 0) m_val = *(uintptr_t*)(m_val); return *this; } bool IsValid() { return m_val != 0; } private: uintptr_t m_val; }; class CModule { public: // CS2TODO: Maybe write a simple caching system CModule(CModule&&) = delete; CModule(const CModule&) = delete; explicit CModule(const char* name) : m_name(name) { this->Load(); } void Load() { this->InitializeHandle(); this->InitializeBounds(); } UTILPtr GetProcAddress(const char* procName) const { UTILPtr rv = 0; if (this->IsLoaded()) { #ifdef IS_WINDOWS rv = ::GetProcAddress(static_cast(this->m_handle), procName); #endif } return rv; } UTILPtr FindInterface(const char* version) const { UTILPtr rv = 0; if (this->IsLoaded()) { UTILPtr pCreateInterface = this->GetProcAddress("CreateInterface"); if (!pCreateInterface.IsValid()) return rv; InterfaceReg* s_pInterfaceRegs = pCreateInterface.ToAbsolute(3, 0) .Dereference(1) .Get(); for (; s_pInterfaceRegs; s_pInterfaceRegs = s_pInterfaceRegs->m_pNext) { if (strcmp(version, s_pInterfaceRegs->m_pName) == 0) { rv = s_pInterfaceRegs->m_CreateFn(); break; } } } return rv; } template UTILPtr FindPattern(const std::array& signature) const { UTILPtr rv = 0; if (this->IsLoaded()) { const int* pSigData = signature.data(); uint8_t* pBytes = reinterpret_cast(this->m_start); for (size_t i = 0; i < this->m_end - N; ++i) { bool found = true; for (size_t j = 0; j < N; ++j) { if (pBytes[i + j] != pSigData[j] && pSigData[j] != -1) { found = false; break; } } if (found) { rv = reinterpret_cast(&pBytes[i]); break; } } } return rv; } const char* GetName() const { return this->m_name; } bool IsLoaded() const { return this->m_handle != 0; } void* GetBase() const { return this->m_handle; } private: void InitializeHandle() { #ifdef IS_WINDOWS this->m_handle = static_cast(GetModuleHandleA(this->GetName())); #endif } void InitializeBounds() { if (!this->IsLoaded()) return; #ifdef IS_WINDOWS MODULEINFO mi; BOOL status = GetModuleInformation(GetCurrentProcess(), static_cast(this->m_handle), &mi, sizeof(mi)); if (status != 0) { this->m_start = reinterpret_cast(this->m_handle); this->m_end = static_cast(mi.SizeOfImage); } #endif } void* m_handle = nullptr; uintptr_t m_start = 0, m_end = 0; const char* m_name = ""; };