1. Add Win10 forward export support

2. Fixed some bugs
This commit is contained in:
Boring
2020-02-22 14:53:26 +08:00
parent ea135ac392
commit ed550ae6c7
15 changed files with 764 additions and 175 deletions
+131 -54
View File
@@ -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
}