|
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,135 @@ 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 | + |
| 258 | +//size_t GetModuleSize(uintptr_t targetModuleBase) { |
| 259 | +// uintptr_t pebAddr = Peb(); |
| 260 | +// |
| 261 | +// uintptr_t ldrAddr = 0; |
| 262 | +// Read(pebAddr + 0x18, &ldrAddr, sizeof(ldrAddr)); |
| 263 | +// |
| 264 | +// uintptr_t moduleListHead = ldrAddr + 0x20; |
| 265 | +// |
| 266 | +// uintptr_t currentLink = 0; |
| 267 | +// Read(moduleListHead, ¤tLink, sizeof(currentLink)); |
| 268 | +// |
| 269 | +// while (currentLink != moduleListHead) { |
| 270 | +// uintptr_t entryAddr = currentLink - 0x10; |
| 271 | +// |
| 272 | +// uintptr_t dllBase = 0; |
| 273 | +// Read(entryAddr + 0x30, &dllBase, sizeof(dllBase)); |
| 274 | +// |
| 275 | +// if (dllBase == targetModuleBase) { |
| 276 | +// |
| 277 | +// size_t sizeOfImage = 0; |
| 278 | +// Read(entryAddr + 0x40, &sizeOfImage, sizeof(sizeOfImage)); |
| 279 | +// |
| 280 | +// return sizeOfImage; |
| 281 | +// } |
| 282 | +// |
| 283 | +// Read(currentLink, ¤tLink, sizeof(currentLink)); |
| 284 | +// } |
| 285 | +// |
| 286 | +// return 0; |
| 287 | +//} |
| 288 | + |
234 | 289 | 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) { |
| 290 | + |
| 291 | + uintptr_t pebAddress = getPEB(); |
| 292 | + |
| 293 | + if (pebAddress == NULL) |
237 | 294 | return false; |
238 | | - } |
239 | 295 |
|
240 | | - MODULEENTRY32W entry = {}; |
241 | | - entry.dwSize = sizeof(MODULEENTRY32W); |
| 296 | + uintptr_t PEBldrAddress = pebAddress + offsetof(PEB, PEB::Ldr); |
| 297 | + uintptr_t PEBldr = 0; |
| 298 | + read(PEBldrAddress, &PEBldr, sizeof(uintptr_t)); |
242 | 299 |
|
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)); |
| 300 | + uintptr_t moduleListHead = PEBldr + offsetof(PEB_LDR_DATA, PEB_LDR_DATA::InMemoryOrderModuleList); |
| 301 | + |
| 302 | + uintptr_t currentLink = 0; |
| 303 | + read(moduleListHead, ¤tLink, sizeof(uintptr_t)); |
| 304 | + |
| 305 | + while (currentLink != moduleListHead) |
| 306 | + { |
| 307 | + uintptr_t entryBase = currentLink - offsetof(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); |
| 308 | + |
| 309 | + |
| 310 | + // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm |
| 311 | + UNICODE_STRING dllString; |
| 312 | + // base dll name is directly after full dll name |
| 313 | + uintptr_t linkDllNameAddress = entryBase + offsetof(LDR_DATA_TABLE_ENTRY, LDR_DATA_TABLE_ENTRY::FullDllName) + sizeof(UNICODE_STRING); |
| 314 | + |
| 315 | + // this is going to give an incorrect pointer to the string located inside dllString |
| 316 | + // however the length will be correct, so the length will be used to construct our own string with the contents |
| 317 | + // of the original |
| 318 | + read(linkDllNameAddress, &dllString, sizeof(UNICODE_STRING)); |
| 319 | + |
| 320 | + size_t charCount = (dllString.Length / sizeof(wchar_t)) + 1; |
| 321 | + std::vector<wchar_t> dllName(charCount, L'\0'); |
| 322 | + |
| 323 | + read(reinterpret_cast<uintptr_t>(dllString.Buffer), dllName.data(), dllString.Length); |
| 324 | + |
| 325 | + if (wcscmp(moduleName, dllName.data()) == 0) |
| 326 | + { |
| 327 | + // found it!!! |
| 328 | + |
| 329 | + uintptr_t baseAddress = 0; |
| 330 | + read(entryBase + offsetof(LDR_DATA_TABLE_ENTRY, LDR_DATA_TABLE_ENTRY::DllBase), &baseAddress, sizeof(baseAddress)); |
| 331 | + |
| 332 | + |
| 333 | + ULONG moduleSize = 0; |
| 334 | + // reserved in winternl but SizeOfImage |
| 335 | + read(entryBase + offsetof(LDR_DATA_TABLE_ENTRY, LDR_DATA_TABLE_ENTRY::DllBase) + 0x10, &moduleSize, sizeof(moduleSize)); |
| 336 | + |
| 337 | + |
| 338 | + info->base = baseAddress; |
| 339 | + info->size = moduleSize; |
| 340 | + |
| 341 | + return true; |
| 342 | + } |
| 343 | + read(currentLink, ¤tLink, sizeof(currentLink)); |
251 | 344 | } |
252 | 345 |
|
253 | | - CloseHandle(snapshot); |
| 346 | + //HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid); |
| 347 | + //if (snapshot == INVALID_HANDLE_VALUE) { |
| 348 | + // return false; |
| 349 | + //} |
| 350 | + |
| 351 | + //MODULEENTRY32W entry = {}; |
| 352 | + //entry.dwSize = sizeof(MODULEENTRY32W); |
| 353 | + |
| 354 | + //if (Module32FirstW(snapshot, &entry)) { |
| 355 | + // do { |
| 356 | + // if (wcsstr(moduleName, entry.szModule)) { |
| 357 | + // info->base = (uintptr_t)entry.modBaseAddr; |
| 358 | + // info->size = entry.modBaseSize; |
| 359 | + // return true; |
| 360 | + // } |
| 361 | + // } while (Module32NextW(snapshot, &entry)); |
| 362 | + //} |
| 363 | + |
| 364 | + //CloseHandle(snapshot); |
254 | 365 |
|
255 | 366 | return false; |
256 | 367 | } |
|
0 commit comments