CS2-Kit
C++23 library for CS2 Metamod:Source plugin development
Loading...
Searching...
No Matches
SigScanner.cpp
Go to the documentation of this file.
1#include "Sdk/SigScanner.hpp"
2
3#include <CS2Kit/Utils/Log.hpp>
4#include <sstream>
5#include <vector>
6
7#ifdef _WIN32
8#include <psapi.h>
9#else
10#include <cstring>
11#include <dlfcn.h>
12#include <link.h>
13#endif
14
15namespace CS2Kit::Sdk
16{
17
18using namespace CS2Kit::Utils;
19
21{
22 uint8_t value;
24};
25
26static std::vector<PatternByte> ParsePattern(const std::string& pattern)
27{
28 std::vector<PatternByte> bytes;
29 std::istringstream stream(pattern);
30 std::string token;
31
32 while (stream >> token)
33 {
34 if (token == "?" || token == "??")
35 {
36 bytes.push_back({0, true});
37 }
38 else
39 {
40 bytes.push_back({static_cast<uint8_t>(std::stoul(token, nullptr, 16)), false});
41 }
42 }
43 return bytes;
44}
45
46static void* ScanMemory(const uint8_t* base, size_t size, const std::vector<PatternByte>& pattern)
47{
48 if (pattern.empty() || size < pattern.size())
49 return nullptr;
50
51 size_t scanEnd = size - pattern.size();
52 for (size_t i = 0; i <= scanEnd; ++i)
53 {
54 bool found = true;
55 for (size_t j = 0; j < pattern.size(); ++j)
56 {
57 if (!pattern[j].wildcard && base[i + j] != pattern[j].value)
58 {
59 found = false;
60 break;
61 }
62 }
63 if (found)
64 return const_cast<uint8_t*>(base + i);
65 }
66 return nullptr;
67}
68
69#ifdef _WIN32
70
71static bool GetModuleInfo(const char* moduleName, uint8_t*& base, size_t& size)
72{
73 HANDLE hProcess = GetCurrentProcess();
74 HMODULE hModules[1024];
75 DWORD cbNeeded = 0;
76
77 if (!EnumProcessModules(hProcess, hModules, sizeof(hModules), &cbNeeded))
78 return false;
79
80 DWORD moduleCount = cbNeeded / sizeof(HMODULE);
81 HMODULE bestModule = nullptr;
82 DWORD bestSize = 0;
83
84 for (DWORD i = 0; i < moduleCount; ++i)
85 {
86 char modPath[MAX_PATH];
87 if (!GetModuleFileNameA(hModules[i], modPath, sizeof(modPath)))
88 continue;
89
90 const char* fileName = strrchr(modPath, '\\');
91 if (!fileName)
92 fileName = strrchr(modPath, '/');
93 fileName = fileName ? fileName + 1 : modPath;
94
95 if (_stricmp(fileName, moduleName) != 0)
96 continue;
97
98 MODULEINFO modInfo{};
99 if (GetModuleInformation(hProcess, hModules[i], &modInfo, sizeof(modInfo)))
100 {
101 if (modInfo.SizeOfImage > bestSize)
102 {
103 bestModule = hModules[i];
104 bestSize = modInfo.SizeOfImage;
105 }
106 }
107 }
108
109 if (!bestModule)
110 return false;
111
112 MODULEINFO modInfo{};
113 if (!GetModuleInformation(hProcess, bestModule, &modInfo, sizeof(modInfo)))
114 return false;
115
116 base = static_cast<uint8_t*>(modInfo.lpBaseOfDll);
117 size = modInfo.SizeOfImage;
118 return true;
119}
120
121#else
122
124{
125 const char* name;
126 uint8_t* base;
127 size_t size;
128 bool found;
129};
130
131static int DlIterateCallback(struct dl_phdr_info* info, size_t /*size*/, void* data)
132{
133 auto* mod = static_cast<ModuleInfo*>(data);
134 if (info->dlpi_name && strstr(info->dlpi_name, mod->name))
135 {
136 mod->base = reinterpret_cast<uint8_t*>(info->dlpi_addr);
137 size_t maxAddr = 0;
138 for (int i = 0; i < info->dlpi_phnum; ++i)
139 {
140 if (info->dlpi_phdr[i].p_type == PT_LOAD)
141 {
142 size_t segEnd = info->dlpi_phdr[i].p_vaddr + info->dlpi_phdr[i].p_memsz;
143 if (segEnd > maxAddr)
144 maxAddr = segEnd;
145 }
146 }
147 mod->size = maxAddr;
148 mod->found = true;
149 return 1;
150 }
151 return 0;
152}
153
154static bool GetModuleInfo(const char* moduleName, uint8_t*& base, size_t& size)
155{
156 ModuleInfo mod{moduleName, nullptr, 0, false};
157 dl_iterate_phdr(DlIterateCallback, &mod);
158 if (mod.found)
159 {
160 base = mod.base;
161 size = mod.size;
162 }
163 return mod.found;
164}
165
166#endif
167
168void* FindPattern(const char* moduleName, const std::string& pattern)
169{
170 std::string fullName;
171#ifdef _WIN32
172 fullName = std::string(moduleName) + ".dll";
173#else
174 fullName = std::string("lib") + moduleName + ".so";
175#endif
176
177 uint8_t* base = nullptr;
178 size_t size = 0;
179 if (!GetModuleInfo(fullName.c_str(), base, size))
180 {
181 Log::Error("SigScanner: Module '{}' not found.", fullName);
182 return nullptr;
183 }
184
185 Log::Info("SigScanner: Scanning '{}' (base={:#x}, size=0x{:X})...", fullName, reinterpret_cast<uintptr_t>(base),
186 size);
187
188 auto patternBytes = ParsePattern(pattern);
189 void* result = ScanMemory(base, size, patternBytes);
190 if (!result)
191 {
192 Log::Warn("SigScanner: Pattern not found in '{}'.", fullName);
193 }
194 else
195 {
196 Log::Info("SigScanner: Found match at {:#x}.", reinterpret_cast<uintptr_t>(result));
197 }
198 return result;
199}
200
201uintptr_t ResolveRelativeAddress(uintptr_t addr, int ripOffset, int ripSize)
202{
203 if (addr == 0)
204 return 0;
205
206 int32_t relative = *reinterpret_cast<int32_t*>(addr + ripOffset);
207 return addr + ripSize + relative;
208}
209
210} // namespace CS2Kit::Sdk
static bool GetModuleInfo(const char *moduleName, uint8_t *&base, size_t &size)
void * FindPattern(const char *moduleName, const std::string &pattern)
static int DlIterateCallback(struct dl_phdr_info *info, size_t, void *data)
static std::vector< PatternByte > ParsePattern(const std::string &pattern)
static void * ScanMemory(const uint8_t *base, size_t size, const std::vector< PatternByte > &pattern)
uintptr_t ResolveRelativeAddress(uintptr_t addr, int ripOffset, int ripSize)