#pragma once #include "head.h" #define IS_WINDOWS 1 class InterfaceReg; //cancer fix me plz namespace global { extern bool isMetaModInit; }; // 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()) { rv = ::GetProcAddress(static_cast(this->m_handle), procName); } return rv; } UTILPtr FindInterface(const char* version) const { UTILPtr rv = 0; if (this->IsLoaded()) { UTILPtr pCreateInterface = this->GetProcAddress("CreateInterface"); if (!pCreateInterface.IsValid()) return rv; auto 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() { if (global::isMetaModInit == false) { this->m_handle = static_cast(GetModuleHandleA(this->GetName())); return; } HANDLE hProcess = GetCurrentProcess(); DWORD cbNeeded; // Call EnumProcessModules with a null hMods parameter to get the needed size. EnumProcessModules(hProcess, nullptr, 0, &cbNeeded); int moduleCount = cbNeeded / sizeof(HMODULE); std::vector hMods(moduleCount); if (EnumProcessModules(hProcess, hMods.data(), cbNeeded, &cbNeeded)) { for (const auto& hMod : hMods) { char szModName[MAX_PATH]; if (GetModuleFileNameExA(hProcess, hMod, szModName, sizeof(szModName) / sizeof(char))) { const auto fullModulePath = std::string(szModName); if (fullModulePath.find("metamod") == std::string::npos && fullModulePath.ends_with(this->GetName()) == true) { this->m_handle = static_cast(hMod); break; } } } } CloseHandle(hProcess); } 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 = ""; };