-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathUserModuleBase.cpp
More file actions
121 lines (97 loc) · 4.86 KB
/
UserModuleBase.cpp
File metadata and controls
121 lines (97 loc) · 4.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// ========================================================================
// File: UserModuleBase.cpp
//
// Author: winterknife
//
// Description: This source file contains routine(s) to query the
// image base address of user modules mapped in UVAS without any
// external dependencies including CRT, Win32, or Native API routines
//
// Modifications:
// 2025-09-23 Created
// 2025-09-25 Updated
// ========================================================================
// ========================================================================
// Includes
// ========================================================================
#include "UserModuleBase.h"
#include <algorithm>
// ========================================================================
// Routines
// ========================================================================
#pragma region ROUTINES
_Use_decl_annotations_
PVOID __stdcall get_user_module_base_by_hash(
QWORD qwTargetModuleHash
) {
// Init local variables
PTEB pTeb = nullptr;
PPEB pPeb = nullptr;
PVOID pImageBase = nullptr;
PPEB_LDR_DATA pPebLdrData = nullptr;
PLIST_ENTRY pListHead = nullptr;
PLIST_ENTRY pNextEntry = nullptr;
PLDR_DATA_TABLE_ENTRY pLdrDataTableEntry = nullptr;
PUNICODE_STRING pUnicodeString = nullptr;
CHAR strModuleName[MAX_BASE_DLL_NAME_LEN]; ZERO_MEMORY(strModuleName, sizeof(strModuleName));
DWORD_PTR dwptrModuleNameLength = 0;
DWORD dwIndex = 0;
WCHAR wchLetter = 0;
QWORD qwModuleHash = 0;
// Get the base address of the current thread's Thread Environment Block (TEB)
pTeb = get_current_teb();
if (pTeb == nullptr)
return nullptr;
// Get the base address of the current process's Process Environment Block (PEB)
pPeb = pTeb->ProcessEnvironmentBlock;
if (pPeb == nullptr)
return nullptr;
// Check if the hash of the target module name is 0, if true then return the base address of the calling module
if (qwTargetModuleHash == 0) {
pImageBase = pPeb->Reserved3[1]; // ntdll!_PEB.ImageBaseAddress (0x10)
return pImageBase;
}
// Get the address of the PEB loader data - ntdll!_PEB_LDR_DATA structure (0x18)
// Caution: race condition below since we cannot acquire the loader lock here before walking the loaded module list
pPebLdrData = pPeb->Ldr;
// Get the address of the circular doubly linked list head - ntdll!_LIST_ENTRY structure (0x20)
pListHead = &(pPebLdrData->InMemoryOrderModuleList);
// Get the address of the first entry - ntdll!_LIST_ENTRY structure (0x00)
pNextEntry = pListHead->Flink;
// Loop through all the list entries/loaded modules till we reach the head again
while (pNextEntry != pListHead) {
// Get the address of the current loader module entry - ntdll!_LDR_DATA_TABLE_ENTRY structure (0x10)
pLdrDataTableEntry = CONTAINING_RECORD(pNextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
// Get the address of the Unicode string representing the current module name - ntdll!_UNICODE_STRING structure
pUnicodeString = BIT_CAST(PUNICODE_STRING, &pLdrDataTableEntry->Reserved4); // ntdll!_LDR_DATA_TABLE_ENTRY.BaseDllName (0x58)
// Reset the ANSI string buffer for the current module
ZERO_MEMORY(strModuleName, sizeof(strModuleName));
// Get the length of the Unicode string representing the current module name
dwptrModuleNameLength = std::min(pUnicodeString->Length / sizeof(WCHAR), sizeof(strModuleName));
// Convert the current module name from Unicode string to ANSI string
for (dwIndex = 0; dwIndex < dwptrModuleNameLength; dwIndex++) {
// Extract each wide character letter
wchLetter = *(pUnicodeString->Buffer + dwIndex);
// Convert each wide character letter to lowercase
if (wchLetter != L'_')
wchLetter = wchLetter | 0x20U;
// Check if each wide character letter is a valid US-ASCII character, else replace with "?"
if (wchLetter > 0x7FU)
wchLetter = '?';
// Put each wide character letter into the ANSI string buffer
strModuleName[dwIndex] = STATIC_CAST(CHAR, wchLetter);
}
// Get the 64-bit FNV-1a hash of the current module name
qwModuleHash = HASH_STRING_RUN_TIME(strModuleName, dwptrModuleNameLength);
// Check if the hash of the current module name matches the hash of the target module name
if (qwModuleHash == qwTargetModuleHash) {
// Return the base address of the current module
pImageBase = pLdrDataTableEntry->DllBase;
return pImageBase;
}
// Get the address of the next entry
pNextEntry = pNextEntry->Flink;
}
return nullptr;
}
#pragma endregion