mirror of
https://github.com/bb107/MemoryModulePP
synced 2026-06-08 13:15:33 +00:00
1. Add Win10 forward export support
2. Fixed some bugs
This commit is contained in:
@@ -51,26 +51,16 @@ static ULONG NTAPI LdrHashEntry(IN const UNICODE_STRING& str, IN bool _xor = tru
|
||||
static HANDLE NTAPI RtlFindtLdrpHeap() {
|
||||
PLIST_ENTRY ListHead, ListEntry;
|
||||
PLDR_DATA_TABLE_ENTRY CurEntry;
|
||||
MEMORY_BASIC_INFORMATION mbi{};
|
||||
static HANDLE result = nullptr;
|
||||
DWORD dwHeaps = 0;
|
||||
HANDLE* hHeaps = nullptr;
|
||||
|
||||
if (result)return result;
|
||||
dwHeaps = GetProcessHeaps(dwHeaps, hHeaps);
|
||||
hHeaps = new HANDLE[dwHeaps];
|
||||
|
||||
ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
|
||||
ListEntry = ListHead->Flink;
|
||||
if (ListHead == ListEntry)return nullptr;
|
||||
if (ListHead == ListEntry)return result;
|
||||
CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
|
||||
GetProcessHeaps(dwHeaps, hHeaps);
|
||||
for (DWORD i = 0; i < dwHeaps; ++i) {
|
||||
if (HeapValidate(hHeaps[i], 0, CurEntry)) {
|
||||
result = hHeaps[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete[]hHeaps;
|
||||
return result;
|
||||
NtQueryVirtualMemory(NtCurrentProcess(), CurEntry, MemoryBasicInformation, &mbi, sizeof(mbi), (PSIZE_T)&ListHead);
|
||||
return result = mbi.AllocationBase;
|
||||
}
|
||||
static PLDR_DATA_TABLE_ENTRY NTAPI RtlFindNtdllLdrEntry() {
|
||||
PLIST_ENTRY ListHead, ListEntry;
|
||||
@@ -242,7 +232,7 @@ static PRTL_BALANCED_NODE NTAPI RtlFindLdrpModuleBaseAddressIndex() {
|
||||
return LdrpModuleBaseAddressIndex;
|
||||
}
|
||||
static NTSTATUS NTAPI NtInsertModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTRY DataTableEntry, IN PVOID BaseAddress) {
|
||||
auto LdrpModuleBaseAddressIndex = RtlFindLdrpModuleBaseAddressIndex();
|
||||
static auto LdrpModuleBaseAddressIndex = RtlFindLdrpModuleBaseAddressIndex();
|
||||
if (!LdrpModuleBaseAddressIndex)return STATUS_UNSUCCESSFUL;
|
||||
|
||||
PLDR_DATA_TABLE_ENTRY_WIN8 LdrNode = decltype(LdrNode)((size_t)LdrpModuleBaseAddressIndex - offsetof(LDR_DATA_TABLE_ENTRY_WIN8, BaseAddressIndexNode));
|
||||
@@ -274,20 +264,82 @@ static NTSTATUS NTAPI NtInsertModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTR
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
static NTSTATUS NTAPI NtRemoveModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTRY DataTableEntry) {
|
||||
RTL_RB_TREE tree{ RtlFindLdrpModuleBaseAddressIndex() };
|
||||
static RTL_RB_TREE tree{ RtlFindLdrpModuleBaseAddressIndex() };
|
||||
if (!tree.Root)return STATUS_UNSUCCESSFUL;
|
||||
|
||||
RtlRbRemoveNode(&tree, &PLDR_DATA_TABLE_ENTRY_WIN8(DataTableEntry)->BaseAddressIndexNode);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS NTAPI NtFreeDependencies(IN PLDR_DATA_TABLE_ENTRY_WIN8 LdrEntry) {
|
||||
_LDR_DDAG_NODE* DependentDdgeNode = nullptr;
|
||||
PLDR_DATA_TABLE_ENTRY_WIN8 ModuleEntry = nullptr;
|
||||
_LDRP_CSLIST* head = (decltype(head))LdrEntry->DdagNode->Dependencies, *entry = head;
|
||||
if (!LdrEntry->DdagNode->Dependencies)return STATUS_SUCCESS;
|
||||
|
||||
//find all dependencies and free
|
||||
do {
|
||||
DependentDdgeNode = entry->Dependent.DependentDdagNode;
|
||||
if (DependentDdgeNode->Modules.Flink->Flink != &DependentDdgeNode->Modules) RaiseException(-1, EXCEPTION_NONCONTINUABLE, 0, nullptr);
|
||||
ModuleEntry = decltype(ModuleEntry)((size_t)DependentDdgeNode->Modules.Flink - offsetof(_LDR_DATA_TABLE_ENTRY_WIN8, NodeModuleLink));
|
||||
if (ModuleEntry->DdagNode != DependentDdgeNode) RaiseException(-1, EXCEPTION_NONCONTINUABLE, 0, nullptr);
|
||||
if (!DependentDdgeNode->IncomingDependencies) RaiseException(-1, EXCEPTION_NONCONTINUABLE, 0, nullptr);
|
||||
_LDRP_CSLIST::_LDRP_CSLIST_INCOMMING* _last = DependentDdgeNode->IncomingDependencies, *_entry = _last;
|
||||
_LDR_DDAG_NODE* CurrentDdagNode;
|
||||
size_t State = 0, Cookies;
|
||||
|
||||
//Acquire LoaderLock
|
||||
do {
|
||||
if (!NT_SUCCESS(LdrLockLoaderLock(LOCK_NO_WAIT_IF_BUSY, &State, &Cookies)))
|
||||
RaiseException(-1, EXCEPTION_NONCONTINUABLE, 0, nullptr);
|
||||
} while (State != LOCK_STATE_ENTERED);
|
||||
do {
|
||||
CurrentDdagNode = (decltype(CurrentDdagNode))((size_t)_entry->IncommingDdagNode & ~1);
|
||||
if (CurrentDdagNode == LdrEntry->DdagNode) {
|
||||
//node is head
|
||||
if (_entry == DependentDdgeNode->IncomingDependencies) {
|
||||
//only one node in list
|
||||
if (_entry->NextIncommingEntry == (PSINGLE_LIST_ENTRY)DependentDdgeNode->IncomingDependencies) {
|
||||
DependentDdgeNode->IncomingDependencies = nullptr;
|
||||
}
|
||||
else {
|
||||
//find the last node in the list
|
||||
PSINGLE_LIST_ENTRY i = _entry->NextIncommingEntry;
|
||||
while (i->Next != (PSINGLE_LIST_ENTRY)_entry)i = i->Next;
|
||||
i->Next = _entry->NextIncommingEntry;
|
||||
DependentDdgeNode->IncomingDependencies = (_LDRP_CSLIST::_LDRP_CSLIST_INCOMMING*)_entry->NextIncommingEntry;
|
||||
}
|
||||
}
|
||||
//node is not head
|
||||
else {
|
||||
_last->NextIncommingEntry = _entry->NextIncommingEntry;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//save the last entry
|
||||
if (_last != _entry)_last = (decltype(_last))_last->NextIncommingEntry;
|
||||
_entry = (decltype(_entry))_entry->NextIncommingEntry;
|
||||
} while (_entry != _last);
|
||||
//free LoaderLock
|
||||
LdrUnlockLoaderLock(0, Cookies);
|
||||
|
||||
//free it
|
||||
LdrUnloadDll(ModuleEntry->DllBase);
|
||||
NtFreeLdrpHeap(LdrEntry->DdagNode->Dependencies);
|
||||
|
||||
//lookup next dependent.
|
||||
entry = (decltype(entry))entry->Dependent.NextDependentEntry;
|
||||
LdrEntry->DdagNode->Dependencies = (_LDRP_CSLIST::_LDRP_CSLIST_DEPENDENT*)(entry == head ? nullptr : entry);
|
||||
} while (entry != head);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
static bool NTAPI NtInitializeLdrDataTableEntry(
|
||||
OUT PLDR_DATA_TABLE_ENTRY LdrEntry,
|
||||
IN DWORD dwFlags,
|
||||
IN PVOID BaseAddress,
|
||||
IN UNICODE_STRING &DllBaseName,
|
||||
IN UNICODE_STRING &DllFullName) {
|
||||
UNREFERENCED_PARAMETER(dwFlags);
|
||||
RtlZeroMemory(LdrEntry, NtLdrDataTableEntrySize());
|
||||
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(BaseAddress);
|
||||
if (!headers)return false;
|
||||
@@ -303,7 +355,7 @@ static bool NTAPI NtInitializeLdrDataTableEntry(
|
||||
case win8:
|
||||
case win8_1: {
|
||||
auto entry = (PLDR_DATA_TABLE_ENTRY_WIN8)LdrEntry;
|
||||
|
||||
NtQuerySystemTime(&entry->LoadTime);
|
||||
entry->OriginalBase = headers->OptionalHeader.ImageBase;
|
||||
entry->BaseNameHashValue = LdrHashEntry(DllBaseName, false);
|
||||
entry->LoadReason = LoadReasonDynamicLoad;
|
||||
@@ -311,14 +363,17 @@ static bool NTAPI NtInitializeLdrDataTableEntry(
|
||||
if (!(entry->DdagNode = (decltype(entry->DdagNode))NtAllocateLdrpHeap(sizeof(_LDR_DDAG_NODE))))return false;
|
||||
//NtInitializeListEntry(&entry->NodeModuleLink);
|
||||
//NtInitializeListEntry(&entry->DdagNode->Modules);
|
||||
//NtInitializeSingleEntry(&entry->DdagNode->CondenseLink);
|
||||
entry->NodeModuleLink.Flink = &entry->DdagNode->Modules;
|
||||
entry->NodeModuleLink.Blink = &entry->DdagNode->Modules;
|
||||
entry->DdagNode->Modules.Flink = &entry->NodeModuleLink;
|
||||
entry->DdagNode->Modules.Blink = &entry->NodeModuleLink;
|
||||
entry->DdagNode->State = LdrModulesReadyToRun;
|
||||
entry->DdagNode->LoadCount = 0;
|
||||
|
||||
NtInitializeSingleEntry(&entry->DdagNode->CondenseLink);
|
||||
entry->DdagNode->LoadCount = 1;
|
||||
entry->ImageDll = entry->LoadNotificationsSent = entry->EntryProcessed =
|
||||
entry->InLegacyLists = entry->InIndexes = entry->ProcessAttachCalled = true;
|
||||
entry->InExceptionTable = !(dwFlags & LOAD_FLAGS_NOT_ADD_INVERTED_FUNCTION);
|
||||
FlagsProcessed = true;
|
||||
}
|
||||
|
||||
case win7: {
|
||||
@@ -344,6 +399,7 @@ static bool NTAPI NtInitializeLdrDataTableEntry(
|
||||
LdrEntry->BaseDllName = DllBaseName;
|
||||
LdrEntry->FullDllName = DllFullName;
|
||||
LdrEntry->EntryPoint = (PVOID)((size_t)BaseAddress + headers->OptionalHeader.AddressOfEntryPoint);
|
||||
LdrEntry->LoadCount = 1;
|
||||
if (!FlagsProcessed) LdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_INSERTED | LDRP_ENTRY_PROCESSED | LDRP_PROCESS_ATTACH_CALLED;
|
||||
NtInitializeListEntry(&LdrEntry->HashLinks);
|
||||
return true;
|
||||
@@ -355,12 +411,12 @@ static bool NTAPI NtFreeLdrDataTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) {
|
||||
switch (NtWindowsVersion()) {
|
||||
case win10:
|
||||
case win10_1:
|
||||
case win10_2: {
|
||||
auto entry = (PLDR_DATA_TABLE_ENTRY_WIN10)LdrEntry;
|
||||
NtFreeLdrpHeap(entry->DdagNode);
|
||||
}
|
||||
case win10_2:
|
||||
case win8:
|
||||
case win8_1: {
|
||||
auto entry = (PLDR_DATA_TABLE_ENTRY_WIN8)LdrEntry;
|
||||
NtFreeDependencies(entry);
|
||||
NtFreeLdrpHeap(entry->DdagNode);
|
||||
NtRemoveModuleBaseAddressIndexNode(LdrEntry);
|
||||
}
|
||||
case win7:
|
||||
@@ -556,7 +612,7 @@ static NTSTATUS NTAPI NtMapDllMemory(IN HMEMORYMODULE ViewBase, IN DWORD dwFlags
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI NtLoadDllMemory(OUT HMEMORYMODULE* BaseAddress, IN LPVOID BufferAddress, IN size_t BufferSize) {
|
||||
return NtLoadDllMemoryExW(BaseAddress, nullptr, 0, BufferAddress, BufferSize, nullptr, nullptr);
|
||||
return NtLoadDllMemoryExW(BaseAddress, nullptr, LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS, BufferAddress, BufferSize, nullptr, nullptr);
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI NtLoadDllMemoryExW(
|
||||
@@ -570,6 +626,8 @@ NTSTATUS NTAPI NtLoadDllMemoryExW(
|
||||
PMEMORYMODULE module = nullptr;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PLDR_DATA_TABLE_ENTRY ModuleEntry = nullptr;
|
||||
PIMAGE_NT_HEADERS headers = nullptr;
|
||||
UNREFERENCED_PARAMETER(BufferSize);
|
||||
|
||||
__try {
|
||||
if (IsBadReadPtr(BufferAddress, BufferSize))status = STATUS_ACCESS_VIOLATION;
|
||||
@@ -616,7 +674,7 @@ NTSTATUS NTAPI NtLoadDllMemoryExW(
|
||||
}
|
||||
}
|
||||
|
||||
if (!(*BaseAddress = MemoryLoadLibrary(BufferAddress, BufferSize))) {
|
||||
if (!(*BaseAddress = MemoryLoadLibrary(BufferAddress))) {
|
||||
switch (GetLastError()) {
|
||||
case ERROR_BAD_EXE_FORMAT:
|
||||
return STATUS_INVALID_IMAGE_FORMAT;
|
||||
@@ -633,7 +691,9 @@ NTSTATUS NTAPI NtLoadDllMemoryExW(
|
||||
return STATUS_INVALID_ADDRESS;
|
||||
}
|
||||
module->loadFromNtLoadDllMemory = true;
|
||||
if (dwFlags & LOAD_FLAGS_NOT_MAP_DLL) return STATUS_SUCCESS;
|
||||
headers = RtlImageNtHeader(*BaseAddress);
|
||||
if (headers->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_SEH)dwFlags |= LOAD_FLAGS_NOT_ADD_INVERTED_FUNCTION;
|
||||
if (dwFlags & LOAD_FLAGS_NOT_MAP_DLL) return status;
|
||||
|
||||
status = NtMapDllMemory(*BaseAddress, dwFlags, DllName, DllFullName, &ModuleEntry);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
@@ -647,26 +707,34 @@ NTSTATUS NTAPI NtLoadDllMemoryExW(
|
||||
|
||||
if (!(dwFlags & LOAD_FLAGS_NOT_USE_REFERENCE_COUNT))module->UseReferenceCount = true;
|
||||
|
||||
if (dwFlags & LOAD_FLAGS_NOT_ADD_INVERTED_FUNCTION)return STATUS_SUCCESS;
|
||||
status = RtlInsertInvertedFunctionTable((PVOID)module->codeBase, RtlImageNtHeader(*BaseAddress)->OptionalHeader.SizeOfImage);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
NtUnloadDllMemory(*BaseAddress);
|
||||
*BaseAddress = nullptr;
|
||||
if (LdrEntry)*LdrEntry = nullptr;
|
||||
return status;
|
||||
}
|
||||
module->InsertInvertedFunctionTableEntry = true;
|
||||
|
||||
if (dwFlags & LOAD_FLAGS_NOT_HANDLE_TLS)return STATUS_SUCCESS;
|
||||
status = LdrpHandleTlsData(ModuleEntry);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
NtUnloadDllMemory(*BaseAddress);
|
||||
*BaseAddress = nullptr;
|
||||
if (LdrEntry)*LdrEntry = nullptr;
|
||||
return status;
|
||||
if (!(dwFlags & LOAD_FLAGS_NOT_ADD_INVERTED_FUNCTION)) {
|
||||
status = RtlInsertInvertedFunctionTable((PVOID)module->codeBase, headers->OptionalHeader.SizeOfImage);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
NtUnloadDllMemory(*BaseAddress);
|
||||
*BaseAddress = nullptr;
|
||||
if (LdrEntry)*LdrEntry = nullptr;
|
||||
return status;
|
||||
}
|
||||
module->InsertInvertedFunctionTableEntry = true;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
if (!(dwFlags & LOAD_FLAGS_NOT_HANDLE_TLS)) {
|
||||
status = LdrpHandleTlsData(ModuleEntry);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
do {
|
||||
if (dwFlags & LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS) {
|
||||
status = 0x7fffffff;
|
||||
break;
|
||||
}
|
||||
NtUnloadDllMemory(*BaseAddress);
|
||||
*BaseAddress = nullptr;
|
||||
if (LdrEntry)*LdrEntry = nullptr;
|
||||
return status;
|
||||
} while (false);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI NtLoadDllMemoryExA(
|
||||
@@ -705,22 +773,28 @@ NTSTATUS NTAPI NtUnloadDllMemory(IN HMEMORYMODULE BaseAddress) {
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PMEMORYMODULE module = MapMemoryModuleHandle(BaseAddress);
|
||||
|
||||
//Not a memory module loaded via NtLoadDllMemory
|
||||
if (!module || !module->loadFromNtLoadDllMemory)return STATUS_INVALID_HANDLE;
|
||||
|
||||
//Mapping dll failed
|
||||
if (module->loadFromNtLoadDllMemory && !module->MappedDll) {
|
||||
module->underUnload = true;
|
||||
MemoryFreeLibrary(BaseAddress);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
|
||||
ListEntry = ListHead->Flink;
|
||||
while (ListEntry != ListHead) {
|
||||
CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
|
||||
ListEntry = ListEntry->Flink;
|
||||
/* Check if it's being unloaded */
|
||||
if (!CurEntry->InMemoryOrderLinks.Flink) continue;
|
||||
/* Check if name matches */
|
||||
if (CurEntry->DllBase == BaseAddress) {
|
||||
if (RtlImageNtHeader(BaseAddress)->OptionalHeader.SizeOfImage == CurEntry->SizeOfImage) {
|
||||
if (module->UseReferenceCount) {
|
||||
status = NtGetReferenceCount(CurEntry, &count);
|
||||
if (!NT_SUCCESS(status))return status;
|
||||
}
|
||||
if (!count) {
|
||||
if (!(count & ~1)) {
|
||||
module->underUnload = true;
|
||||
if (module->MappedDll) {
|
||||
if (module->InsertInvertedFunctionTableEntry) {
|
||||
@@ -774,7 +848,10 @@ static VOID NTAPI RtlpInsertInvertedFunctionTable(IN PRTL_INVERTED_FUNCTION_TABL
|
||||
if (CurrentSize != InvertedTable->MaxCount) {
|
||||
//if (need)_InterlockedIncrement(&InvertedTable->Epoch);
|
||||
if (CurrentSize != 0) {
|
||||
while (Index < CurrentSize)if (ImageBase < InvertedTable->Entries[Index].ImageBase)break;
|
||||
while (Index < CurrentSize) {
|
||||
if (ImageBase < InvertedTable->Entries[Index].ImageBase)break;
|
||||
++Index;
|
||||
}
|
||||
|
||||
if (Index != CurrentSize) {
|
||||
RtlMoveMemory(&InvertedTable->Entries[Index + 1],
|
||||
@@ -873,13 +950,13 @@ static VOID NTAPI RtlpRemoveInvertedFunctionTable(IN PRTL_INVERTED_FUNCTION_TABL
|
||||
#else
|
||||
if (IsWin10) {
|
||||
RtlMoveMemory(&InvertedTable->Entries[Index], &InvertedTable->Entries[Index + 1],
|
||||
(CurrentSize - Index) * sizeof(PRTL_INVERTED_FUNCTION_TABLE_ENTRY));
|
||||
(CurrentSize - Index) * sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY));
|
||||
}
|
||||
else {
|
||||
RtlMoveMemory(
|
||||
Index ? &InvertedTable->Entries[Index - 1].NextEntrySEHandlerTableEncoded : (PVOID)&InvertedTable->NextEntrySEHandlerTableEncoded,
|
||||
&InvertedTable->Entries[Index].NextEntrySEHandlerTableEncoded,
|
||||
(CurrentSize - Index) * sizeof(PRTL_INVERTED_FUNCTION_TABLE_ENTRY));
|
||||
(CurrentSize - Index) * sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user