Skip to content

Commit d6f0715

Browse files
committed
update
1 parent 0c4f334 commit d6f0715

20 files changed

Lines changed: 550 additions & 383 deletions

MemoryModule/BaseAddressIndex.cpp

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,7 @@
11
#include "stdafx.h"
22

3-
PRTL_RB_TREE NTAPI RtlFindLdrpModuleBaseAddressIndex() {
4-
static PRTL_RB_TREE LdrpModuleBaseAddressIndex = nullptr;
5-
if (LdrpModuleBaseAddressIndex)return LdrpModuleBaseAddressIndex;
6-
7-
PLDR_DATA_TABLE_ENTRY_WIN10 nt10 = decltype(nt10)(RtlFindNtdllLdrEntry());
8-
PRTL_BALANCED_NODE node = nullptr;
9-
if (!nt10 || !RtlIsWindowsVersionOrGreater(6, 2, 0))return nullptr;
10-
node = &nt10->BaseAddressIndexNode;
11-
while (node->ParentValue & (~7)) node = decltype(node)(node->ParentValue & (~7));
12-
13-
if (!node->Red) {
14-
BYTE count = 0;
15-
PRTL_RB_TREE tmp = nullptr;
16-
SEARCH_CONTEXT SearchContext{};
17-
SearchContext.MemoryBuffer = &node;
18-
SearchContext.BufferLength = sizeof(size_t);
19-
while (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection((HMODULE)nt10->DllBase, ".data", &SearchContext))) {
20-
if (count++)return nullptr;
21-
tmp = (decltype(tmp))SearchContext.MemoryBlockInSection;
22-
}
23-
if (count && tmp && tmp->Root && tmp->Min) {
24-
LdrpModuleBaseAddressIndex = tmp;
25-
}
26-
}
27-
28-
return LdrpModuleBaseAddressIndex;
29-
}
30-
313
NTSTATUS NTAPI RtlInsertModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTRY DataTableEntry, IN PVOID BaseAddress) {
32-
static auto LdrpModuleBaseAddressIndex = RtlFindLdrpModuleBaseAddressIndex();
4+
auto LdrpModuleBaseAddressIndex = MmpGlobalDataPtr->LdrpModuleBaseAddressIndex;
335
if (!LdrpModuleBaseAddressIndex)return STATUS_UNSUCCESSFUL;
346

357
PLDR_DATA_TABLE_ENTRY_WIN8 LdrNode = decltype(LdrNode)((size_t)LdrpModuleBaseAddressIndex - offsetof(LDR_DATA_TABLE_ENTRY_WIN8, BaseAddressIndexNode));
@@ -61,7 +33,7 @@ NTSTATUS NTAPI RtlInsertModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTRY Data
6133
}
6234

6335
NTSTATUS NTAPI RtlRemoveModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTRY DataTableEntry) {
64-
static auto tree{ RtlFindLdrpModuleBaseAddressIndex() };
36+
static auto tree{ MmpGlobalDataPtr->LdrpModuleBaseAddressIndex };
6537
if (!tree->Root)return STATUS_UNSUCCESSFUL;
6638
RtlRbRemoveNode(tree, &PLDR_DATA_TABLE_ENTRY_WIN8(DataTableEntry)->BaseAddressIndexNode);
6739
return STATUS_SUCCESS;

MemoryModule/BaseAddressIndex.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#pragma once
22

3-
PRTL_RB_TREE NTAPI RtlFindLdrpModuleBaseAddressIndex();
4-
53
NTSTATUS NTAPI RtlInsertModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTRY DataTableEntry, IN PVOID BaseAddress);
64

75
NTSTATUS NTAPI RtlRemoveModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTRY DataTableEntry);

MemoryModule/Initialize.cpp

Lines changed: 237 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,191 @@
11
#include "stdafx.h"
22
#include <wchar.h>
33

4+
PMMP_GLOBAL_DATA MmpGlobalDataPtr;
5+
6+
#ifdef _WIN64
7+
#define FindLdrpInvertedFunctionTable FindLdrpInvertedFunctionTable64
8+
#else
9+
#define FindLdrpInvertedFunctionTable FindLdrpInvertedFunctionTable32
10+
#endif
11+
412
BOOLEAN MmpBuildSectionName(_Out_ PUNICODE_STRING SectionName) {
513
WCHAR buffer[128];
614

715
wsprintfW(buffer, L"\\Sessions\\%d\\BaseNamedObjects\\MMPP%d", NtCurrentPeb()->SessionId, (unsigned int)NtCurrentProcessId());
816
return RtlCreateUnicodeString(SectionName, buffer);
917
}
1018

11-
VOID InitializeLockHeld() {
12-
NTSTATUS status;
13-
HANDLE hSection;
19+
PRTL_RB_TREE FindLdrpModuleBaseAddressIndex() {
20+
PRTL_RB_TREE LdrpModuleBaseAddressIndex = nullptr;
21+
PLDR_DATA_TABLE_ENTRY_WIN10 nt10 = decltype(nt10)(MmpGlobalDataPtr->LdrpNtdllBase);
22+
PRTL_BALANCED_NODE node = nullptr;
23+
if (!nt10 || !RtlIsWindowsVersionOrGreater(6, 2, 0))return nullptr;
24+
node = &nt10->BaseAddressIndexNode;
25+
while (node->ParentValue & (~7)) node = decltype(node)(node->ParentValue & (~7));
26+
27+
if (!node->Red) {
28+
BYTE count = 0;
29+
PRTL_RB_TREE tmp = nullptr;
30+
SEARCH_CONTEXT SearchContext{};
31+
SearchContext.MemoryBuffer = &node;
32+
SearchContext.BufferLength = sizeof(size_t);
33+
while (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection((HMODULE)nt10->DllBase, ".data", &SearchContext))) {
34+
if (count++)return nullptr;
35+
tmp = (decltype(tmp))SearchContext.MemoryBlockInSection;
36+
}
37+
if (count && tmp && tmp->Root && tmp->Min) {
38+
LdrpModuleBaseAddressIndex = tmp;
39+
}
40+
}
41+
42+
return LdrpModuleBaseAddressIndex;
43+
}
44+
45+
static __forceinline bool IsModuleUnloaded(PLDR_DATA_TABLE_ENTRY entry) {
46+
if (RtlIsWindowsVersionOrGreater(6, 2, 0)) {
47+
return PLDR_DATA_TABLE_ENTRY_WIN8(entry)->DdagNode->State == LdrModulesUnloaded;
48+
}
49+
else {
50+
return entry->DllBase == nullptr;
51+
}
52+
}
53+
54+
PVOID FindLdrpInvertedFunctionTable32() {
55+
// _RTL_INVERTED_FUNCTION_TABLE x86
56+
// Count +0x0 ????????
57+
// MaxCount +0x4 0x00000200
58+
// Overflow +0x8 0x00000000(Win7) ????????(Win10)
59+
// NextEntrySEHandlerTableEncoded +0xc 0x00000000(Win10) ++++++++(Win7)
60+
// _RTL_INVERTED_FUNCTION_TABLE_ENTRY[0] +0x10 ntdll.dll(win10) or The smallest base module
61+
// ImageBase +0x10 ++++++++
62+
// ImageSize +0x14 ++++++++
63+
// SEHandlerCount +0x18 ++++++++
64+
// NextEntrySEHandlerTableEncoded +0x1c ++++++++(Win10) ????????(Win7)
65+
// _RTL_INVERTED_FUNCTION_TABLE_ENTRY[1] ... ...
66+
// ......
67+
HMODULE hModule = nullptr, hNtdll = GetModuleHandleW(L"ntdll.dll");
68+
PIMAGE_NT_HEADERS NtdllHeaders = RtlImageNtHeader(hNtdll), ModuleHeaders = nullptr;
69+
_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 entry{};
70+
LPCSTR lpSectionName = ".data";
71+
SEARCH_CONTEXT SearchContext{ SearchContext.MemoryBuffer = &entry,SearchContext.BufferLength = sizeof(entry) };
72+
PLIST_ENTRY ListHead = &NtCurrentPeb()->Ldr->InMemoryOrderModuleList,
73+
ListEntry = ListHead->Flink;
74+
PLDR_DATA_TABLE_ENTRY CurEntry = nullptr;
75+
DWORD SEHTable, SEHCount;
76+
BYTE Offset = 0x20; //sizeof(_RTL_INVERTED_FUNCTION_TABLE_ENTRY)*2
77+
78+
if (RtlIsWindowsVersionOrGreater(6, 3, 0)) lpSectionName = ".mrdata";
79+
else if (!RtlIsWindowsVersionOrGreater(6, 2, 0)) Offset = 0xC;
80+
81+
while (ListEntry != ListHead) {
82+
CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
83+
ListEntry = ListEntry->Flink;
84+
if (IsModuleUnloaded(CurEntry))continue; //skip unloaded module
85+
if (IsValidMemoryModuleHandle((HMEMORYMODULE)CurEntry->DllBase))continue; //skip our memory module.
86+
if (CurEntry->DllBase == hNtdll && Offset == 0x20)continue; //Win10 skip first entry, if the base of ntdll is smallest.
87+
hModule = (HMODULE)(hModule ? min(hModule, CurEntry->DllBase) : CurEntry->DllBase);
88+
}
89+
ModuleHeaders = RtlImageNtHeader(hModule);
90+
if (!hModule || !ModuleHeaders || !hNtdll || !NtdllHeaders)return nullptr;
91+
92+
RtlCaptureImageExceptionValues(hModule, &SEHTable, &SEHCount);
93+
entry = { RtlEncodeSystemPointer((PVOID)SEHTable),(DWORD)hModule,ModuleHeaders->OptionalHeader.SizeOfImage,(PVOID)SEHCount };
94+
95+
while (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(hNtdll, lpSectionName, &SearchContext))) {
96+
PRTL_INVERTED_FUNCTION_TABLE_WIN7_32 tab = decltype(tab)(SearchContext.OutBufferPtr - Offset);
97+
98+
//Note: Same memory layout for RTL_INVERTED_FUNCTION_TABLE_ENTRY in Windows 10 x86 and x64.
99+
if (RtlIsWindowsVersionOrGreater(6, 2, 0) && tab->MaxCount == 0x200 && !tab->NextEntrySEHandlerTableEncoded) return tab;
100+
else if (tab->MaxCount == 0x200 && !tab->Overflow) return tab;
101+
}
102+
103+
return nullptr;
104+
}
105+
106+
PVOID FindLdrpInvertedFunctionTable64() {
107+
// _RTL_INVERTED_FUNCTION_TABLE x64
108+
// Count +0x0 ????????
109+
// MaxCount +0x4 0x00000200
110+
// Epoch +0x8 ????????
111+
// OverFlow +0xc 0x00000000
112+
// _RTL_INVERTED_FUNCTION_TABLE_ENTRY[0] +0x10 ntdll.dll(win10) or The smallest base module
113+
// ExceptionDirectory +0x10 ++++++++
114+
// ImageBase +0x18 ++++++++
115+
// ImageSize +0x20 ++++++++
116+
// ExceptionDirectorySize +0x24 ++++++++
117+
// _RTL_INVERTED_FUNCTION_TABLE_ENTRY[1] ... ...
118+
// ......
119+
HMODULE hModule = nullptr, hNtdll = GetModuleHandleW(L"ntdll.dll");
120+
PIMAGE_NT_HEADERS NtdllHeaders = RtlImageNtHeader(hNtdll), ModuleHeaders = nullptr;
121+
_RTL_INVERTED_FUNCTION_TABLE_ENTRY_64 entry{};
122+
LPCSTR lpSectionName = ".data";
123+
PIMAGE_DATA_DIRECTORY dir = nullptr;
124+
SEARCH_CONTEXT SearchContext{ SearchContext.MemoryBuffer = &entry,SearchContext.BufferLength = sizeof(entry) };
125+
126+
//Windows 8
127+
if (RtlVerifyVersion(6, 2, 0, RTL_VERIFY_FLAGS_MAJOR_VERSION | RTL_VERIFY_FLAGS_MINOR_VERSION)) {
128+
hModule = hNtdll;
129+
ModuleHeaders = NtdllHeaders;
130+
//lpSectionName = ".data";
131+
}
132+
//Windows 8.1 ~ Windows 10
133+
else if (RtlIsWindowsVersionOrGreater(6, 3, 0)) {
134+
hModule = hNtdll;
135+
ModuleHeaders = NtdllHeaders;
136+
lpSectionName = ".mrdata";
137+
}
138+
else {
139+
PLIST_ENTRY ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList,
140+
ListEntry = ListHead->Flink;
141+
PLDR_DATA_TABLE_ENTRY CurEntry = nullptr;
142+
while (ListEntry != ListHead) {
143+
CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
144+
ListEntry = ListEntry->Flink;
145+
//Make sure the smallest base address is not our memory module
146+
if (IsValidMemoryModuleHandle((HMEMORYMODULE)CurEntry->DllBase))continue;
147+
hModule = (HMODULE)(hModule ? min(hModule, CurEntry->DllBase) : CurEntry->DllBase);
148+
}
149+
ModuleHeaders = RtlImageNtHeader(hModule);
150+
}
151+
152+
if (!hModule || !ModuleHeaders || !hNtdll || !NtdllHeaders)return nullptr;
153+
dir = &ModuleHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
154+
entry = {
155+
dir->Size ? decltype(entry.ExceptionDirectory)((size_t)hModule + dir->VirtualAddress) : nullptr ,
156+
(PVOID)hModule, ModuleHeaders->OptionalHeader.SizeOfImage,dir->Size
157+
};
158+
159+
while (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(hNtdll, lpSectionName, &SearchContext))) {
160+
PRTL_INVERTED_FUNCTION_TABLE_64 tab = decltype(tab)(SearchContext.OutBufferPtr - 0x10);
161+
if (RtlIsWindowsVersionOrGreater(6, 2, 0) && tab->MaxCount == 0x200 && !tab->Overflow) return tab;
162+
else if (tab->MaxCount == 0x200 && !tab->Epoch) return tab;
163+
}
164+
165+
return nullptr;
166+
}
167+
168+
PLIST_ENTRY FindLdrpHashTable() {
169+
PLIST_ENTRY list = nullptr;
170+
PLIST_ENTRY head = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList, entry = head->Flink;
171+
PLDR_DATA_TABLE_ENTRY CurEntry = nullptr;
172+
while (head != entry) {
173+
CurEntry = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, LDR_DATA_TABLE_ENTRY::InInitializationOrderLinks);
174+
entry = entry->Flink;
175+
if (CurEntry->HashLinks.Flink == &CurEntry->HashLinks)continue;
176+
list = CurEntry->HashLinks.Flink;
177+
if (list->Flink == &CurEntry->HashLinks) {
178+
list = (decltype(list))((size_t)CurEntry->HashLinks.Flink - LdrHashEntry(CurEntry->BaseDllName) * sizeof(_LIST_ENTRY));
179+
break;
180+
}
181+
list = nullptr;
182+
}
183+
return list;
184+
}
185+
186+
NTSTATUS InitializeLockHeld() {
187+
NTSTATUS status = STATUS_UNSUCCESSFUL;
188+
HANDLE hSection = nullptr;
14189
OBJECT_ATTRIBUTES oa;
15190
LARGE_INTEGER li;
16191
UNICODE_STRING us{};
@@ -35,12 +210,26 @@ VOID InitializeLockHeld() {
35210
if (!NT_SUCCESS(status)) {
36211
if (status != STATUS_OBJECT_NAME_COLLISION) break;
37212

213+
HANDLE hSection2;
38214
status = NtOpenSection(
39-
&hSection,
215+
&hSection2,
40216
SECTION_ALL_ACCESS,
41217
&oa
42218
);
43219
if (!NT_SUCCESS(status))break;
220+
221+
SECTION_BASIC_INFORMATION sbi{};
222+
status = NtQuerySection(
223+
hSection2,
224+
SECTION_INFORMATION_CLASS::SectionBasicInformation,
225+
&sbi,
226+
sizeof(sbi),
227+
nullptr
228+
);
229+
230+
NtClose(hSection2);
231+
MmpGlobalDataPtr = (PMMP_GLOBAL_DATA)sbi.BaseAddress;
232+
break;
44233
}
45234

46235
PVOID BaseAddress = 0;
@@ -57,8 +246,52 @@ VOID InitializeLockHeld() {
57246
0,
58247
PAGE_READWRITE
59248
);
249+
if (!NT_SUCCESS(status))break;
250+
251+
MmpGlobalDataPtr = (PMMP_GLOBAL_DATA)BaseAddress;
252+
253+
MmpGlobalDataPtr->MajorVersion = 1;
254+
MmpGlobalDataPtr->MinorVersion = 0;
255+
256+
MmpGlobalDataPtr->LdrpNtdllBase = RtlFindNtdllLdrEntry();
257+
MmpGlobalDataPtr->LdrpHashTable = FindLdrpHashTable();
258+
259+
MmpGlobalDataPtr->LdrpModuleBaseAddressIndex = FindLdrpModuleBaseAddressIndex();
260+
261+
MmpGlobalDataPtr->LdrpInvertedFunctionTable = FindLdrpInvertedFunctionTable();
262+
263+
MmpGlobalDataPtr->MmpFeatures = MEMORY_FEATURE_SUPPORT_VERSION | MEMORY_FEATURE_LDRP_HEAP | MEMORY_FEATURE_LDRP_HANDLE_TLS_DATA | MEMORY_FEATURE_LDRP_RELEASE_TLS_ENTRY;
264+
if (MmpGlobalDataPtr->LdrpModuleBaseAddressIndex)MmpGlobalDataPtr->MmpFeatures |= MEMORY_FEATURE_MODULE_BASEADDRESS_INDEX;
265+
if (MmpGlobalDataPtr->LdrpHashTable)MmpGlobalDataPtr->MmpFeatures |= MEMORY_FEATURE_LDRP_HASH_TABLE;
266+
if (MmpGlobalDataPtr->LdrpInvertedFunctionTable)MmpGlobalDataPtr->MmpFeatures |= MEMORY_FEATURE_INVERTED_FUNCTION_TABLE;
267+
268+
MmpTlsInitialize();
60269

61270
} while (false);
62271

272+
if (!NT_SUCCESS(status) && hSection)NtClose(hSection);
63273
RtlFreeUnicodeString(&us);
274+
return status;
275+
}
276+
277+
NTSTATUS NTAPI Initialize() {
278+
NTSTATUS status;
279+
280+
RtlAcquirePebLock();
281+
status = InitializeLockHeld();
282+
RtlReleasePebLock();
283+
284+
return status;
285+
}
286+
287+
#ifdef _USRDLL
288+
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
289+
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
290+
return NT_SUCCESS(Initialize());
291+
}
292+
293+
return TRUE;
64294
}
295+
#else
296+
const NTSTATUS Initializer = Initialize();
297+
#endif

0 commit comments

Comments
 (0)