|
5 | 5 | #include <vector> |
6 | 6 | #include <tlhelp32.h> |
7 | 7 | #include <unordered_map> |
| 8 | +#include <winternl.h> |
8 | 9 | #include <Psapi.h> |
9 | 10 |
|
10 | 11 | struct processSnapshot { |
@@ -68,6 +69,7 @@ namespace mem { |
68 | 69 |
|
69 | 70 | bool getProcessList(); |
70 | 71 | HANDLE openHandle(DWORD pid); |
| 72 | + uintptr_t getPEB(); |
71 | 73 | bool getModuleInfo(DWORD pid, const wchar_t* moduleName, moduleInfo* info); |
72 | 74 | void getModules(); |
73 | 75 | void getSections(const moduleInfo& info, std::vector<moduleSection>& dest); |
@@ -231,26 +233,104 @@ inline void mem::getSections(const moduleInfo& info, std::vector<moduleSection>& |
231 | 233 | } |
232 | 234 | } |
233 | 235 |
|
| 236 | + |
| 237 | + |
| 238 | +typedef NTSTATUS(*_NtQueryInformationProcess)(IN HANDLE ProcessHandle, |
| 239 | + IN PROCESSINFOCLASS ProcessInformationClass, |
| 240 | + OUT PVOID ProcessInformation, |
| 241 | + IN ULONG ProcessInformationLength, |
| 242 | + OUT PULONG ReturnLength OPTIONAL); |
| 243 | + |
| 244 | +inline uintptr_t mem::getPEB() |
| 245 | +{ |
| 246 | + PROCESS_BASIC_INFORMATION processInformation; |
| 247 | + ULONG written = 0; |
| 248 | + |
| 249 | + HMODULE hNtdll = GetModuleHandleA("ntdll.dll"); |
| 250 | + |
| 251 | + static _NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(hNtdll, "NtQueryInformationProcess"); |
| 252 | + |
| 253 | + NTSTATUS result = query(memHandle, ProcessBasicInformation, &processInformation, sizeof(PROCESS_BASIC_INFORMATION), &written); |
| 254 | + |
| 255 | + return reinterpret_cast<uintptr_t>(processInformation.PebBaseAddress); |
| 256 | +} |
| 257 | + |
234 | 258 | inline bool mem::getModuleInfo(DWORD pid, const wchar_t* moduleName, moduleInfo* info) { |
235 | | - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid); |
236 | | - if (snapshot == INVALID_HANDLE_VALUE) { |
| 259 | + |
| 260 | + uintptr_t pebAddress = getPEB(); |
| 261 | + |
| 262 | + if (pebAddress == NULL) |
237 | 263 | return false; |
238 | | - } |
239 | 264 |
|
240 | | - MODULEENTRY32W entry = {}; |
241 | | - entry.dwSize = sizeof(MODULEENTRY32W); |
| 265 | + uintptr_t PEBldrAddress = pebAddress + offsetof(PEB, PEB::Ldr); |
| 266 | + uintptr_t PEBldr = 0; |
| 267 | + read(PEBldrAddress, &PEBldr, sizeof(uintptr_t)); |
242 | 268 |
|
243 | | - if (Module32FirstW(snapshot, &entry)) { |
244 | | - do { |
245 | | - if (wcsstr(moduleName, entry.szModule)) { |
246 | | - info->base = (uintptr_t)entry.modBaseAddr; |
247 | | - info->size = entry.modBaseSize; |
248 | | - return true; |
249 | | - } |
250 | | - } while (Module32NextW(snapshot, &entry)); |
| 269 | + uintptr_t moduleListHead = PEBldr + offsetof(PEB_LDR_DATA, PEB_LDR_DATA::InMemoryOrderModuleList); |
| 270 | + |
| 271 | + uintptr_t currentLink = 0; |
| 272 | + read(moduleListHead, ¤tLink, sizeof(uintptr_t)); |
| 273 | + |
| 274 | + while (currentLink != moduleListHead) |
| 275 | + { |
| 276 | + uintptr_t entryBase = currentLink - offsetof(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); |
| 277 | + |
| 278 | + |
| 279 | + // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm |
| 280 | + UNICODE_STRING dllString; |
| 281 | + // base dll name is directly after full dll name |
| 282 | + uintptr_t linkDllNameAddress = entryBase + offsetof(LDR_DATA_TABLE_ENTRY, LDR_DATA_TABLE_ENTRY::FullDllName) + sizeof(UNICODE_STRING); |
| 283 | + |
| 284 | + // this is going to give an incorrect pointer to the string located inside dllString |
| 285 | + // however the length will be correct, so the length will be used to construct our own string with the contents |
| 286 | + // of the original |
| 287 | + read(linkDllNameAddress, &dllString, sizeof(UNICODE_STRING)); |
| 288 | + |
| 289 | + size_t charCount = (dllString.Length / sizeof(wchar_t)) + 1; |
| 290 | + std::vector<wchar_t> dllName(charCount, L'\0'); |
| 291 | + |
| 292 | + read(reinterpret_cast<uintptr_t>(dllString.Buffer), dllName.data(), dllString.Length); |
| 293 | + |
| 294 | + if (wcscmp(moduleName, dllName.data()) == 0) |
| 295 | + { |
| 296 | + // found it!!! |
| 297 | + |
| 298 | + uintptr_t baseAddress = 0; |
| 299 | + read(entryBase + offsetof(LDR_DATA_TABLE_ENTRY, LDR_DATA_TABLE_ENTRY::DllBase), &baseAddress, sizeof(baseAddress)); |
| 300 | + |
| 301 | + |
| 302 | + ULONG moduleSize = 0; |
| 303 | + // reserved in winternl but SizeOfImage |
| 304 | + read(entryBase + offsetof(LDR_DATA_TABLE_ENTRY, LDR_DATA_TABLE_ENTRY::DllBase) + 0x10, &moduleSize, sizeof(moduleSize)); |
| 305 | + |
| 306 | + |
| 307 | + info->base = baseAddress; |
| 308 | + info->size = moduleSize; |
| 309 | + |
| 310 | + return true; |
| 311 | + } |
| 312 | + read(currentLink, ¤tLink, sizeof(currentLink)); |
251 | 313 | } |
252 | 314 |
|
253 | | - CloseHandle(snapshot); |
| 315 | + //HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid); |
| 316 | + //if (snapshot == INVALID_HANDLE_VALUE) { |
| 317 | + // return false; |
| 318 | + //} |
| 319 | + |
| 320 | + //MODULEENTRY32W entry = {}; |
| 321 | + //entry.dwSize = sizeof(MODULEENTRY32W); |
| 322 | + |
| 323 | + //if (Module32FirstW(snapshot, &entry)) { |
| 324 | + // do { |
| 325 | + // if (wcsstr(moduleName, entry.szModule)) { |
| 326 | + // info->base = (uintptr_t)entry.modBaseAddr; |
| 327 | + // info->size = entry.modBaseSize; |
| 328 | + // return true; |
| 329 | + // } |
| 330 | + // } while (Module32NextW(snapshot, &entry)); |
| 331 | + //} |
| 332 | + |
| 333 | + //CloseHandle(snapshot); |
254 | 334 |
|
255 | 335 | return false; |
256 | 336 | } |
|
0 commit comments