refactoring

This commit is contained in:
Boring
2022-09-26 22:43:43 +08:00
parent 446bb917d9
commit adf274cef0
60 changed files with 40266 additions and 2481 deletions
+68
View File
@@ -0,0 +1,68 @@
#include "stdafx.h"
PRTL_RB_TREE NTAPI RtlFindLdrpModuleBaseAddressIndex() {
static PRTL_RB_TREE LdrpModuleBaseAddressIndex = nullptr;
if (LdrpModuleBaseAddressIndex)return LdrpModuleBaseAddressIndex;
PLDR_DATA_TABLE_ENTRY_WIN10 nt10 = decltype(nt10)(RtlFindNtdllLdrEntry());
PRTL_BALANCED_NODE node = nullptr;
if (!nt10 || !RtlIsWindowsVersionOrGreater(6, 2, 0))return nullptr;
node = &nt10->BaseAddressIndexNode;
while (node->ParentValue & (~7)) node = decltype(node)(node->ParentValue & (~7));
if (!node->Red) {
BYTE count = 0;
PRTL_RB_TREE tmp = nullptr;
SEARCH_CONTEXT SearchContext{};
SearchContext.MemoryBuffer = &node;
SearchContext.BufferLength = sizeof(size_t);
while (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection((HMODULE)nt10->DllBase, ".data", &SearchContext))) {
if (count++)return nullptr;
tmp = (decltype(tmp))SearchContext.MemoryBlockInSection;
}
if (count && tmp && tmp->Root && tmp->Min) {
LdrpModuleBaseAddressIndex = tmp;
}
}
return LdrpModuleBaseAddressIndex;
}
NTSTATUS NTAPI RtlInsertModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTRY DataTableEntry, IN PVOID BaseAddress) {
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));
bool bRight = false;
const auto i = offsetof(LDR_DATA_TABLE_ENTRY_WIN8, BaseAddressIndexNode);
while (true) {
if (BaseAddress < LdrNode->DllBase) {
if (!LdrNode->BaseAddressIndexNode.Left)break;
LdrNode = decltype(LdrNode)((size_t)LdrNode->BaseAddressIndexNode.Left - offsetof(LDR_DATA_TABLE_ENTRY_WIN8, BaseAddressIndexNode));
}
else if (BaseAddress > LdrNode->DllBase) {
if (!LdrNode->BaseAddressIndexNode.Right) {
bRight = true;
break;
}
LdrNode = decltype(LdrNode)((size_t)LdrNode->BaseAddressIndexNode.Right - offsetof(LDR_DATA_TABLE_ENTRY_WIN8, BaseAddressIndexNode));
}
else {
LdrNode->DdagNode->LoadCount++;
if (RtlIsWindowsVersionOrGreater(10, 0, 0)) {
PLDR_DATA_TABLE_ENTRY_WIN10(LdrNode)->ReferenceCount++;
}
return STATUS_SUCCESS;
}
}
RtlRbInsertNodeEx(LdrpModuleBaseAddressIndex, &LdrNode->BaseAddressIndexNode, bRight, &PLDR_DATA_TABLE_ENTRY_WIN8(DataTableEntry)->BaseAddressIndexNode);
return STATUS_SUCCESS;
}
NTSTATUS NTAPI RtlRemoveModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTRY DataTableEntry) {
static auto tree{ RtlFindLdrpModuleBaseAddressIndex() };
if (!tree->Root)return STATUS_UNSUCCESSFUL;
RtlRbRemoveNode(tree, &PLDR_DATA_TABLE_ENTRY_WIN8(DataTableEntry)->BaseAddressIndexNode);
return STATUS_SUCCESS;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
PRTL_RB_TREE NTAPI RtlFindLdrpModuleBaseAddressIndex();
NTSTATUS NTAPI RtlInsertModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTRY DataTableEntry, IN PVOID BaseAddress);
NTSTATUS NTAPI RtlRemoveModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTRY DataTableEntry);
+5
View File
@@ -0,0 +1,5 @@
#include "stdafx.h"
VOID Initialize() {
}
+357
View File
@@ -0,0 +1,357 @@
#include "stdafx.h"
#include <cstddef>
PLDR_DATA_TABLE_ENTRY const LdrpNtdllBase = RtlFindLdrTableEntryByBaseName(L"ntdll.dll");
static NTSTATUS NTAPI RtlFreeDependencies(IN PLDR_DATA_TABLE_ENTRY_WIN10 LdrEntry) {
_LDR_DDAG_NODE* DependentDdgeNode = nullptr;
PLDR_DATA_TABLE_ENTRY_WIN10 ModuleEntry = nullptr;
_LDRP_CSLIST* head = (decltype(head))LdrEntry->DdagNode->Dependencies, * entry = head;
HANDLE heap = NtCurrentPeb()->ProcessHeap;
const static bool IsWin8 = RtlIsWindowsVersionInScope(6, 2, 0, 6, 3, -1);
if (!LdrEntry->DdagNode->Dependencies)return STATUS_SUCCESS;
//find all dependencies and free
do {
DependentDdgeNode = entry->Dependent.DependentDdagNode;
if (DependentDdgeNode->Modules.Flink->Flink != &DependentDdgeNode->Modules) __fastfail(FAST_FAIL_CORRUPT_LIST_ENTRY);
ModuleEntry = decltype(ModuleEntry)((size_t)DependentDdgeNode->Modules.Flink - offsetof(_LDR_DATA_TABLE_ENTRY_WIN8, NodeModuleLink));
if (ModuleEntry->DdagNode != DependentDdgeNode) __fastfail(FAST_FAIL_CORRUPT_LIST_ENTRY);
if (!DependentDdgeNode->IncomingDependencies) __fastfail(FAST_FAIL_CORRUPT_LIST_ENTRY);
_LDRP_CSLIST::_LDRP_CSLIST_INCOMMING* _last = DependentDdgeNode->IncomingDependencies, * _entry = _last;
_LDR_DDAG_NODE* CurrentDdagNode;
ULONG State = 0;
PVOID Cookies;
//Acquire LoaderLock
do {
if (!NT_SUCCESS(LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY, &State, &Cookies))) __fastfail(FAST_FAIL_FATAL_APP_EXIT);
} while (State != LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED);
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);
entry = (decltype(entry))entry->Dependent.NextDependentEntry;
//free it
if (IsWin8) {
//Update win8 dep count
_LDR_DDAG_NODE_WIN8* win8_node = (decltype(win8_node))ModuleEntry->DdagNode;
if (!win8_node->DependencyCount)__fastfail(FAST_FAIL_CORRUPT_LIST_ENTRY);
--win8_node->DependencyCount;
if (!ModuleEntry->DdagNode->LoadCount && win8_node->ReferenceCount == 1 && !win8_node->DependencyCount) {
win8_node->LoadCount = 1;
LdrUnloadDll(ModuleEntry->DllBase);
}
}
else {
LdrUnloadDll(ModuleEntry->DllBase);
}
RtlFreeHeap(heap, 0, LdrEntry->DdagNode->Dependencies);
//lookup next dependent.
LdrEntry->DdagNode->Dependencies = (_LDRP_CSLIST::_LDRP_CSLIST_DEPENDENT*)(entry == head ? nullptr : entry);
} while (entry != head);
return STATUS_SUCCESS;
}
PLDR_DATA_TABLE_ENTRY NTAPI RtlAllocateDataTableEntry(IN PVOID BaseAddress) {
PLDR_DATA_TABLE_ENTRY LdrEntry = nullptr;
PIMAGE_NT_HEADERS NtHeader;
HANDLE heap = NtCurrentPeb()->ProcessHeap;
/* Make sure the header is valid */
if (NtHeader = RtlImageNtHeader(BaseAddress)) {
/* Allocate an entry */
LdrEntry = (PLDR_DATA_TABLE_ENTRY)RtlAllocateHeap(heap, HEAP_ZERO_MEMORY, LdrpDataTableEntrySize());
}
/* Return the entry */
return LdrEntry;
}
bool NTAPI RtlInitializeLdrDataTableEntry(
OUT PLDR_DATA_TABLE_ENTRY LdrEntry,
IN DWORD dwFlags,
IN PVOID BaseAddress,
IN UNICODE_STRING& DllBaseName,
IN UNICODE_STRING& DllFullName) {
RtlZeroMemory(LdrEntry, LdrpDataTableEntrySize());
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(BaseAddress);
if (!headers)return false;
HANDLE heap = NtCurrentPeb()->ProcessHeap;
bool FlagsProcessed = false;
bool CorImage = false, CorIL = false;
auto& com = headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
if (com.Size && com.VirtualAddress) {
CorImage = true;
auto cor = PIMAGE_COR20_HEADER(LPBYTE(BaseAddress) + com.VirtualAddress);
if (cor->Flags & ReplacesCorHdrNumericDefines::COMIMAGE_FLAGS_ILONLY) {
CorIL = true;
}
}
switch (NtWindowsVersion()) {
case win10:
case win10_1:
case win10_2: {
auto entry = (PLDR_DATA_TABLE_ENTRY_WIN10)LdrEntry;
entry->ReferenceCount = 1;
}
case win8:
case win8_1: {
auto entry = (PLDR_DATA_TABLE_ENTRY_WIN8)LdrEntry;
const static bool IsWin8 = RtlIsWindowsVersionInScope(6, 2, 0, 6, 3, -1);
NtQuerySystemTime(&entry->LoadTime);
entry->OriginalBase = headers->OptionalHeader.ImageBase;
entry->BaseNameHashValue = LdrHashEntry(DllBaseName, false);
entry->LoadReason = LoadReasonDynamicLoad;
if (!NT_SUCCESS(RtlInsertModuleBaseAddressIndexNode(LdrEntry, BaseAddress)))return false;
if (!(entry->DdagNode = (decltype(entry->DdagNode))
RtlAllocateHeap(heap, HEAP_ZERO_MEMORY, IsWin8 ? sizeof(_LDR_DDAG_NODE_WIN8) : sizeof(_LDR_DDAG_NODE))))return false;
//RtlInitializeListEntry(&entry->NodeModuleLink);
//RtlInitializeListEntry(&entry->DdagNode->Modules);
//RtlInitializeSingleEntry(&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 = 1;
if (IsWin8) ((_LDR_DDAG_NODE_WIN8*)(entry->DdagNode))->ReferenceCount = 1;
entry->ImageDll = entry->LoadNotificationsSent = entry->EntryProcessed =
entry->InLegacyLists = entry->InIndexes = entry->ProcessAttachCalled = true;
entry->InExceptionTable = !(dwFlags & LOAD_FLAGS_NOT_ADD_INVERTED_FUNCTION);
entry->CorImage = CorImage;
entry->CorILOnly = CorIL;
FlagsProcessed = true;
}
case win7: {
if (LdrpDataTableEntrySize() == sizeof(LDR_DATA_TABLE_ENTRY_WIN7)) {
auto entry = (PLDR_DATA_TABLE_ENTRY_WIN7)LdrEntry;
entry->OriginalBase = headers->OptionalHeader.ImageBase;
NtQuerySystemTime(&entry->LoadTime);
}
}
case vista: {
if (LdrpDataTableEntrySize() == sizeof(LDR_DATA_TABLE_ENTRY_VISTA) ||
LdrpDataTableEntrySize() == sizeof(LDR_DATA_TABLE_ENTRY_WIN7)) {
auto entry = (PLDR_DATA_TABLE_ENTRY_VISTA)LdrEntry;
RtlInitializeListEntry(&entry->ForwarderLinks);
RtlInitializeListEntry(&entry->StaticLinks);
RtlInitializeListEntry(&entry->ServiceTagLinks);
}
}
case xp: {
LdrEntry->DllBase = BaseAddress;
LdrEntry->SizeOfImage = headers->OptionalHeader.SizeOfImage;
LdrEntry->TimeDateStamp = headers->FileHeader.TimeDateStamp;
LdrEntry->BaseDllName = DllBaseName;
LdrEntry->FullDllName = DllFullName;
LdrEntry->EntryPoint = (PLDR_INIT_ROUTINE)((size_t)BaseAddress + headers->OptionalHeader.AddressOfEntryPoint);
LdrEntry->ObsoleteLoadCount = 1;
if (!FlagsProcessed) {
LdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_INSERTED | LDRP_ENTRY_PROCESSED | LDRP_PROCESS_ATTACH_CALLED;
if (CorImage)LdrEntry->Flags |= LDRP_COR_IMAGE;
}
RtlInitializeListEntry(&LdrEntry->HashLinks);
return true;
}
default:return false;
}
}
bool NTAPI RtlFreeLdrDataTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) {
HANDLE heap = NtCurrentPeb()->ProcessHeap;
switch (NtWindowsVersion()) {
case win10:
case win10_1:
case win10_2:
case win8:
case win8_1: {
auto entry = (PLDR_DATA_TABLE_ENTRY_WIN10)LdrEntry;
RtlFreeDependencies(entry);
RtlFreeHeap(heap, 0, entry->DdagNode);
RtlRemoveModuleBaseAddressIndexNode(LdrEntry);
}
case win7:
case vista: {
if (LdrpDataTableEntrySize() == sizeof(LDR_DATA_TABLE_ENTRY_VISTA) ||
LdrpDataTableEntrySize() == sizeof(LDR_DATA_TABLE_ENTRY_WIN7)) {
PLDR_DATA_TABLE_ENTRY_VISTA entry = (decltype(entry))LdrEntry;
PLIST_ENTRY head = &entry->ForwarderLinks, next = head->Flink;
while (head != next) {
PLDR_DATA_TABLE_ENTRY dep = *(decltype(&dep))((size_t*)next + 2);
LdrUnloadDll(dep->DllBase);
next = next->Flink;
RtlFreeHeap(heap, 0, next->Blink);
}
}
}
case xp: {
RtlFreeHeap(heap, 0, LdrEntry->BaseDllName.Buffer);
RtlFreeHeap(heap, 0, LdrEntry->FullDllName.Buffer);
RemoveEntryList(&LdrEntry->InLoadOrderLinks);
RemoveEntryList(&LdrEntry->InMemoryOrderLinks);
RemoveEntryList(&LdrEntry->InInitializationOrderLinks);
RemoveEntryList(&LdrEntry->HashLinks);
RtlFreeHeap(heap, 0, LdrEntry);
return true;
}
default:return false;
}
}
NTSTATUS NTAPI RtlUpdateReferenceCount(IN OUT PMEMORYMODULE pModule, IN DWORD Flags) {
if (Flags != FLAG_REFERENCE && Flags != FLAG_DEREFERENCE)return STATUS_INVALID_PARAMETER_2;
if (Flags == FLAG_REFERENCE && pModule->dwReferenceCount != 0xffffffff)
++pModule->dwReferenceCount;
if (Flags == FLAG_DEREFERENCE && pModule->dwReferenceCount)
--pModule->dwReferenceCount;
return STATUS_SUCCESS;
}
NTSTATUS NTAPI RtlGetReferenceCount(IN PMEMORYMODULE pModule, OUT PULONG Count) {
*Count = pModule->dwReferenceCount;
return STATUS_SUCCESS;
}
VOID NTAPI RtlInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) {
PPEB_LDR_DATA PebData = NtCurrentPeb()->Ldr;
PLIST_ENTRY LdrpHashTable = RtlFindLdrpHashTable();
ULONG i;
/* Insert into hash table */
i = LdrHashEntry(LdrEntry->BaseDllName);
InsertTailList(&LdrpHashTable[i], &LdrEntry->HashLinks);
/* Insert into other lists */
InsertTailList(&PebData->InLoadOrderModuleList, &LdrEntry->InLoadOrderLinks);
InsertTailList(&PebData->InMemoryOrderModuleList, &LdrEntry->InMemoryOrderLinks);
InsertTailList(&PebData->InInitializationOrderModuleList, &LdrEntry->InInitializationOrderLinks);
}
VOID NTAPI RtlRbInsertNodeEx(IN PRTL_RB_TREE Tree, IN PRTL_BALANCED_NODE Parent, IN BOOLEAN Right, OUT PRTL_BALANCED_NODE Node) {
decltype(&RtlRbInsertNodeEx)_RtlRbInsertNodeEx = decltype(_RtlRbInsertNodeEx)(RtlGetNtProcAddress("RtlRbInsertNodeEx"));
if (!_RtlRbInsertNodeEx)return;
return _RtlRbInsertNodeEx(Tree, Parent, Right, Node);
}
VOID NTAPI RtlRbRemoveNode(IN PRTL_RB_TREE Tree, IN PRTL_BALANCED_NODE Node) {
decltype(&RtlRbRemoveNode)_RtlRbRemoveNode = decltype(_RtlRbRemoveNode)(RtlGetNtProcAddress("RtlRbRemoveNode"));
if (!_RtlRbRemoveNode)return;
return _RtlRbRemoveNode(Tree, Node);
}
PLDR_DATA_TABLE_ENTRY NTAPI RtlFindLdrTableEntryByHandle(PVOID BaseAddress) {
PLIST_ENTRY ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList, ListEntry = ListHead->Flink;
PLDR_DATA_TABLE_ENTRY CurEntry;
while (ListEntry != ListHead) {
CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
ListEntry = ListEntry->Flink;
if (CurEntry->DllBase == BaseAddress) {
return CurEntry;
}
}
return nullptr;
}
PLDR_DATA_TABLE_ENTRY NTAPI RtlFindLdrTableEntryByBaseName(PCWSTR BaseName) {
PLIST_ENTRY ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList, ListEntry = ListHead->Flink;
PLDR_DATA_TABLE_ENTRY CurEntry;
while (ListEntry != ListHead) {
CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
ListEntry = ListEntry->Flink;
if (!wcsnicmp(BaseName, CurEntry->BaseDllName.Buffer, (CurEntry->BaseDllName.Length / sizeof(wchar_t)) - 4) ||
!wcsnicmp(BaseName, CurEntry->BaseDllName.Buffer, CurEntry->BaseDllName.Length / sizeof(wchar_t))) {
return CurEntry;
}
}
return nullptr;
}
ULONG NTAPI LdrHashEntry(IN UNICODE_STRING& str, IN bool _xor) {
ULONG result = 0;
if (RtlIsWindowsVersionOrGreater(6, 2, 0)) {
RtlHashUnicodeString(&str, TRUE, HASH_STRING_ALGORITHM_DEFAULT, &result);
}
else {
for (USHORT i = 0; i < (str.Length / sizeof(wchar_t)); ++i)
result += 0x1003F * RtlUpcaseUnicodeChar(str.Buffer[i]);
}
if (_xor)result &= (LDR_HASH_TABLE_ENTRIES - 1);
return result;
}
PLIST_ENTRY NTAPI RtlFindLdrpHashTable() {
static PLIST_ENTRY list = nullptr;
if (list) return list;
PLIST_ENTRY head = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList, entry = head->Flink;
PLDR_DATA_TABLE_ENTRY CurEntry = nullptr;
while (head != entry) {
CurEntry = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, LDR_DATA_TABLE_ENTRY::InInitializationOrderLinks);
entry = entry->Flink;
if (CurEntry->HashLinks.Flink == &CurEntry->HashLinks)continue;
list = CurEntry->HashLinks.Flink;
if (list->Flink == &CurEntry->HashLinks) {
list = (decltype(list))((size_t)CurEntry->HashLinks.Flink - LdrHashEntry(CurEntry->BaseDllName) * sizeof(_LIST_ENTRY));
break;
}
list = nullptr;
}
return list;
}
size_t NTAPI LdrpDataTableEntrySize() {
static size_t size = 0;
if (size)return size;
switch (NtWindowsVersion()) {
case xp:return size = sizeof(LDR_DATA_TABLE_ENTRY_XP);
case vista:return size = sizeof(LDR_DATA_TABLE_ENTRY_VISTA);
case win7:return size = sizeof(LDR_DATA_TABLE_ENTRY_WIN7);
case win8:return size = sizeof(LDR_DATA_TABLE_ENTRY_WIN8);
case win8_1:return size = sizeof(LDR_DATA_TABLE_ENTRY_WIN8_1);
case win10:return size = sizeof(LDR_DATA_TABLE_ENTRY_WIN10);
case win10_1:return size = sizeof(LDR_DATA_TABLE_ENTRY_WIN10_1);
case win10_2:return size = sizeof(LDR_DATA_TABLE_ENTRY_WIN10_2);
default:return size = sizeof(LDR_DATA_TABLE_ENTRY_WIN10_2);
}
}
@@ -1,5 +1,20 @@
#pragma once
#define FLAG_REFERENCE 0
#define FLAG_DEREFERENCE 1
PLDR_DATA_TABLE_ENTRY NTAPI RtlAllocateDataTableEntry(IN PVOID BaseAddress);
bool NTAPI RtlInitializeLdrDataTableEntry(OUT PLDR_DATA_TABLE_ENTRY LdrEntry, IN DWORD dwFlags, IN PVOID BaseAddress, IN UNICODE_STRING& DllBaseName, IN UNICODE_STRING& DllFullName);
bool NTAPI RtlFreeLdrDataTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry);
NTSTATUS NTAPI RtlUpdateReferenceCount(IN OUT PMEMORYMODULE pModule, IN DWORD Flags);
NTSTATUS NTAPI RtlGetReferenceCount(IN PMEMORYMODULE pModule, OUT PULONG Count);
VOID NTAPI RtlInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry);
PLDR_DATA_TABLE_ENTRY NTAPI RtlFindLdrTableEntryByHandle(PVOID BaseAddress);
PLDR_DATA_TABLE_ENTRY NTAPI RtlFindLdrTableEntryByBaseName(PCWSTR BaseName);
@@ -41,92 +56,11 @@ extern PLDR_DATA_TABLE_ENTRY const LdrpNtdllBase;
#define LDR_GET_HASH_ENTRY(x) (RtlUpcaseUnicodeChar((x)) & (LDR_HASH_TABLE_ENTRIES - 1))
#define LDR_HASH_TABLE_ENTRIES 32
//0x18 bytes (sizeof)
typedef struct _RTL_BALANCED_NODE {
union {
_RTL_BALANCED_NODE* Children[2]; //0x0
struct {
_RTL_BALANCED_NODE* Left; //0x0
_RTL_BALANCED_NODE* Right; //0x8
};
};
union {
struct {
UCHAR Red : 1; //0x10
UCHAR Balance : 2; //0x10
};
size_t ParentValue; //0x10
};
}RTL_BALANCED_NODE, * PRTL_BALANCED_NODE;
typedef struct _RTL_RB_TREE {
PRTL_BALANCED_NODE Root;
PRTL_BALANCED_NODE Min;
} RTL_RB_TREE, * PRTL_RB_TREE;
// RtlRbInsertNodeEx
VOID NTAPI RtlRbInsertNodeEx(IN PRTL_RB_TREE Tree, IN PRTL_BALANCED_NODE Parent, IN BOOLEAN Right, OUT PRTL_BALANCED_NODE Node);
// RtlRbRemoveNode
VOID NTAPI RtlRbRemoveNode(IN PRTL_RB_TREE Tree, IN PRTL_BALANCED_NODE Node);
enum _LDR_DLL_LOAD_REASON {
LoadReasonStaticDependency = 0,
LoadReasonStaticForwarderDependency = 1,
LoadReasonDynamicForwarderDependency = 2,
LoadReasonDelayloadDependency = 3,
LoadReasonDynamicLoad = 4,
LoadReasonAsImageLoad = 5,
LoadReasonAsDataLoad = 6,
LoadReasonUnknown = -1
};
//0x10 bytes (sizeof)
struct _LDR_SERVICE_TAG_RECORD {
_LDR_SERVICE_TAG_RECORD* Next; //0x0
ULONG ServiceTag; //0x8
};
//0x8 bytes (sizeof)
struct _LDRP_CSLIST {
struct _LDRP_CSLIST_DEPENDENT {
_SINGLE_LIST_ENTRY* NextDependentEntry; //0x0
struct _LDR_DDAG_NODE* DependentDdagNode;
}Dependent;
struct _LDRP_CSLIST_INCOMMING {
_SINGLE_LIST_ENTRY* NextIncommingEntry;
struct _LDR_DDAG_NODE* IncommingDdagNode;
}Incomming;
};
//0x4 bytes (sizeof)
enum _LDR_DDAG_STATE {
LdrModulesMerged = -5,
LdrModulesInitError = -4,
LdrModulesSnapError = -3,
LdrModulesUnloaded = -2,
LdrModulesUnloading = -1,
LdrModulesPlaceHolder = 0,
LdrModulesMapping = 1,
LdrModulesMapped = 2,
LdrModulesWaitingForDependencies = 3,
LdrModulesSnapping = 4,
LdrModulesSnapped = 5,
LdrModulesCondensed = 6,
LdrModulesReadyToInit = 7,
LdrModulesInitializing = 8,
LdrModulesReadyToRun = 9
};
//0x50 bytes (sizeof)
struct _LDR_DDAG_NODE {
_LIST_ENTRY Modules; //0x0
_LDR_SERVICE_TAG_RECORD* ServiceTagList; //0x10
ULONG LoadCount; //0x18
ULONG LoadWhileUnloadingCount; //0x1c
ULONG LowestLink; //0x20
_LDRP_CSLIST::_LDRP_CSLIST_DEPENDENT* Dependencies; //0x28
_LDRP_CSLIST::_LDRP_CSLIST_INCOMMING* IncomingDependencies; //0x30
_LDR_DDAG_STATE State; //0x38
_SINGLE_LIST_ENTRY CondenseLink; //0x40
ULONG PreorderNumber; //0x48
};
struct _LDR_DDAG_NODE_WIN8 {
_LIST_ENTRY Modules; //0x0
_LDR_SERVICE_TAG_RECORD* ServiceTagList; //0x10
@@ -398,16 +332,10 @@ typedef struct _LDR_DATA_TABLE_ENTRY_WIN10_2 {
UCHAR SigningLevel; //0x11c
}LDR_DATA_TABLE_ENTRY_WIN10_2, * PLDR_DATA_TABLE_ENTRY_WIN10_2;
ULONG NTAPI LdrHashEntry(IN const UNICODE_STRING& str, IN bool _xor = true);
HANDLE NTAPI RtlFindLdrpHeap();
ULONG NTAPI LdrHashEntry(IN UNICODE_STRING& str, IN bool _xor = true);
PLIST_ENTRY NTAPI RtlFindLdrpHashTable();
PVOID NTAPI RtlAllocateLdrpHeap(IN size_t size);
BOOL NTAPI RtlFreeLdrpHeap(IN PVOID buffer);
#define RtlInitializeListEntry(entry) ((entry)->Blink = (entry)->Flink = (entry))
#define RtlInitializeSingleEntry(entry) ((entry->Next = (entry)))
+1 -1
View File
@@ -2,7 +2,7 @@
#include <Windows.h>
typedef HMODULE HMEMORYMODULE;
#include "NativeFunctionsInternal.h"
#include "Loader.h"
#define MemoryModuleToModule(_hMemoryModule_) (_hMemoryModule_)
+311
View File
@@ -0,0 +1,311 @@
#include "stdafx.h"
#include <cstdlib>
static NTSTATUS NTAPI LdrMapDllMemory(IN HMEMORYMODULE ViewBase, IN DWORD dwFlags, IN PCWSTR DllName OPTIONAL,
IN PCWSTR lpFullDllName OPTIONAL, OUT PLDR_DATA_TABLE_ENTRY* DataTableEntry OPTIONAL) {
UNICODE_STRING FullDllName, BaseDllName;
PIMAGE_NT_HEADERS NtHeaders;
PLDR_DATA_TABLE_ENTRY LdrEntry;
HANDLE heap = NtCurrentPeb()->ProcessHeap;
if (!(NtHeaders = RtlImageNtHeader(ViewBase))) return STATUS_INVALID_IMAGE_FORMAT;
if (!(LdrEntry = RtlAllocateDataTableEntry(ViewBase))) return STATUS_NO_MEMORY;
if (!RtlResolveDllNameUnicodeString(DllName, lpFullDllName, &BaseDllName, &FullDllName)) {
RtlFreeHeap(heap, 0, LdrEntry);
return STATUS_NO_MEMORY;
}
if (!RtlInitializeLdrDataTableEntry(LdrEntry, dwFlags, ViewBase, BaseDllName, FullDllName)) {
RtlFreeHeap(heap, 0, LdrEntry);
RtlFreeHeap(heap, 0, BaseDllName.Buffer);
RtlFreeHeap(heap, 0, FullDllName.Buffer);
return STATUS_UNSUCCESSFUL;
}
RtlInsertMemoryTableEntry(LdrEntry);
if (DataTableEntry)*DataTableEntry = LdrEntry;
return STATUS_SUCCESS;
}
NTSTATUS NTAPI LdrLoadDllMemory(OUT HMEMORYMODULE* BaseAddress, IN LPVOID BufferAddress, IN size_t BufferSize) {
return LdrLoadDllMemoryExW(BaseAddress, nullptr, LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS, BufferAddress, BufferSize, nullptr, nullptr);
}
NTSTATUS NTAPI LdrLoadDllMemoryExW(
OUT HMEMORYMODULE* BaseAddress,
OUT PVOID* LdrEntry OPTIONAL,
IN DWORD dwFlags,
IN LPVOID BufferAddress,
IN size_t BufferSize,
IN LPCWSTR DllName OPTIONAL,
IN LPCWSTR DllFullName OPTIONAL) {
PMEMORYMODULE module = nullptr;
NTSTATUS status = STATUS_SUCCESS;
PLDR_DATA_TABLE_ENTRY ModuleEntry = nullptr;
PIMAGE_NT_HEADERS headers = nullptr;
if (BufferSize)return STATUS_INVALID_PARAMETER_5;
__try {
*BaseAddress = nullptr;
if (LdrEntry)*LdrEntry = nullptr;
if (!(dwFlags & LOAD_FLAGS_PASS_IMAGE_CHECK) && !RtlIsValidImageBuffer(BufferAddress, &BufferSize))status = STATUS_INVALID_IMAGE_FORMAT;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
if (!NT_SUCCESS(status))return status;
if (dwFlags & LOAD_FLAGS_NOT_MAP_DLL) {
dwFlags &= LOAD_FLAGS_NOT_MAP_DLL;
DllName = DllFullName = nullptr;
}
if (dwFlags & LOAD_FLAGS_USE_DLL_NAME && (!DllName || !DllFullName))return STATUS_INVALID_PARAMETER_3;
if (DllName) {
PLIST_ENTRY ListHead, ListEntry;
PLDR_DATA_TABLE_ENTRY CurEntry;
PIMAGE_NT_HEADERS h1 = RtlImageNtHeader(BufferAddress), h2 = nullptr;
if (!h1)return STATUS_INVALID_IMAGE_FORMAT;
ListEntry = (ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList)->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 (!wcsnicmp(DllName, CurEntry->BaseDllName.Buffer, (CurEntry->BaseDllName.Length / sizeof(wchar_t)) - 4) ||
!wcsnicmp(DllName, CurEntry->BaseDllName.Buffer, CurEntry->BaseDllName.Length / sizeof(wchar_t))) {
/* Let's compare their headers */
if (!(h2 = RtlImageNtHeader(CurEntry->DllBase)))continue;
if (!(module = MapMemoryModuleHandle((HMEMORYMODULE)CurEntry->DllBase)))continue;
if ((h1->OptionalHeader.SizeOfCode == h2->OptionalHeader.SizeOfCode) &&
(h1->OptionalHeader.SizeOfHeaders == h2->OptionalHeader.SizeOfHeaders)) {
/* This is our entry!, update load count and return success */
if (!module->UseReferenceCount || dwFlags & LOAD_FLAGS_NOT_USE_REFERENCE_COUNT)return STATUS_INVALID_PARAMETER_3;
RtlUpdateReferenceCount(module, FLAG_REFERENCE);
*BaseAddress = (HMEMORYMODULE)CurEntry->DllBase;
if (LdrEntry)*LdrEntry = CurEntry;
return STATUS_SUCCESS;
}
}
}
}
status = MemoryLoadLibrary(BaseAddress, BufferAddress, BufferSize);
if (!NT_SUCCESS(status) || status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)return status;
if (!(module = MapMemoryModuleHandle(*BaseAddress))) {
__fastfail(FAST_FAIL_FATAL_APP_EXIT);
DebugBreak();
ExitProcess(STATUS_INVALID_ADDRESS);
TerminateProcess(NtCurrentProcess(), STATUS_INVALID_ADDRESS);
}
module->loadFromNtLoadDllMemory = true;
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) {
do {
status = MemoryResolveImportTable(LPBYTE(*BaseAddress), headers, module);
if (!NT_SUCCESS(status))break;
status = MemorySetSectionProtection(LPBYTE(*BaseAddress), headers);
if (!NT_SUCCESS(status))break;
if (!LdrpExecuteTLS(module) || !LdrpCallInitializers(module, DLL_PROCESS_ATTACH)) {
status = STATUS_DLL_INIT_FAILED;
break;
}
} while (false);
if (!NT_SUCCESS(status)) {
MemoryFreeLibrary(*BaseAddress);
}
return status;
}
do {
status = LdrMapDllMemory(*BaseAddress, dwFlags, DllName, DllFullName, &ModuleEntry);
if (!NT_SUCCESS(status))break;
module->MappedDll = true;
status = MemoryResolveImportTable(LPBYTE(*BaseAddress), headers, module);
if (!NT_SUCCESS(status))break;
status = MemorySetSectionProtection(LPBYTE(*BaseAddress), headers);
if (!NT_SUCCESS(status))break;
if (!(dwFlags & LOAD_FLAGS_NOT_USE_REFERENCE_COUNT))module->UseReferenceCount = true;
if (!(dwFlags & LOAD_FLAGS_NOT_ADD_INVERTED_FUNCTION)) {
status = RtlInsertInvertedFunctionTable((PVOID)module->codeBase, headers->OptionalHeader.SizeOfImage);
if (!NT_SUCCESS(status)) break;
module->InsertInvertedFunctionTableEntry = true;
}
if (!(dwFlags & LOAD_FLAGS_NOT_HANDLE_TLS)) {
status = MmpHandleTlsData(ModuleEntry);
if (!NT_SUCCESS(status)) {
if (dwFlags & LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS) status = 0x7fffffff;
if (!NT_SUCCESS(status))break;
}
else {
module->TlsHandled = true;
}
}
if (dwFlags & LOAD_FLAGS_HOOK_DOT_NET) {
MmpPreInitializeHooksForDotNet();
}
if (!LdrpExecuteTLS(module) || !LdrpCallInitializers(module, DLL_PROCESS_ATTACH)) {
status = STATUS_DLL_INIT_FAILED;
break;
}
if (dwFlags & LOAD_FLAGS_HOOK_DOT_NET) {
MmpInitializeHooksForDotNet();
}
} while (false);
if (NT_SUCCESS(status)) {
if (LdrEntry)*LdrEntry = ModuleEntry;
}
else {
LdrUnloadDllMemory(*BaseAddress);
*BaseAddress = nullptr;
}
return status;
}
NTSTATUS NTAPI LdrLoadDllMemoryExA(
OUT HMEMORYMODULE* BaseAddress,
OUT PVOID* LdrEntry OPTIONAL,
IN DWORD dwFlags,
IN LPVOID BufferAddress,
IN size_t BufferSize,
IN LPCSTR DllName OPTIONAL,
IN LPCSTR DllFullName OPTIONAL){
LPWSTR _DllName = nullptr, _DllFullName = nullptr;
size_t size;
NTSTATUS status;
if (DllName) {
size = strlen(DllName) + 1;
_DllName = new wchar_t[size];
mbstowcs(_DllName, DllName, size);
}
if (DllFullName) {
size = strlen(DllFullName) + 1;
_DllFullName = new wchar_t[size];
mbstowcs(_DllFullName, DllFullName, size);
}
status = LdrLoadDllMemoryExW(BaseAddress, LdrEntry, dwFlags, BufferAddress, BufferSize, _DllName, _DllFullName);
if (_DllName)delete[]_DllName;
if (_DllFullName)delete[]_DllFullName;
return status;
}
NTSTATUS NTAPI LdrUnloadDllMemory(IN HMEMORYMODULE BaseAddress) {
__try {
ProbeForRead(BaseAddress, sizeof(size_t));
}
__except (EXCEPTION_EXECUTE_HANDLER) {
return GetExceptionCode();
}
PLDR_DATA_TABLE_ENTRY CurEntry;
ULONG count = 0;
NTSTATUS status = STATUS_SUCCESS;
PMEMORYMODULE module = MapMemoryModuleHandle(BaseAddress);
//Not a memory module loaded via LdrLoadDllMemory
if (!module || !module->loadFromNtLoadDllMemory)return STATUS_INVALID_HANDLE;
//Mapping dll failed
if (module->loadFromNtLoadDllMemory && !module->MappedDll) {
module->underUnload = true;
return MemoryFreeLibrary(BaseAddress) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
}
if (CurEntry = RtlFindLdrTableEntryByHandle(BaseAddress)) {
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(BaseAddress);
if (headers->OptionalHeader.SizeOfImage == CurEntry->SizeOfImage) {
if (module->UseReferenceCount) {
status = RtlGetReferenceCount(module, &count);
if (!NT_SUCCESS(status))return status;
}
if (!(count & ~1)) {
module->underUnload = true;
if (module->initialized) {
PDLL_STARTUP_ROUTINE((LPVOID)(module->codeBase + headers->OptionalHeader.AddressOfEntryPoint))(
(HINSTANCE)module->codeBase,
DLL_PROCESS_DETACH,
0
);
}
if (module->MappedDll) {
if (module->InsertInvertedFunctionTableEntry) {
status = RtlRemoveInvertedFunctionTable(BaseAddress);
if (!NT_SUCCESS(status))__fastfail(FAST_FAIL_CORRUPT_LIST_ENTRY);
}
if (module->TlsHandled) {
status = MmpReleaseTlsEntry(CurEntry);
if (!NT_SUCCESS(status)) __fastfail(FAST_FAIL_FATAL_APP_EXIT);
}
if (!RtlFreeLdrDataTableEntry(CurEntry))__fastfail(FAST_FAIL_FATAL_APP_EXIT);
}
if (!MemoryFreeLibrary(BaseAddress))__fastfail(FAST_FAIL_FATAL_APP_EXIT);
return STATUS_SUCCESS;
}
else {
return RtlUpdateReferenceCount(module, FLAG_DEREFERENCE);
}
}
}
return STATUS_INVALID_HANDLE;
}
__declspec(noreturn)
VOID NTAPI LdrUnloadDllMemoryAndExitThread(IN HMEMORYMODULE BaseAddress, IN DWORD dwExitCode) {
LdrUnloadDllMemory(BaseAddress);
RtlExitUserThread(dwExitCode);
}
NTSTATUS NTAPI LdrQuerySystemMemoryModuleFeatures(OUT PDWORD pFeatures) {
static DWORD features = 0;
NTSTATUS status = STATUS_SUCCESS;
PVOID pfn = nullptr;
bool value = false;
__try {
if (features) {
*pFeatures = features;
return status;
}
if (RtlFindLdrpModuleBaseAddressIndex())features |= MEMORY_FEATURE_MODULE_BASEADDRESS_INDEX;
if (RtlFindLdrpHashTable())features |= MEMORY_FEATURE_LDRP_HASH_TABLE;
if (RtlFindLdrpInvertedFunctionTable())features |= MEMORY_FEATURE_INVERTED_FUNCTION_TABLE;
features |= MEMORY_FEATURE_LDRP_HEAP | MEMORY_FEATURE_LDRP_HANDLE_TLS_DATA | MEMORY_FEATURE_LDRP_RELEASE_TLS_ENTRY;
if (features)features |= MEMORY_FEATURE_SUPPORT_VERSION;
*pFeatures = features;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
return status;
}
+43 -14
View File
@@ -29,32 +29,61 @@
<ClCompile Include="..\3rdparty\Detours\disolx86.cpp" />
<ClCompile Include="..\3rdparty\Detours\image.cpp" />
<ClCompile Include="..\3rdparty\Detours\modules.cpp" />
<ClCompile Include="Initialize.cpp" />
<ClCompile Include="LoadDllMemoryApi.cpp" />
<ClCompile Include="MemoryModule.cpp" />
<ClCompile Include="MmpDotNet.cpp" />
<ClCompile Include="MmpTls.cpp" />
<ClCompile Include="Native.cpp" />
<ClCompile Include="NativeFunctionsInternal.cpp" />
<ClCompile Include="rtlinv.cpp" />
<ClCompile Include="rtlldr.cpp" />
<ClCompile Include="rtlsearch.cpp" />
<ClCompile Include="rtltls.cpp" />
<ClCompile Include="rtlver.cpp" />
<ClCompile Include="Loader.cpp" />
<ClCompile Include="InvertedFunctionTable.cpp" />
<ClCompile Include="LdrEntry.cpp" />
<ClCompile Include="BaseAddressIndex.cpp" />
<ClCompile Include="Utils.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\3rdparty\Detours\detours.h" />
<ClInclude Include="..\3rdparty\Detours\detver.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntbcd.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntdbg.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntexapi.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntgdi.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntioapi.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntkeapi.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntldr.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntlpcapi.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntmisc.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntmmapi.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntnls.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntobapi.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntpebteb.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntpfapi.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntpnpapi.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntpoapi.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntpsapi.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntregapi.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntrtl.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntsam.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntseapi.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntsmss.h" />
<ClInclude Include="..\3rdparty\phnt\include\nttmapi.h" />
<ClInclude Include="..\3rdparty\phnt\include\nttp.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntwow64.h" />
<ClInclude Include="..\3rdparty\phnt\include\ntxcapi.h" />
<ClInclude Include="..\3rdparty\phnt\include\phnt.h" />
<ClInclude Include="..\3rdparty\phnt\include\phnt_ntdef.h" />
<ClInclude Include="..\3rdparty\phnt\include\phnt_windows.h" />
<ClInclude Include="..\3rdparty\phnt\include\subprocesstag.h" />
<ClInclude Include="..\3rdparty\phnt\include\winsta.h" />
<ClInclude Include="LoadDllMemoryApi.h" />
<ClInclude Include="MemoryModule.h" />
<ClInclude Include="MmpDotNet.h" />
<ClInclude Include="Native.h" />
<ClInclude Include="NativeFunctionsInternal.h" />
<ClInclude Include="rtlinv.h" />
<ClInclude Include="rtlldr.h" />
<ClInclude Include="rtlsearch.h" />
<ClInclude Include="rtltls.h" />
<ClInclude Include="rtlver.h" />
<ClInclude Include="MmpTls.h" />
<ClInclude Include="Loader.h" />
<ClInclude Include="BaseAddressIndex.h" />
<ClInclude Include="InvertedFunctionTable.h" />
<ClInclude Include="LdrEntry.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="Utils.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\README.md" />
+124 -34
View File
@@ -25,33 +25,21 @@
<Filter Include="Source Files\3rdparty\Detours">
<UniqueIdentifier>{10bf9b0e-09d4-473b-a4bb-d7c4cecc65b4}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\3rdparty\phnt">
<UniqueIdentifier>{e1243ce3-529c-401e-83a4-fe009cda27b1}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="MemoryModule.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Native.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NativeFunctionsInternal.cpp">
<ClCompile Include="Loader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="LoadDllMemoryApi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="rtlver.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="rtlldr.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="rtlinv.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="rtltls.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="rtlsearch.cpp">
<ClCompile Include="InvertedFunctionTable.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MmpTls.cpp">
@@ -90,33 +78,30 @@
<ClCompile Include="MmpDotNet.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="LdrEntry.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="BaseAddressIndex.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Initialize.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="MemoryModule.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Native.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NativeFunctionsInternal.h">
<ClInclude Include="Loader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="LoadDllMemoryApi.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="rtlver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="rtlldr.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="rtlinv.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="rtltls.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="rtlsearch.h">
<ClInclude Include="InvertedFunctionTable.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="stdafx.h">
@@ -131,6 +116,111 @@
<ClInclude Include="MmpDotNet.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BaseAddressIndex.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="LdrEntry.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MmpTls.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntbcd.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntdbg.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntexapi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntgdi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntioapi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntkeapi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntldr.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntlpcapi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntmisc.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntmmapi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntnls.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntobapi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntpebteb.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntpfapi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntpnpapi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntpoapi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntpsapi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntregapi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntrtl.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntsam.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntseapi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntsmss.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\nttmapi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\nttp.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntwow64.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\ntxcapi.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\phnt.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\phnt_ntdef.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\phnt_windows.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\subprocesstag.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\phnt\include\winsta.h">
<Filter>Header Files\3rdparty\phnt</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\README.md">
+9 -9
View File
@@ -33,8 +33,8 @@ FILETIME AssemblyTimes;
CRITICAL_SECTION MmpFakeHandleListLock;
LIST_ENTRY MmpFakeHandleListHead;
static BOOLEAN PreHooked = FALSE;
static BOOLEAN Initialized = FALSE;
static BOOLEAN g_PreHooked = FALSE;
static BOOLEAN g_Initialized = FALSE;
BOOL MmpIsMemoryModuleFileName(
_In_ LPCWSTR lpFileName,
@@ -82,7 +82,7 @@ VOID MmpInsertHandleEntry(
_In_ HANDLE hObject,
_In_ PVOID value,
_In_ BOOL bImageMapping = FALSE) {
auto entry = (PMMP_FAKE_HANDLE_LIST_ENTRY)RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(MMP_FAKE_HANDLE_LIST_ENTRY));
auto entry = (PMMP_FAKE_HANDLE_LIST_ENTRY)RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MMP_FAKE_HANDLE_LIST_ENTRY));
entry->hObject = hObject;
entry->value = value;
entry->bImageMapping = bImageMapping;
@@ -394,7 +394,7 @@ BOOL WINAPI MmpPreInitializeHooksForDotNet() {
EnterCriticalSection(NtCurrentPeb()->FastPebLock);
if (!PreHooked) {
if (!g_PreHooked) {
HMODULE hModule = LoadLibraryW(L"mscoree.dll");
if (hModule) {
OriginGetFileVersion2 = (GetFileVersion_T)GetProcAddress(hModule, "GetFileVersion");
@@ -422,14 +422,14 @@ BOOL WINAPI MmpPreInitializeHooksForDotNet() {
DetourTransactionCommit();
PreHooked = TRUE;
g_PreHooked = TRUE;
}
}
}
LeaveCriticalSection(NtCurrentPeb()->FastPebLock);
return PreHooked;
return g_PreHooked;
}
BOOL WINAPI MmpInitializeHooksForDotNet() {
@@ -440,17 +440,17 @@ BOOL WINAPI MmpInitializeHooksForDotNet() {
EnterCriticalSection(NtCurrentPeb()->FastPebLock);
if (!PreHooked) {
if (!g_PreHooked) {
LeaveCriticalSection(NtCurrentPeb()->FastPebLock);
return FALSE;
}
if (!Initialized) {
if (!g_Initialized) {
DetourTransactionBegin();
DetourUpdateThread(NtCurrentThread());
DetourAttach((PVOID*)&OriginGetFileVersion1, HookGetFileVersion);
DetourTransactionCommit();
Initialized = TRUE;
g_Initialized = TRUE;
}
LeaveCriticalSection(NtCurrentPeb()->FastPebLock);
+5 -30
View File
@@ -70,31 +70,6 @@ decltype(&NtCreateThreadEx) OriginNtCreateThreadEx = NtCreateThreadEx;
decltype(&NtSetInformationProcess) OriginNtSetInformationProcess = NtSetInformationProcess;
decltype(&LdrShutdownThread) OriginLdrShutdownThread = LdrShutdownThread;
typedef struct _THREAD_TLS_INFORMATION {
ULONG Flags;
union {
PVOID* TlsVector;
PVOID TlsModulePointer;
};
HANDLE ThreadId;
} THREAD_TLS_INFORMATION, * PTHREAD_TLS_INFORMATION;
typedef struct _PROCESS_TLS_INFORMATION {
ULONG Reserved;
PROCESS_TLS_INFORMATION_TYPE OperationType;
ULONG ThreadDataCount;
union {
ULONG TlsIndex;
ULONG TlsVectorLength;
};
THREAD_TLS_INFORMATION ThreadData[ANYSIZE_ARRAY];
} PROCESS_TLS_INFORMATION, * PPROCESS_TLS_INFORMATION;
typedef struct _THREAD_CONTEXT {
PTHREAD_START_ROUTINE ThreadStartRoutine;
LPVOID ThreadParameter;
@@ -304,7 +279,7 @@ NTSTATUS NTAPI HookNtCreateThread(
ProcessHandle,
ClientId,
&Context,
InitialTeb,
(PINITIAL_TEB)InitialTeb,
CreateSuspended
);
if (!NT_SUCCESS(status)) {
@@ -345,7 +320,7 @@ NTSTATUS NTAPI HookNtCreateThreadEx(
ZeroBits,
StackSize,
MaximumStackSize,
AttributeList
(PPS_ATTRIBUTE_LIST)AttributeList
);
if (!NT_SUCCESS(status)) {
RtlFreeHeap(RtlProcessHeap(), 0, Context);
@@ -462,7 +437,7 @@ BOOL NTAPI PreHookNtSetInformationProcess() {
status = NtSetInformationProcess(
NtCurrentProcess(),
ProcessResourceManagement,
PROCESSINFOCLASS::ProcessTlsInformation,
ProcessTlsInformation,
ProcessTlsInformationLength
);
@@ -497,7 +472,7 @@ NTSTATUS NTAPI HookNtSetInformationProcess(
_In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,
_In_ ULONG ProcessInformationLength) {
if (ProcessInformationClass != ProcessResourceManagement) {
if (ProcessInformationClass != ProcessTlsInformation) {
return OriginNtSetInformationProcess(
ProcessHandle,
ProcessInformationClass,
@@ -807,7 +782,7 @@ NTSTATUS NTAPI MmpHandleTlsData(_In_ PLDR_DATA_TABLE_ENTRY lpModuleEntry) {
status = NtSetInformationProcess(
nullptr, // hack
ProcessResourceManagement,
PROCESSINFOCLASS::ProcessTlsInformation,
ProcessTlsInformation,
Length
);
+5
View File
@@ -0,0 +1,5 @@
#pragma once
NTSTATUS NTAPI MmpReleaseTlsEntry(PLDR_DATA_TABLE_ENTRY lpModuleEntry);
NTSTATUS NTAPI MmpHandleTlsData(PLDR_DATA_TABLE_ENTRY lpModuleEntry);
-52
View File
@@ -1,52 +0,0 @@
#include "stdafx.h"
#pragma warning(disable:6387)
#pragma warning(disable:26812)
#pragma comment(lib,"ntdll.lib")
FARPROC NTAPI RtlGetNtProcAddress(LPCSTR func_name) {
return GetProcAddress(GetModuleHandleA("ntdll.dll"), func_name);
}
WCHAR NTAPI RtlUpcaseUnicodeChar(IN WCHAR Source) {
USHORT Offset;
if (Source < 'a') return Source;
if (Source <= 'z') return (Source - ('a' - 'A'));
Offset = 0;
return Source + (SHORT)Offset;
}
VOID NTAPI RtlGetNtVersionNumbers(OUT DWORD* MajorVersion, OUT DWORD* MinorVersion, OUT DWORD* BuildNumber) {
static DWORD Versions[3]{ 0 };
static auto _RtlGetNtVersionNumbers = (decltype(&RtlGetNtVersionNumbers))(RtlGetNtProcAddress("RtlGetNtVersionNumbers"));
if (Versions[0] || !_RtlGetNtVersionNumbers) goto ret;
_RtlGetNtVersionNumbers(Versions, Versions + 1, Versions + 2);
if (Versions[2] & 0xf0000000)Versions[2] &= 0xffff;
ret:
if (MajorVersion)*MajorVersion = Versions[0];
if (MinorVersion)*MinorVersion = Versions[1];
if (BuildNumber)*BuildNumber = Versions[2];
return;
}
BOOLEAN NTAPI VirtualAccessCheckNoException(LPCVOID pBuffer, size_t size, ACCESS_MASK protect) {
if (size) {
MEMORY_BASIC_INFORMATION mbi{};
SIZE_T len = 0;
if (!NT_SUCCESS(NtQueryVirtualMemory(NtCurrentProcess(), const_cast<PVOID>(pBuffer), MemoryBasicInformation, &mbi, sizeof(mbi), &len)) ||
!(mbi.Protect & protect)) {
return FALSE;
}
}
return TRUE;
}
BOOLEAN NTAPI VirtualAccessCheck(LPCVOID pBuffer, size_t size, ACCESS_MASK protect) {
if (!VirtualAccessCheckNoException(pBuffer, size, protect)) {
RtlRaiseStatus(STATUS_ACCESS_VIOLATION);
return FALSE;
}
return TRUE;
}
File diff suppressed because it is too large Load Diff
-824
View File
@@ -1,824 +0,0 @@
#include "stdafx.h"
#include <random>
typedef BOOL(WINAPI* PDLL_STARTUP_ROUTINE)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
static PRTL_RB_TREE NTAPI RtlFindLdrpModuleBaseAddressIndex() {
static PRTL_RB_TREE LdrpModuleBaseAddressIndex = nullptr;
if (LdrpModuleBaseAddressIndex)return LdrpModuleBaseAddressIndex;
PLDR_DATA_TABLE_ENTRY_WIN10 nt10 = decltype(nt10)(RtlFindNtdllLdrEntry());
PRTL_BALANCED_NODE node = nullptr;
if (!nt10 || !RtlIsWindowsVersionOrGreater(6, 2, 0))return nullptr;
node = &nt10->BaseAddressIndexNode;
while (node->ParentValue & (~7)) node = decltype(node)(node->ParentValue & (~7));
if (!node->Red) {
BYTE count = 0;
PRTL_RB_TREE tmp = nullptr;
SEARCH_CONTEXT SearchContext{};
SearchContext.MemoryBuffer = &node;
SearchContext.BufferLength = sizeof(size_t);
while (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection((HMODULE)nt10->DllBase, ".data", &SearchContext))) {
if (count++)return nullptr;
tmp = (decltype(tmp))SearchContext.MemoryBlockInSection;
}
if (count && tmp && tmp->Root && tmp->Min) {
LdrpModuleBaseAddressIndex = tmp;
}
}
return LdrpModuleBaseAddressIndex;
}
static NTSTATUS NTAPI RtlInsertModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTRY DataTableEntry, IN PVOID BaseAddress) {
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));
bool bRight = false;
const auto i = offsetof(LDR_DATA_TABLE_ENTRY_WIN8, BaseAddressIndexNode);
while (true) {
if (BaseAddress < LdrNode->DllBase) {
if (!LdrNode->BaseAddressIndexNode.Left)break;
LdrNode = decltype(LdrNode)((size_t)LdrNode->BaseAddressIndexNode.Left - offsetof(LDR_DATA_TABLE_ENTRY_WIN8, BaseAddressIndexNode));
}
else if (BaseAddress > LdrNode->DllBase) {
if (!LdrNode->BaseAddressIndexNode.Right) {
bRight = true;
break;
}
LdrNode = decltype(LdrNode)((size_t)LdrNode->BaseAddressIndexNode.Right - offsetof(LDR_DATA_TABLE_ENTRY_WIN8, BaseAddressIndexNode));
}
else {
LdrNode->DdagNode->LoadCount++;
if (RtlIsWindowsVersionOrGreater(10, 0, 0)) {
PLDR_DATA_TABLE_ENTRY_WIN10(LdrNode)->ReferenceCount++;
}
return STATUS_SUCCESS;
}
}
RtlRbInsertNodeEx(LdrpModuleBaseAddressIndex, &LdrNode->BaseAddressIndexNode, bRight, &PLDR_DATA_TABLE_ENTRY_WIN8(DataTableEntry)->BaseAddressIndexNode);
return STATUS_SUCCESS;
}
static NTSTATUS NTAPI RtlRemoveModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTRY DataTableEntry) {
static auto tree{ RtlFindLdrpModuleBaseAddressIndex() };
if (!tree->Root)return STATUS_UNSUCCESSFUL;
RtlRbRemoveNode(tree, &PLDR_DATA_TABLE_ENTRY_WIN8(DataTableEntry)->BaseAddressIndexNode);
return STATUS_SUCCESS;
}
static NTSTATUS NTAPI RtlFreeDependencies(IN PLDR_DATA_TABLE_ENTRY_WIN10 LdrEntry) {
_LDR_DDAG_NODE* DependentDdgeNode = nullptr;
PLDR_DATA_TABLE_ENTRY_WIN10 ModuleEntry = nullptr;
_LDRP_CSLIST* head = (decltype(head))LdrEntry->DdagNode->Dependencies, *entry = head;
const static bool IsWin8 = RtlIsWindowsVersionInScope(6, 2, 0, 6, 3, -1);
if (!LdrEntry->DdagNode->Dependencies)return STATUS_SUCCESS;
//find all dependencies and free
do {
DependentDdgeNode = entry->Dependent.DependentDdagNode;
if (DependentDdgeNode->Modules.Flink->Flink != &DependentDdgeNode->Modules) __fastfail(FAST_FAIL_CORRUPT_LIST_ENTRY);
ModuleEntry = decltype(ModuleEntry)((size_t)DependentDdgeNode->Modules.Flink - offsetof(_LDR_DATA_TABLE_ENTRY_WIN8, NodeModuleLink));
if (ModuleEntry->DdagNode != DependentDdgeNode) __fastfail(FAST_FAIL_CORRUPT_LIST_ENTRY);
if (!DependentDdgeNode->IncomingDependencies) __fastfail(FAST_FAIL_CORRUPT_LIST_ENTRY);
_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))) __fastfail(FAST_FAIL_FATAL_APP_EXIT);
} 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);
entry = (decltype(entry))entry->Dependent.NextDependentEntry;
//free it
if (IsWin8) {
//Update win8 dep count
_LDR_DDAG_NODE_WIN8* win8_node = (decltype(win8_node))ModuleEntry->DdagNode;
if (!win8_node->DependencyCount)__fastfail(FAST_FAIL_CORRUPT_LIST_ENTRY);
--win8_node->DependencyCount;
if (!ModuleEntry->DdagNode->LoadCount && win8_node->ReferenceCount == 1 && !win8_node->DependencyCount) {
win8_node->LoadCount = 1;
LdrUnloadDll(ModuleEntry->DllBase);
}
}
else {
LdrUnloadDll(ModuleEntry->DllBase);
}
RtlFreeLdrpHeap(LdrEntry->DdagNode->Dependencies);
//lookup next dependent.
LdrEntry->DdagNode->Dependencies = (_LDRP_CSLIST::_LDRP_CSLIST_DEPENDENT*)(entry == head ? nullptr : entry);
} while (entry != head);
return STATUS_SUCCESS;
}
static bool NTAPI RtlInitializeLdrDataTableEntry(
OUT PLDR_DATA_TABLE_ENTRY LdrEntry,
IN DWORD dwFlags,
IN PVOID BaseAddress,
IN UNICODE_STRING &DllBaseName,
IN UNICODE_STRING &DllFullName) {
RtlZeroMemory(LdrEntry, LdrpDataTableEntrySize());
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(BaseAddress);
if (!headers)return false;
bool FlagsProcessed = false;
bool CorImage = false, CorIL = false;
auto& com = headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
if (com.Size && com.VirtualAddress) {
CorImage = true;
auto cor = PIMAGE_COR20_HEADER(LPBYTE(BaseAddress) + com.VirtualAddress);
if (cor->Flags & ReplacesCorHdrNumericDefines::COMIMAGE_FLAGS_ILONLY) {
CorIL = true;
}
}
switch (NtWindowsVersion()) {
case win10:
case win10_1:
case win10_2: {
auto entry = (PLDR_DATA_TABLE_ENTRY_WIN10)LdrEntry;
entry->ReferenceCount = 1;
}
case win8:
case win8_1: {
auto entry = (PLDR_DATA_TABLE_ENTRY_WIN8)LdrEntry;
const static bool IsWin8 = RtlIsWindowsVersionInScope(6, 2, 0, 6, 3, -1);
NtQuerySystemTime(&entry->LoadTime);
entry->OriginalBase = headers->OptionalHeader.ImageBase;
entry->BaseNameHashValue = LdrHashEntry(DllBaseName, false);
entry->LoadReason = LoadReasonDynamicLoad;
if (!NT_SUCCESS(RtlInsertModuleBaseAddressIndexNode(LdrEntry, BaseAddress)))return false;
if (!(entry->DdagNode = (decltype(entry->DdagNode))
RtlAllocateLdrpHeap(IsWin8 ? sizeof(_LDR_DDAG_NODE_WIN8) : sizeof(_LDR_DDAG_NODE))))return false;
//RtlInitializeListEntry(&entry->NodeModuleLink);
//RtlInitializeListEntry(&entry->DdagNode->Modules);
//RtlInitializeSingleEntry(&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 = 1;
if (IsWin8) ((_LDR_DDAG_NODE_WIN8*)(entry->DdagNode))->ReferenceCount = 1;
entry->ImageDll = entry->LoadNotificationsSent = entry->EntryProcessed =
entry->InLegacyLists = entry->InIndexes = entry->ProcessAttachCalled = true;
entry->InExceptionTable = !(dwFlags & LOAD_FLAGS_NOT_ADD_INVERTED_FUNCTION);
entry->CorImage = CorImage;
entry->CorILOnly = CorIL;
FlagsProcessed = true;
}
case win7: {
if (LdrpDataTableEntrySize() == sizeof(LDR_DATA_TABLE_ENTRY_WIN7)) {
auto entry = (PLDR_DATA_TABLE_ENTRY_WIN7)LdrEntry;
entry->OriginalBase = headers->OptionalHeader.ImageBase;
NtQuerySystemTime(&entry->LoadTime);
}
}
case vista: {
if (LdrpDataTableEntrySize() == sizeof(LDR_DATA_TABLE_ENTRY_VISTA) ||
LdrpDataTableEntrySize() == sizeof(LDR_DATA_TABLE_ENTRY_WIN7)) {
auto entry = (PLDR_DATA_TABLE_ENTRY_VISTA)LdrEntry;
RtlInitializeListEntry(&entry->ForwarderLinks);
RtlInitializeListEntry(&entry->StaticLinks);
RtlInitializeListEntry(&entry->ServiceTagLinks);
}
}
case xp: {
LdrEntry->DllBase = BaseAddress;
LdrEntry->SizeOfImage = headers->OptionalHeader.SizeOfImage;
LdrEntry->TimeDateStamp = headers->FileHeader.TimeDateStamp;
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;
if (CorImage)LdrEntry->Flags |= LDRP_COR_IMAGE;
}
RtlInitializeListEntry(&LdrEntry->HashLinks);
return true;
}
default:return false;
}
}
static bool NTAPI RtlFreeLdrDataTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) {
switch (NtWindowsVersion()) {
case win10:
case win10_1:
case win10_2:
case win8:
case win8_1: {
auto entry = (PLDR_DATA_TABLE_ENTRY_WIN10)LdrEntry;
RtlFreeDependencies(entry);
RtlFreeLdrpHeap(entry->DdagNode);
RtlRemoveModuleBaseAddressIndexNode(LdrEntry);
}
case win7:
case vista: {
if (LdrpDataTableEntrySize() == sizeof(LDR_DATA_TABLE_ENTRY_VISTA) ||
LdrpDataTableEntrySize() == sizeof(LDR_DATA_TABLE_ENTRY_WIN7)) {
PLDR_DATA_TABLE_ENTRY_VISTA entry = (decltype(entry))LdrEntry;
PLIST_ENTRY head = &entry->ForwarderLinks, next = head->Flink;
while (head != next) {
PLDR_DATA_TABLE_ENTRY dep = *(decltype(&dep))((size_t*)next + 2);
LdrUnloadDll(dep->DllBase);
next = next->Flink;
RtlFreeLdrpHeap(next->Blink);
}
}
}
case xp: {
RtlFreeLdrpHeap(LdrEntry->BaseDllName.Buffer);
RtlFreeLdrpHeap(LdrEntry->FullDllName.Buffer);
RemoveEntryList(&LdrEntry->InLoadOrderLinks);
RemoveEntryList(&LdrEntry->InMemoryOrderLinks);
RemoveEntryList(&LdrEntry->InInitializationOrderLinks);
RemoveEntryList(&LdrEntry->HashLinks);
RtlFreeLdrpHeap(LdrEntry);
return true;
}
default:return false;
}
}
#define FLAG_REFERENCE 0
#define FLAG_DEREFERENCE 1
static NTSTATUS NTAPI RtlUpdateReferenceCount(IN OUT PMEMORYMODULE pModule, IN DWORD Flags) {
if (Flags != FLAG_REFERENCE && Flags != FLAG_DEREFERENCE)return STATUS_INVALID_PARAMETER_2;
if (Flags == FLAG_REFERENCE && pModule->dwReferenceCount != 0xffffffff)
++pModule->dwReferenceCount;
if (Flags == FLAG_DEREFERENCE && pModule->dwReferenceCount)
--pModule->dwReferenceCount;
return STATUS_SUCCESS;
}
static NTSTATUS NTAPI RtlGetReferenceCount(IN PMEMORYMODULE pModule, OUT PULONG Count) {
*Count = pModule->dwReferenceCount;
return STATUS_SUCCESS;
}
static bool NTAPI RtlResolveDllNameUnicodeString(
IN PCWSTR DllName OPTIONAL, IN PCWSTR DllFullName OPTIONAL,
OUT PUNICODE_STRING BaseDllName, OUT PUNICODE_STRING FullDllName) {
std::random_device random;
size_t Length = 0;
size_t FullLength = 0;
PWSTR _DllName = nullptr, _DllFullName = _DllName;
bool result = false;
if (DllName) {
bool add = false;
if ((Length = wcslen(DllName)) <= 4 || wcsnicmp(DllName + Length - 4, L".dll", 4)) {
add = true;
Length += 4;
}
_DllName = new wchar_t[++Length];
wcscpy(_DllName, DllName);
if (add)wcscat(_DllName, L".DLL");
}
else {
Length = 16 + 4 + 1; //hex(ULONG64) + ".dll" + '\0'
_DllName = new wchar_t[Length];
swprintf(_DllName, L"%016llX.DLL", ((ULONG64)random() << 32) | random());
}
if (DllFullName) {
bool add = false;
FullLength = wcslen(DllFullName);
if (DllName && !wcsstr(DllFullName, DllName) && wcsnicmp(DllFullName + FullLength - 4, L".dll", 4)) {
add = true;
FullLength += Length;
}
wcscpy(_DllFullName = new wchar_t[++FullLength], DllFullName);
if (add) swprintf(_DllFullName, L"%s\\%s", _DllFullName, _DllName);
}
else {
FullLength = 16 + 1 + Length; //hex(ULONG64) + '\\' + _DllName
swprintf(_DllFullName = new wchar_t[FullLength], L"%016llX\\%s", ((ULONG64)random() << 32) | random(), _DllName);
}
FullLength *= sizeof(wchar_t);
Length *= sizeof(wchar_t);
/* Allocate space for full DLL name */
if (!(FullDllName->Buffer = (PWSTR)RtlAllocateLdrpHeap(FullLength))) goto end;
FullDllName->Length = FullLength - sizeof(wchar_t);
FullDllName->MaximumLength = FullLength;
wcscpy(FullDllName->Buffer, _DllFullName);
/* Construct base DLL name */
BaseDllName->Length = Length - sizeof(wchar_t);
BaseDllName->MaximumLength = Length;
BaseDllName->Buffer = (PWSTR)RtlAllocateLdrpHeap(Length);
if (!BaseDllName->Buffer) {
RtlFreeLdrpHeap(BaseDllName->Buffer);
goto end;
}
wcscpy(BaseDllName->Buffer, _DllName);
result = true;
end:
delete[]_DllName;
delete[]_DllFullName;
return result;
}
static PLDR_DATA_TABLE_ENTRY NTAPI RtlAllocateDataTableEntry(IN PVOID BaseAddress) {
PLDR_DATA_TABLE_ENTRY LdrEntry = nullptr;
PIMAGE_NT_HEADERS NtHeader;
/* Make sure the header is valid */
if (NtHeader = RtlImageNtHeader(BaseAddress)) {
/* Allocate an entry */
LdrEntry = (decltype(LdrEntry))RtlAllocateLdrpHeap(LdrpDataTableEntrySize());
}
/* Return the entry */
return LdrEntry;
}
static VOID NTAPI RtlInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) {
PPEB_LDR_DATA PebData = NtCurrentPeb()->Ldr;
PLIST_ENTRY LdrpHashTable = RtlFindLdrpHashTable();
ULONG i;
/* Insert into hash table */
i = LdrHashEntry(LdrEntry->BaseDllName);
InsertTailList(&LdrpHashTable[i], &LdrEntry->HashLinks);
/* Insert into other lists */
InsertTailList(&PebData->InLoadOrderModuleList, &LdrEntry->InLoadOrderLinks);
InsertTailList(&PebData->InMemoryOrderModuleList, &LdrEntry->InMemoryOrderLinks);
InsertTailList(&PebData->InInitializationOrderModuleList, &LdrEntry->InInitializationOrderLinks);
}
static NTSTATUS NTAPI LdrMapDllMemory(IN HMEMORYMODULE ViewBase, IN DWORD dwFlags, IN PCWSTR DllName OPTIONAL,
IN PCWSTR lpFullDllName OPTIONAL, OUT PLDR_DATA_TABLE_ENTRY* DataTableEntry OPTIONAL) {
UNICODE_STRING FullDllName, BaseDllName;
PIMAGE_NT_HEADERS NtHeaders;
PLDR_DATA_TABLE_ENTRY LdrEntry;
if (!(NtHeaders = RtlImageNtHeader(ViewBase))) return STATUS_INVALID_IMAGE_FORMAT;
if (!(LdrEntry = RtlAllocateDataTableEntry(ViewBase))) return STATUS_NO_MEMORY;
if (!RtlResolveDllNameUnicodeString(DllName, lpFullDllName, &BaseDllName, &FullDllName)) {
RtlFreeLdrpHeap(LdrEntry);
return STATUS_NO_MEMORY;
}
if (!RtlInitializeLdrDataTableEntry(LdrEntry, dwFlags, ViewBase, BaseDllName, FullDllName)) {
RtlFreeLdrpHeap(LdrEntry);
RtlFreeLdrpHeap(BaseDllName.Buffer);
RtlFreeLdrpHeap(FullDllName.Buffer);
return STATUS_UNSUCCESSFUL;
}
RtlInsertMemoryTableEntry(LdrEntry);
if (DataTableEntry)*DataTableEntry = LdrEntry;
return STATUS_SUCCESS;
}
#ifndef _INLINE_INTERNALS
static __forceinline WORD CalcCheckSum(DWORD StartValue, LPVOID BaseAddress, DWORD WordCount) {
LPWORD Ptr = (LPWORD)BaseAddress;
DWORD Sum = StartValue;
for (DWORD i = 0; i < WordCount; i++) {
Sum += *Ptr;
if (HIWORD(Sum) != 0) Sum = LOWORD(Sum) + HIWORD(Sum);
Ptr++;
}
return (WORD)(LOWORD(Sum) + HIWORD(Sum));
}
BOOLEAN __forceinline WINAPI CheckSumBufferedFile(LPVOID BaseAddress, DWORD BufferLength) {
PIMAGE_NT_HEADERS header = RtlImageNtHeader(BaseAddress);
DWORD CalcSum = CalcCheckSum(0, BaseAddress, (BufferLength + 1) / sizeof(WORD));
DWORD HdrSum = header->OptionalHeader.CheckSum;
if (!HdrSum)return TRUE;
if (!header) return FALSE;
if (LOWORD(CalcSum) >= LOWORD(HdrSum)) CalcSum -= LOWORD(HdrSum);
else CalcSum = ((LOWORD(CalcSum) - LOWORD(HdrSum)) & 0xFFFF) - 1;
if (LOWORD(CalcSum) >= HIWORD(HdrSum)) CalcSum -= HIWORD(HdrSum);
else CalcSum = ((LOWORD(CalcSum) - HIWORD(HdrSum)) & 0xFFFF) - 1;
CalcSum += BufferLength;
return HdrSum == CalcSum;
}
#endif
BOOLEAN NTAPI RtlIsValidImageBuffer(
_In_ PVOID Buffer,
_Out_opt_ size_t* Size) {
BOOLEAN result = FALSE;
__try {
if (Size)*Size = 0;
union {
PIMAGE_NT_HEADERS32 nt32;
PIMAGE_NT_HEADERS64 nt64;
PIMAGE_NT_HEADERS nt;
}headers;
headers.nt = RtlImageNtHeader(Buffer);
PIMAGE_SECTION_HEADER sections = nullptr;
size_t SizeofImage = 0;
if (!headers.nt) {
return FALSE;
}
switch (headers.nt->OptionalHeader.Magic) {
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
sections = PIMAGE_SECTION_HEADER((char*)&headers.nt32->OptionalHeader + headers.nt32->FileHeader.SizeOfOptionalHeader);
SizeofImage = headers.nt32->OptionalHeader.SizeOfHeaders;
ProbeForRead(sections, headers.nt32->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
for (WORD i = 0; i < headers.nt32->FileHeader.NumberOfSections; ++i, ++sections)
SizeofImage += sections->SizeOfRawData;
//Signature size
SizeofImage += headers.nt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
break;
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
sections = PIMAGE_SECTION_HEADER((char*)&headers.nt64->OptionalHeader + headers.nt64->FileHeader.SizeOfOptionalHeader);
SizeofImage = headers.nt64->OptionalHeader.SizeOfHeaders;
ProbeForRead(sections, headers.nt64->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
for (WORD i = 0; i < headers.nt64->FileHeader.NumberOfSections; ++i, ++sections)
SizeofImage += sections->SizeOfRawData;
SizeofImage += headers.nt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
break;
default:
return FALSE;
}
IMAGE_FIRST_SECTION(headers.nt32);
ProbeForRead(Buffer, SizeofImage);
if (Size)*Size = SizeofImage;
result = CheckSumBufferedFile(Buffer, SizeofImage);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError(RtlNtStatusToDosError(GetExceptionCode()));
}
return result;
}
BOOL NTAPI LdrpExecuteTLS(PMEMORYMODULE module) {
unsigned char* codeBase = module->codeBase;
PIMAGE_TLS_DIRECTORY tls;
PIMAGE_TLS_CALLBACK* callback;
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(codeBase);
PIMAGE_DATA_DIRECTORY directory = &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
if (directory->VirtualAddress == 0) return TRUE;
tls = (PIMAGE_TLS_DIRECTORY)(codeBase + directory->VirtualAddress);
callback = (PIMAGE_TLS_CALLBACK*)tls->AddressOfCallBacks;
if (callback) {
while (*callback) {
(*callback)((LPVOID)codeBase, DLL_PROCESS_ATTACH, nullptr);
callback++;
}
}
return TRUE;
}
BOOL NTAPI LdrpCallInitializers(PMEMORYMODULE module, DWORD dwReason) {
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(module->codeBase);
if (headers->OptionalHeader.AddressOfEntryPoint) {
__try {
// notify library about attaching to process
if (((PDLL_STARTUP_ROUTINE)(module->codeBase + headers->OptionalHeader.AddressOfEntryPoint))((HINSTANCE)module->codeBase, dwReason, 0)) {
module->initialized = TRUE;
return TRUE;
}
SetLastError(ERROR_DLL_INIT_FAILED);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError(RtlNtStatusToDosError(GetExceptionCode()));
}
return FALSE;
}
return TRUE;
}
NTSTATUS NTAPI LdrLoadDllMemory(OUT HMEMORYMODULE* BaseAddress, IN LPVOID BufferAddress, IN size_t BufferSize) {
return LdrLoadDllMemoryExW(BaseAddress, nullptr, LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS, BufferAddress, BufferSize, nullptr, nullptr);
}
NTSTATUS NTAPI LdrLoadDllMemoryExW(
OUT HMEMORYMODULE* BaseAddress,
OUT PVOID* LdrEntry OPTIONAL,
IN DWORD dwFlags,
IN LPVOID BufferAddress,
IN size_t BufferSize,
IN LPCWSTR DllName OPTIONAL,
IN LPCWSTR DllFullName OPTIONAL) {
PMEMORYMODULE module = nullptr;
NTSTATUS status = STATUS_SUCCESS;
PLDR_DATA_TABLE_ENTRY ModuleEntry = nullptr;
PIMAGE_NT_HEADERS headers = nullptr;
if (BufferSize)return STATUS_INVALID_PARAMETER_5;
__try {
*BaseAddress = nullptr;
if (LdrEntry)*LdrEntry = nullptr;
if (!(dwFlags & LOAD_FLAGS_PASS_IMAGE_CHECK) && !RtlIsValidImageBuffer(BufferAddress, &BufferSize))status = STATUS_INVALID_IMAGE_FORMAT;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
if (!NT_SUCCESS(status))return status;
if (dwFlags & LOAD_FLAGS_NOT_MAP_DLL) {
dwFlags &= LOAD_FLAGS_NOT_MAP_DLL;
DllName = DllFullName = nullptr;
}
if (dwFlags & LOAD_FLAGS_USE_DLL_NAME && (!DllName || !DllFullName))return STATUS_INVALID_PARAMETER_3;
if (DllName) {
PLIST_ENTRY ListHead, ListEntry;
PLDR_DATA_TABLE_ENTRY CurEntry;
PIMAGE_NT_HEADERS h1 = RtlImageNtHeader(BufferAddress), h2 = nullptr;
if (!h1)return STATUS_INVALID_IMAGE_FORMAT;
ListEntry = (ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList)->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 (!wcsnicmp(DllName, CurEntry->BaseDllName.Buffer, (CurEntry->BaseDllName.Length / sizeof(wchar_t)) - 4) ||
!wcsnicmp(DllName, CurEntry->BaseDllName.Buffer, CurEntry->BaseDllName.Length / sizeof(wchar_t))) {
/* Let's compare their headers */
if (!(h2 = RtlImageNtHeader(CurEntry->DllBase)))continue;
if (!(module = MapMemoryModuleHandle((HMEMORYMODULE)CurEntry->DllBase)))continue;
if ((h1->OptionalHeader.SizeOfCode == h2->OptionalHeader.SizeOfCode) &&
(h1->OptionalHeader.SizeOfHeaders == h2->OptionalHeader.SizeOfHeaders)) {
/* This is our entry!, update load count and return success */
if (!module->UseReferenceCount || dwFlags & LOAD_FLAGS_NOT_USE_REFERENCE_COUNT)return STATUS_INVALID_PARAMETER_3;
RtlUpdateReferenceCount(module, FLAG_REFERENCE);
*BaseAddress = (HMEMORYMODULE)CurEntry->DllBase;
if (LdrEntry)*LdrEntry = CurEntry;
return STATUS_SUCCESS;
}
}
}
}
status = MemoryLoadLibrary(BaseAddress, BufferAddress, BufferSize);
if (!NT_SUCCESS(status) || status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)return status;
if (!(module = MapMemoryModuleHandle(*BaseAddress))) {
__fastfail(FAST_FAIL_FATAL_APP_EXIT);
DebugBreak();
ExitProcess(STATUS_INVALID_ADDRESS);
TerminateProcess(NtCurrentProcess(), STATUS_INVALID_ADDRESS);
}
module->loadFromNtLoadDllMemory = true;
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) {
do {
status = MemoryResolveImportTable(LPBYTE(*BaseAddress), headers, module);
if (!NT_SUCCESS(status))break;
status = MemorySetSectionProtection(LPBYTE(*BaseAddress), headers);
if (!NT_SUCCESS(status))break;
if (!LdrpExecuteTLS(module) || !LdrpCallInitializers(module, DLL_PROCESS_ATTACH)) {
status = STATUS_DLL_INIT_FAILED;
break;
}
} while (false);
if (!NT_SUCCESS(status)) {
MemoryFreeLibrary(*BaseAddress);
}
return status;
}
do {
status = LdrMapDllMemory(*BaseAddress, dwFlags, DllName, DllFullName, &ModuleEntry);
if (!NT_SUCCESS(status))break;
module->MappedDll = true;
status = MemoryResolveImportTable(LPBYTE(*BaseAddress), headers, module);
if (!NT_SUCCESS(status))break;
status = MemorySetSectionProtection(LPBYTE(*BaseAddress), headers);
if (!NT_SUCCESS(status))break;
if (!(dwFlags & LOAD_FLAGS_NOT_USE_REFERENCE_COUNT))module->UseReferenceCount = true;
if (!(dwFlags & LOAD_FLAGS_NOT_ADD_INVERTED_FUNCTION)) {
status = RtlInsertInvertedFunctionTable((PVOID)module->codeBase, headers->OptionalHeader.SizeOfImage);
if (!NT_SUCCESS(status)) break;
module->InsertInvertedFunctionTableEntry = true;
}
if (!(dwFlags & LOAD_FLAGS_NOT_HANDLE_TLS)) {
status = LdrpHandleTlsData(ModuleEntry);
if (!NT_SUCCESS(status)) {
if (dwFlags & LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS) status = 0x7fffffff;
if (!NT_SUCCESS(status))break;
}
else {
module->TlsHandled = true;
}
}
if (dwFlags & LOAD_FLAGS_HOOK_DOT_NET) {
MmpPreInitializeHooksForDotNet();
}
if (!LdrpExecuteTLS(module) || !LdrpCallInitializers(module, DLL_PROCESS_ATTACH)) {
status = STATUS_DLL_INIT_FAILED;
break;
}
if (dwFlags & LOAD_FLAGS_HOOK_DOT_NET) {
MmpInitializeHooksForDotNet();
}
} while (false);
if (NT_SUCCESS(status)) {
if (LdrEntry)*LdrEntry = ModuleEntry;
}
else {
LdrUnloadDllMemory(*BaseAddress);
*BaseAddress = nullptr;
}
return status;
}
NTSTATUS NTAPI LdrLoadDllMemoryExA(
OUT HMEMORYMODULE* BaseAddress,
OUT PVOID* LdrEntry OPTIONAL,
IN DWORD dwFlags,
IN LPVOID BufferAddress,
IN size_t BufferSize,
IN LPCSTR DllName OPTIONAL,
IN LPCSTR DllFullName OPTIONAL){
LPWSTR _DllName = nullptr, _DllFullName = nullptr;
size_t size;
NTSTATUS status;
if (DllName) {
size = strlen(DllName) + 1;
_DllName = new wchar_t[size];
mbstowcs(_DllName, DllName, size);
}
if (DllFullName) {
size = strlen(DllFullName) + 1;
_DllFullName = new wchar_t[size];
mbstowcs(_DllFullName, DllFullName, size);
}
status = LdrLoadDllMemoryExW(BaseAddress, LdrEntry, dwFlags, BufferAddress, BufferSize, _DllName, _DllFullName);
if (_DllName)delete[]_DllName;
if (_DllFullName)delete[]_DllFullName;
return status;
}
NTSTATUS NTAPI LdrUnloadDllMemory(IN HMEMORYMODULE BaseAddress) {
__try {
ProbeForRead(BaseAddress, sizeof(size_t));
}
__except (EXCEPTION_EXECUTE_HANDLER) {
return GetExceptionCode();
}
PLDR_DATA_TABLE_ENTRY CurEntry;
ULONG count = 0;
NTSTATUS status = STATUS_SUCCESS;
PMEMORYMODULE module = MapMemoryModuleHandle(BaseAddress);
//Not a memory module loaded via LdrLoadDllMemory
if (!module || !module->loadFromNtLoadDllMemory)return STATUS_INVALID_HANDLE;
//Mapping dll failed
if (module->loadFromNtLoadDllMemory && !module->MappedDll) {
module->underUnload = true;
return MemoryFreeLibrary(BaseAddress) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
}
if (CurEntry = RtlFindLdrTableEntryByHandle(BaseAddress)) {
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(BaseAddress);
if (headers->OptionalHeader.SizeOfImage == CurEntry->SizeOfImage) {
if (module->UseReferenceCount) {
status = RtlGetReferenceCount(module, &count);
if (!NT_SUCCESS(status))return status;
}
if (!(count & ~1)) {
module->underUnload = true;
if (module->initialized) {
PDLL_STARTUP_ROUTINE((LPVOID)(module->codeBase + headers->OptionalHeader.AddressOfEntryPoint))(
(HINSTANCE)module->codeBase,
DLL_PROCESS_DETACH,
0
);
}
if (module->MappedDll) {
if (module->InsertInvertedFunctionTableEntry) {
status = RtlRemoveInvertedFunctionTable(BaseAddress);
if (!NT_SUCCESS(status))__fastfail(FAST_FAIL_CORRUPT_LIST_ENTRY);
}
if (module->TlsHandled) {
status = LdrpReleaseTlsEntry(CurEntry);
if (!NT_SUCCESS(status)) __fastfail(FAST_FAIL_FATAL_APP_EXIT);
}
if (!RtlFreeLdrDataTableEntry(CurEntry))__fastfail(FAST_FAIL_FATAL_APP_EXIT);
}
if (!MemoryFreeLibrary(BaseAddress))__fastfail(FAST_FAIL_FATAL_APP_EXIT);
return STATUS_SUCCESS;
}
else {
return RtlUpdateReferenceCount(module, FLAG_DEREFERENCE);
}
}
}
return STATUS_INVALID_HANDLE;
}
__declspec(noreturn)
VOID NTAPI LdrUnloadDllMemoryAndExitThread(IN HMEMORYMODULE BaseAddress, IN DWORD dwExitCode) {
LdrUnloadDllMemory(BaseAddress);
RtlExitUserThread(dwExitCode);
}
NTSTATUS NTAPI LdrQuerySystemMemoryModuleFeatures(OUT PDWORD pFeatures) {
static DWORD features = 0;
NTSTATUS status = STATUS_SUCCESS;
PVOID pfn = nullptr;
bool value = false;
__try {
if (features) {
*pFeatures = features;
return status;
}
if (RtlFindLdrpModuleBaseAddressIndex())features |= MEMORY_FEATURE_MODULE_BASEADDRESS_INDEX;
if (RtlFindLdrpHeap())features |= MEMORY_FEATURE_LDRP_HEAP;
if (RtlFindLdrpHashTable())features |= MEMORY_FEATURE_LDRP_HASH_TABLE;
if (RtlFindLdrpInvertedFunctionTable())features |= MEMORY_FEATURE_INVERTED_FUNCTION_TABLE;
features |= MEMORY_FEATURE_LDRP_HANDLE_TLS_DATA | MEMORY_FEATURE_LDRP_RELEASE_TLS_ENTRY;
if (features)features |= MEMORY_FEATURE_SUPPORT_VERSION;
*pFeatures = features;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
return status;
}
+410
View File
@@ -0,0 +1,410 @@
#include "stdafx.h"
#include <random>
#pragma comment(lib,"ntdll.lib")
bool NTAPI RtlResolveDllNameUnicodeString(
IN PCWSTR DllName OPTIONAL, IN PCWSTR DllFullName OPTIONAL,
OUT PUNICODE_STRING BaseDllName, OUT PUNICODE_STRING FullDllName) {
std::random_device random;
size_t Length = 0;
size_t FullLength = 0;
PWSTR _DllName = nullptr, _DllFullName = _DllName;
HANDLE heap = NtCurrentPeb()->ProcessHeap;
bool result = false;
if (DllName) {
bool add = false;
if ((Length = wcslen(DllName)) <= 4 || wcsnicmp(DllName + Length - 4, L".dll", 4)) {
add = true;
Length += 4;
}
_DllName = new wchar_t[++Length];
wcscpy(_DllName, DllName);
if (add)wcscat(_DllName, L".DLL");
}
else {
Length = 16 + 4 + 1; //hex(ULONG64) + ".dll" + '\0'
_DllName = new wchar_t[Length];
swprintf(_DllName, L"%016llX.DLL", ((ULONG64)random() << 32) | random());
}
if (DllFullName) {
bool add = false;
FullLength = wcslen(DllFullName);
if (DllName && !wcsstr(DllFullName, DllName) && wcsnicmp(DllFullName + FullLength - 4, L".dll", 4)) {
add = true;
FullLength += Length;
}
wcscpy(_DllFullName = new wchar_t[++FullLength], DllFullName);
if (add) swprintf(_DllFullName, L"%s\\%s", _DllFullName, _DllName);
}
else {
FullLength = 16 + 1 + Length; //hex(ULONG64) + '\\' + _DllName
swprintf(_DllFullName = new wchar_t[FullLength], L"%016llX\\%s", ((ULONG64)random() << 32) | random(), _DllName);
}
FullLength *= sizeof(wchar_t);
Length *= sizeof(wchar_t);
/* Allocate space for full DLL name */
if (!(FullDllName->Buffer = (PWSTR)RtlAllocateHeap(heap, HEAP_ZERO_MEMORY, FullLength))) goto end;
FullDllName->Length = FullLength - sizeof(wchar_t);
FullDllName->MaximumLength = FullLength;
wcscpy(FullDllName->Buffer, _DllFullName);
/* Construct base DLL name */
BaseDllName->Length = Length - sizeof(wchar_t);
BaseDllName->MaximumLength = Length;
BaseDllName->Buffer = (PWSTR)RtlAllocateHeap(heap, HEAP_ZERO_MEMORY, Length);
if (!BaseDllName->Buffer) {
RtlFreeHeap(heap, 0, BaseDllName->Buffer);
goto end;
}
wcscpy(BaseDllName->Buffer, _DllName);
result = true;
end:
delete[]_DllName;
delete[]_DllFullName;
return result;
}
BOOL NTAPI LdrpExecuteTLS(PMEMORYMODULE module) {
unsigned char* codeBase = module->codeBase;
PIMAGE_TLS_DIRECTORY tls;
PIMAGE_TLS_CALLBACK* callback;
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(codeBase);
PIMAGE_DATA_DIRECTORY directory = &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
if (directory->VirtualAddress == 0) return TRUE;
tls = (PIMAGE_TLS_DIRECTORY)(codeBase + directory->VirtualAddress);
callback = (PIMAGE_TLS_CALLBACK*)tls->AddressOfCallBacks;
if (callback) {
while (*callback) {
(*callback)((LPVOID)codeBase, DLL_PROCESS_ATTACH, nullptr);
callback++;
}
}
return TRUE;
}
BOOL NTAPI LdrpCallInitializers(PMEMORYMODULE module, DWORD dwReason) {
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(module->codeBase);
if (headers->OptionalHeader.AddressOfEntryPoint) {
__try {
// notify library about attaching to process
if (((PDLL_STARTUP_ROUTINE)(module->codeBase + headers->OptionalHeader.AddressOfEntryPoint))((HINSTANCE)module->codeBase, dwReason, 0)) {
module->initialized = TRUE;
return TRUE;
}
SetLastError(ERROR_DLL_INIT_FAILED);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError(RtlNtStatusToDosError(GetExceptionCode()));
}
return FALSE;
}
return TRUE;
}
#ifndef _WIN64
SIZE_T NTAPI _RtlCompareMemory(
const VOID* Source1,
const VOID* Source2,
SIZE_T Length) {
return decltype(&_RtlCompareMemory)(RtlGetNtProcAddress("RtlCompareMemory"))(Source1, Source2, Length);
}
#define RtlCompareMemory _RtlCompareMemory
#endif
NTSTATUS NTAPI RtlFindMemoryBlockFromModuleSection(
IN HMODULE hModule OPTIONAL,
IN LPCSTR lpSectionName OPTIONAL,
IN OUT PSEARCH_CONTEXT SearchContext) {
NTSTATUS status = STATUS_SUCCESS;
size_t begin = 0, buffer = 0;
DWORD Length = 0, bufferLength = 0;
__try {
begin = SearchContext->OutBufferPtr;
Length = SearchContext->RemainingLength;
buffer = SearchContext->InBufferPtr;
bufferLength = SearchContext->BufferLength;
if (!buffer || !bufferLength) {
SearchContext->OutBufferPtr = 0;
SearchContext->RemainingLength = 0;
return STATUS_INVALID_PARAMETER;
}
if (!begin) {
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(hModule);
PIMAGE_SECTION_HEADER section = nullptr;
if (!headers)return STATUS_INVALID_PARAMETER_1;
section = IMAGE_FIRST_SECTION(headers);
for (WORD i = 0; i < headers->FileHeader.NumberOfSections; ++i) {
if (!_stricmp(lpSectionName, (LPCSTR)section->Name)) {
begin = SearchContext->OutBufferPtr = (size_t)hModule + section->VirtualAddress;
Length = SearchContext->RemainingLength = section->Misc.VirtualSize;
break;
}
++section;
}
if (!begin || !Length || Length < bufferLength) {
SearchContext->OutBufferPtr = 0;
SearchContext->RemainingLength = 0;
return STATUS_NOT_FOUND;
}
}
else {
begin++;
Length--;
}
status = STATUS_NOT_FOUND;
for (DWORD i = 0; i < Length - bufferLength; ++begin, ++i) {
if (RtlCompareMemory((PVOID)begin, (PVOID)buffer, bufferLength) == bufferLength) {
SearchContext->OutBufferPtr = begin;
--SearchContext->RemainingLength;
return STATUS_SUCCESS;
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
SearchContext->OutBufferPtr = 0;
SearchContext->RemainingLength = 0;
return status;
}
#ifndef _WIN64
#undef RtlCompareMemory
#endif
static __forceinline WORD CalcCheckSum(DWORD StartValue, LPVOID BaseAddress, DWORD WordCount) {
LPWORD Ptr = (LPWORD)BaseAddress;
DWORD Sum = StartValue;
for (DWORD i = 0; i < WordCount; i++) {
Sum += *Ptr;
if (HIWORD(Sum) != 0) Sum = LOWORD(Sum) + HIWORD(Sum);
Ptr++;
}
return (WORD)(LOWORD(Sum) + HIWORD(Sum));
}
BOOLEAN __forceinline WINAPI CheckSumBufferedFile(LPVOID BaseAddress, DWORD BufferLength) {
PIMAGE_NT_HEADERS header = RtlImageNtHeader(BaseAddress);
DWORD CalcSum = CalcCheckSum(0, BaseAddress, (BufferLength + 1) / sizeof(WORD));
DWORD HdrSum = header->OptionalHeader.CheckSum;
if (!HdrSum)return TRUE;
if (!header) return FALSE;
if (LOWORD(CalcSum) >= LOWORD(HdrSum)) CalcSum -= LOWORD(HdrSum);
else CalcSum = ((LOWORD(CalcSum) - LOWORD(HdrSum)) & 0xFFFF) - 1;
if (LOWORD(CalcSum) >= HIWORD(HdrSum)) CalcSum -= HIWORD(HdrSum);
else CalcSum = ((LOWORD(CalcSum) - HIWORD(HdrSum)) & 0xFFFF) - 1;
CalcSum += BufferLength;
return HdrSum == CalcSum;
}
BOOLEAN NTAPI RtlIsValidImageBuffer(
_In_ PVOID Buffer,
_Out_opt_ size_t* Size) {
BOOLEAN result = FALSE;
__try {
if (Size)*Size = 0;
union {
PIMAGE_NT_HEADERS32 nt32;
PIMAGE_NT_HEADERS64 nt64;
PIMAGE_NT_HEADERS nt;
}headers;
headers.nt = RtlImageNtHeader(Buffer);
PIMAGE_SECTION_HEADER sections = nullptr;
size_t SizeofImage = 0;
if (!headers.nt) {
return FALSE;
}
switch (headers.nt->OptionalHeader.Magic) {
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
sections = PIMAGE_SECTION_HEADER((char*)&headers.nt32->OptionalHeader + headers.nt32->FileHeader.SizeOfOptionalHeader);
SizeofImage = headers.nt32->OptionalHeader.SizeOfHeaders;
ProbeForRead(sections, headers.nt32->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
for (WORD i = 0; i < headers.nt32->FileHeader.NumberOfSections; ++i, ++sections)
SizeofImage += sections->SizeOfRawData;
//Signature size
SizeofImage += headers.nt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
break;
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
sections = PIMAGE_SECTION_HEADER((char*)&headers.nt64->OptionalHeader + headers.nt64->FileHeader.SizeOfOptionalHeader);
SizeofImage = headers.nt64->OptionalHeader.SizeOfHeaders;
ProbeForRead(sections, headers.nt64->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
for (WORD i = 0; i < headers.nt64->FileHeader.NumberOfSections; ++i, ++sections)
SizeofImage += sections->SizeOfRawData;
SizeofImage += headers.nt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
break;
default:
return FALSE;
}
IMAGE_FIRST_SECTION(headers.nt32);
ProbeForRead(Buffer, SizeofImage);
if (Size)*Size = SizeofImage;
result = CheckSumBufferedFile(Buffer, SizeofImage);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError(RtlNtStatusToDosError(GetExceptionCode()));
}
return result;
}
FARPROC NTAPI RtlGetNtProcAddress(LPCSTR func_name) {
return GetProcAddress(GetModuleHandleA("ntdll.dll"), func_name);
}
VOID NTAPI RtlGetNtVersionNumbersEx(OUT DWORD* MajorVersion, OUT DWORD* MinorVersion, OUT DWORD* BuildNumber) {
static DWORD Versions[3]{ 0 };
if (Versions[0]) goto ret;
RtlGetNtVersionNumbers(Versions, Versions + 1, Versions + 2);
if (Versions[2] & 0xf0000000)Versions[2] &= 0xffff;
ret:
if (MajorVersion)*MajorVersion = Versions[0];
if (MinorVersion)*MinorVersion = Versions[1];
if (BuildNumber)*BuildNumber = Versions[2];
return;
}
BOOLEAN NTAPI VirtualAccessCheckNoException(LPCVOID pBuffer, size_t size, ACCESS_MASK protect) {
if (size) {
MEMORY_BASIC_INFORMATION mbi{};
SIZE_T len = 0;
if (!NT_SUCCESS(NtQueryVirtualMemory(NtCurrentProcess(), const_cast<PVOID>(pBuffer), MemoryBasicInformation, &mbi, sizeof(mbi), &len)) ||
!(mbi.Protect & protect)) {
return FALSE;
}
}
return TRUE;
}
BOOLEAN NTAPI VirtualAccessCheck(LPCVOID pBuffer, size_t size, ACCESS_MASK protect) {
if (!VirtualAccessCheckNoException(pBuffer, size, protect)) {
RtlRaiseStatus(STATUS_ACCESS_VIOLATION);
return FALSE;
}
return TRUE;
}
bool NTAPI RtlVerifyVersion(IN DWORD MajorVersion, IN DWORD MinorVersion OPTIONAL, IN DWORD BuildNumber OPTIONAL, IN BYTE Flags) {
DWORD Versions[3];
RtlGetNtVersionNumbersEx(Versions, Versions + 1, Versions + 2);
if (Versions[0] == MajorVersion &&
((Flags & RTL_VERIFY_FLAGS_MINOR_VERSION) ? Versions[1] == MinorVersion : true) &&
((Flags & RTL_VERIFY_FLAGS_BUILD_NUMBERS) ? Versions[2] == BuildNumber : true))return true;
return false;
}
bool NTAPI RtlIsWindowsVersionOrGreater(IN DWORD MajorVersion, IN DWORD MinorVersion, IN DWORD BuildNumber) {
static DWORD Versions[3]{};
if (!Versions[0])RtlGetNtVersionNumbersEx(Versions, Versions + 1, Versions + 2);
if (Versions[0] == MajorVersion) {
if (Versions[1] == MinorVersion) return Versions[2] >= BuildNumber;
else return (Versions[1] > MinorVersion);
}
else return Versions[0] > MajorVersion;
}
bool NTAPI RtlIsWindowsVersionInScope(
IN DWORD MinMajorVersion, IN DWORD MinMinorVersion, IN DWORD MinBuildNumber,
IN DWORD MaxMajorVersion, IN DWORD MaxMinorVersion, IN DWORD MaxBuildNumber) {
return RtlIsWindowsVersionOrGreater(MinMajorVersion, MinMinorVersion, MinBuildNumber) &&
!RtlIsWindowsVersionOrGreater(MaxMajorVersion, MaxMinorVersion, MaxBuildNumber);
}
WINDOWS_VERSION NTAPI NtWindowsVersion() {
static WINDOWS_VERSION version = null;
DWORD versions[3]{};
if (version)return version;
RtlGetNtVersionNumbersEx(versions, versions + 1, versions + 2);
switch (versions[0]) {
case 5: {
switch (versions[1]) {
case 1:return version = versions[2] == 2600 ? xp : invalid;
case 2:return version = versions[2] == 3790 ? xp : invalid;
default:break;
}
break;
}
break;
case 6: {
switch (versions[1]) {
case 0: {
switch (versions[2]) {
case 6000:
case 6001:
case 6002:
return version = vista;
default:
break;
}
break;
}
break;
case 1: {
switch (versions[2]) {
case 7600:
case 7601:
return version = win7;
default:
break;
}
break;
}
break;
case 2: {
if (versions[2] == 9200)return version = win8;
break;
}
break;
case 3: {
if (versions[2] == 9600)return version = win8_1;
break;
}
break;
default:
break;
}
break;
}
break;
case 10: {
if (versions[1])break;
switch (versions[2]) {
case 10240:
case 10586: return version = win10;
case 14393: return version = win10_1;
case 15063:
case 16299:
case 17134:
case 17763:
case 18362:return version = win10_2;
default:if (RtlIsWindowsVersionOrGreater(versions[0], versions[1], 15063))return version = win10_2;
break;
}
break;
}
break;
default:
break;
}
return version = invalid;
}
+88
View File
@@ -0,0 +1,88 @@
#pragma once
typedef struct _SEARCH_CONTEXT {
union {
IN PVOID MemoryBuffer;
size_t InBufferPtr;
};
union {
IN DWORD BufferLength;
size_t reserved0;
};
union {
OUT PVOID MemoryBlockInSection;
size_t OutBufferPtr;
};
union {
DWORD RemainingLength;
size_t reserved1;
};
}SEARCH_CONTEXT, * PSEARCH_CONTEXT;
NTSTATUS NTAPI RtlFindMemoryBlockFromModuleSection(
IN HMODULE hModule OPTIONAL,
IN LPCSTR lpSectionName OPTIONAL,
IN OUT PSEARCH_CONTEXT SearchContext
);
typedef BOOL(WINAPI* PDLL_STARTUP_ROUTINE)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
bool NTAPI RtlResolveDllNameUnicodeString(IN PCWSTR DllName OPTIONAL, IN PCWSTR DllFullName OPTIONAL, OUT PUNICODE_STRING BaseDllName, OUT PUNICODE_STRING FullDllName);
BOOL NTAPI LdrpExecuteTLS(PMEMORYMODULE module);
BOOL NTAPI LdrpCallInitializers(PMEMORYMODULE module, DWORD dwReason);
BOOLEAN NTAPI RtlIsValidImageBuffer(PVOID Buffer, size_t* Size);
FARPROC NTAPI RtlGetNtProcAddress(LPCSTR func_name);
VOID NTAPI RtlGetNtVersionNumbersEx(
OUT DWORD* MajorVersion,
OUT DWORD* MinorVersion,
OUT DWORD* BuildNumber);
BOOLEAN NTAPI VirtualAccessCheck(LPCVOID pBuffer, size_t size, ACCESS_MASK protect);
BOOLEAN NTAPI VirtualAccessCheckNoException(LPCVOID pBuffer, size_t size, ACCESS_MASK protect);
#define ProbeForRead(pBuffer, size) VirtualAccessCheck(pBuffer, size, PAGE_READONLY | PAGE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE)
#define ProbeForWrite(pBuffer, size) VirtualAccessCheck(pBuffer, size, PAGE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE)
#define ProbeForReadWrite(pBuffer, size) VirtualAccessCheck(pBuffer, size, PAGE_EXECUTE_READWRITE | PAGE_READWRITE)
#define ProbeForExecute(pBuffer, size) VirtualAccessCheck(pBuffer, size, PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
#define _ProbeForRead(pBuffer, size) VirtualAccessCheckNoException(pBuffer, size, PAGE_READONLY | PAGE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE)
#define _ProbeForWrite(pBuffer, size) VirtualAccessCheckNoException(pBuffer, size, PAGE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE)
#define _ProbeForReadWrite(pBuffer, size) VirtualAccessCheckNoException(pBuffer, size, PAGE_EXECUTE_READWRITE | PAGE_READWRITE)
#define _ProbeForExecute(pBuffer, size) VirtualAccessCheckNoException(pBuffer, size, PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
#define RtlClearBit(BitMapHeader,BitNumber) RtlClearBits((BitMapHeader),(BitNumber),1)
#define RTL_VERIFY_FLAGS_MAJOR_VERSION 0
#define RTL_VERIFY_FLAGS_MINOR_VERSION 1
#define RTL_VERIFY_FLAGS_BUILD_NUMBERS 2
#define RTL_VERIFY_FLAGS_DEFAULT RTL_VERIFY_FLAGS_MAJOR_VERSION|RTL_VERIFY_FLAGS_MINOR_VERSION|RTL_VERIFY_FLAGS_BUILD_NUMBERS
bool NTAPI RtlVerifyVersion(IN DWORD MajorVersion, IN DWORD MinorVersion OPTIONAL, IN DWORD BuildNumber OPTIONAL, IN BYTE Flags);
bool NTAPI RtlIsWindowsVersionOrGreater(IN DWORD MajorVersion, IN DWORD MinorVersion, IN DWORD BuildNumber);
bool NTAPI RtlIsWindowsVersionInScope(
IN DWORD MinMajorVersion, IN DWORD MinMinorVersion, IN DWORD MinBuildNumber,
IN DWORD MaxMajorVersion, IN DWORD MaxMinorVersion, IN DWORD MaxBuildNumber
);
typedef enum _WINDOWS_VERSION {
null,
xp,
vista,
win7,
win8,
win8_1,
win10,
win10_1,
win10_2,
invalid
}WINDOWS_VERSION;
WINDOWS_VERSION NTAPI NtWindowsVersion();
-113
View File
@@ -1,113 +0,0 @@
#include "stdafx.h"
#pragma warning(disable:4996)
PLDR_DATA_TABLE_ENTRY const LdrpNtdllBase = RtlFindLdrTableEntryByBaseName(L"ntdll.dll");
VOID NTAPI RtlRbInsertNodeEx(IN PRTL_RB_TREE Tree, IN PRTL_BALANCED_NODE Parent, IN BOOLEAN Right, OUT PRTL_BALANCED_NODE Node) {
decltype(&RtlRbInsertNodeEx)_RtlRbInsertNodeEx = decltype(_RtlRbInsertNodeEx)(RtlGetNtProcAddress("RtlRbInsertNodeEx"));
if (!_RtlRbInsertNodeEx)return;
return _RtlRbInsertNodeEx(Tree, Parent, Right, Node);
}
VOID NTAPI RtlRbRemoveNode(IN PRTL_RB_TREE Tree, IN PRTL_BALANCED_NODE Node) {
decltype(&RtlRbRemoveNode)_RtlRbRemoveNode = decltype(_RtlRbRemoveNode)(RtlGetNtProcAddress("RtlRbRemoveNode"));
if (!_RtlRbRemoveNode)return;
return _RtlRbRemoveNode(Tree, Node);
}
PLDR_DATA_TABLE_ENTRY NTAPI RtlFindLdrTableEntryByHandle(PVOID BaseAddress) {
PLIST_ENTRY ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList, ListEntry = ListHead->Flink;
PLDR_DATA_TABLE_ENTRY CurEntry;
while (ListEntry != ListHead) {
CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
ListEntry = ListEntry->Flink;
if (CurEntry->DllBase == BaseAddress) {
return CurEntry;
}
}
return nullptr;
}
PLDR_DATA_TABLE_ENTRY NTAPI RtlFindLdrTableEntryByBaseName(PCWSTR BaseName) {
PLIST_ENTRY ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList, ListEntry = ListHead->Flink;
PLDR_DATA_TABLE_ENTRY CurEntry;
while (ListEntry != ListHead) {
CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
ListEntry = ListEntry->Flink;
if (!wcsnicmp(BaseName, CurEntry->BaseDllName.Buffer, (CurEntry->BaseDllName.Length / sizeof(wchar_t)) - 4) ||
!wcsnicmp(BaseName, CurEntry->BaseDllName.Buffer, CurEntry->BaseDllName.Length / sizeof(wchar_t))) {
return CurEntry;
}
}
return nullptr;
}
ULONG NTAPI LdrHashEntry(IN const UNICODE_STRING& str, IN bool _xor) {
ULONG result = 0;
if (RtlIsWindowsVersionOrGreater(6, 2, 0)) {
RtlHashUnicodeString(&str, TRUE, HASH_STRING_ALGORITHM_DEFAULT, &result);
}
else {
for (USHORT i = 0; i < (str.Length / sizeof(wchar_t)); ++i)
result += 0x1003F * RtlUpcaseUnicodeChar(str.Buffer[i]);
}
if (_xor)result &= (LDR_HASH_TABLE_ENTRIES - 1);
return result;
}
HANDLE NTAPI RtlFindLdrpHeap() {
return RtlProcessHeap();
}
PLIST_ENTRY NTAPI RtlFindLdrpHashTable() {
static PLIST_ENTRY list = nullptr;
if (list) return list;
PLIST_ENTRY head = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList, entry = head->Flink;
PLDR_DATA_TABLE_ENTRY CurEntry = nullptr;
while (head != entry) {
CurEntry = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, LDR_DATA_TABLE_ENTRY::InInitializationOrderLinks);
entry = entry->Flink;
if (CurEntry->HashLinks.Flink == &CurEntry->HashLinks)continue;
list = CurEntry->HashLinks.Flink;
if (list->Flink == &CurEntry->HashLinks) {
list = (decltype(list))((size_t)CurEntry->HashLinks.Flink - LdrHashEntry(CurEntry->BaseDllName) * sizeof(_LIST_ENTRY));
break;
}
list = nullptr;
}
return list;
}
PVOID NTAPI RtlAllocateLdrpHeap(IN size_t size) {
HANDLE heap = RtlFindLdrpHeap();
if (!heap)return nullptr;
return RtlAllocateHeap(heap, HEAP_ZERO_MEMORY, size);
}
BOOL NTAPI RtlFreeLdrpHeap(IN PVOID buffer) {
HANDLE LdrpHeap = RtlFindLdrpHeap();
if (!LdrpHeap)return FALSE;
return RtlFreeHeap(LdrpHeap, 0, buffer);
}
size_t NTAPI LdrpDataTableEntrySize() {
static size_t size = 0;
if (size)return size;
switch (NtWindowsVersion()) {
case xp:return size = sizeof(LDR_DATA_TABLE_ENTRY_XP);
case vista:return size = sizeof(LDR_DATA_TABLE_ENTRY_VISTA);
case win7:return size = sizeof(LDR_DATA_TABLE_ENTRY_WIN7);
case win8:return size = sizeof(LDR_DATA_TABLE_ENTRY_WIN8);
case win8_1:return size = sizeof(LDR_DATA_TABLE_ENTRY_WIN8_1);
case win10:return size = sizeof(LDR_DATA_TABLE_ENTRY_WIN10);
case win10_1:return size = sizeof(LDR_DATA_TABLE_ENTRY_WIN10_1);
case win10_2:return size = sizeof(LDR_DATA_TABLE_ENTRY_WIN10_2);
default:return size = sizeof(LDR_DATA_TABLE_ENTRY_WIN10_2);
}
}
-76
View File
@@ -1,76 +0,0 @@
#include "stdafx.h"
#ifndef _WIN64
SIZE_T NTAPI _RtlCompareMemory(
const VOID* Source1,
const VOID* Source2,
SIZE_T Length) {
return decltype(&_RtlCompareMemory)(RtlGetNtProcAddress("RtlCompareMemory"))(Source1, Source2, Length);
}
#define RtlCompareMemory _RtlCompareMemory
#endif
NTSTATUS NTAPI RtlFindMemoryBlockFromModuleSection(
IN HMODULE hModule OPTIONAL,
IN LPCSTR lpSectionName OPTIONAL,
IN OUT PSEARCH_CONTEXT SearchContext) {
NTSTATUS status = STATUS_SUCCESS;
size_t begin = 0, buffer = 0;
DWORD Length = 0, bufferLength = 0;
__try {
begin = SearchContext->OutBufferPtr;
Length = SearchContext->RemainingLength;
buffer = SearchContext->InBufferPtr;
bufferLength = SearchContext->BufferLength;
if (!buffer || !bufferLength) {
SearchContext->OutBufferPtr = 0;
SearchContext->RemainingLength = 0;
return STATUS_INVALID_PARAMETER;
}
if (!begin) {
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(hModule);
PIMAGE_SECTION_HEADER section = nullptr;
if (!headers)return STATUS_INVALID_PARAMETER_1;
section = IMAGE_FIRST_SECTION(headers);
for (WORD i = 0; i < headers->FileHeader.NumberOfSections; ++i) {
if (!_stricmp(lpSectionName, (LPCSTR)section->Name)) {
begin = SearchContext->OutBufferPtr = (size_t)hModule + section->VirtualAddress;
Length = SearchContext->RemainingLength = section->Misc.VirtualSize;
break;
}
++section;
}
if (!begin || !Length || Length < bufferLength) {
SearchContext->OutBufferPtr = 0;
SearchContext->RemainingLength = 0;
return STATUS_NOT_FOUND;
}
}
else {
begin++;
Length--;
}
status = STATUS_NOT_FOUND;
for (DWORD i = 0; i < Length - bufferLength; ++begin, ++i) {
if (RtlCompareMemory((PVOID)begin, (PVOID)buffer, bufferLength) == bufferLength) {
SearchContext->OutBufferPtr = begin;
--SearchContext->RemainingLength;
return STATUS_SUCCESS;
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
SearchContext->OutBufferPtr = 0;
SearchContext->RemainingLength = 0;
return status;
}
#ifndef _WIN64
#undef RtlCompareMemory
#endif
-27
View File
@@ -1,27 +0,0 @@
#pragma once
typedef struct _SEARCH_CONTEXT {
union {
IN PVOID MemoryBuffer;
size_t InBufferPtr;
};
union {
IN DWORD BufferLength;
size_t reserved0;
};
union {
OUT PVOID MemoryBlockInSection;
size_t OutBufferPtr;
};
union {
DWORD RemainingLength;
size_t reserved1;
};
}SEARCH_CONTEXT, * PSEARCH_CONTEXT;
NTSTATUS NTAPI RtlFindMemoryBlockFromModuleSection(
IN HMODULE hModule OPTIONAL,
IN LPCSTR lpSectionName OPTIONAL,
IN OUT PSEARCH_CONTEXT SearchContext
);
-15
View File
@@ -1,15 +0,0 @@
#include "stdafx.h"
// MmpTls.cpp
NTSTATUS NTAPI MmpReleaseTlsEntry(_In_ PLDR_DATA_TABLE_ENTRY lpModuleEntry);
// MmpTls.cpp
NTSTATUS NTAPI MmpHandleTlsData(_In_ PLDR_DATA_TABLE_ENTRY lpModuleEntry);
NTSTATUS NTAPI LdrpHandleTlsData(IN PLDR_DATA_TABLE_ENTRY LdrEntry) {
return MmpHandleTlsData(LdrEntry);
}
NTSTATUS NTAPI LdrpReleaseTlsEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) {
return MmpReleaseTlsEntry(LdrEntry);
}
-6
View File
@@ -1,6 +0,0 @@
#pragma once
NTSTATUS NTAPI LdrpHandleTlsData(IN PLDR_DATA_TABLE_ENTRY LdrEntry);
NTSTATUS NTAPI LdrpReleaseTlsEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry);
-108
View File
@@ -1,108 +0,0 @@
#include "stdafx.h"
bool NTAPI RtlVerifyVersion(IN DWORD MajorVersion, IN DWORD MinorVersion OPTIONAL, IN DWORD BuildNumber OPTIONAL, IN BYTE Flags) {
DWORD Versions[3];
RtlGetNtVersionNumbers(Versions, Versions + 1, Versions + 2);
if (Versions[0] == MajorVersion &&
((Flags & RTL_VERIFY_FLAGS_MINOR_VERSION) ? Versions[1] == MinorVersion : true) &&
((Flags & RTL_VERIFY_FLAGS_BUILD_NUMBERS) ? Versions[2] == BuildNumber : true))return true;
return false;
}
bool NTAPI RtlIsWindowsVersionOrGreater(IN DWORD MajorVersion, IN DWORD MinorVersion, IN DWORD BuildNumber) {
static DWORD Versions[3]{};
if (!Versions[0])RtlGetNtVersionNumbers(Versions, Versions + 1, Versions + 2);
if (Versions[0] == MajorVersion) {
if (Versions[1] == MinorVersion) return Versions[2] >= BuildNumber;
else return (Versions[1] > MinorVersion);
}
else return Versions[0] > MajorVersion;
}
bool NTAPI RtlIsWindowsVersionInScope(
IN DWORD MinMajorVersion, IN DWORD MinMinorVersion, IN DWORD MinBuildNumber,
IN DWORD MaxMajorVersion, IN DWORD MaxMinorVersion, IN DWORD MaxBuildNumber) {
return RtlIsWindowsVersionOrGreater(MinMajorVersion, MinMinorVersion, MinBuildNumber) &&
!RtlIsWindowsVersionOrGreater(MaxMajorVersion, MaxMinorVersion, MaxBuildNumber);
}
WINDOWS_VERSION NTAPI NtWindowsVersion() {
static WINDOWS_VERSION version = null;
DWORD versions[3]{};
if (version)return version;
RtlGetNtVersionNumbers(versions, versions + 1, versions + 2);
switch (versions[0]) {
case 5: {
switch (versions[1]) {
case 1:return version = versions[2] == 2600 ? xp : invalid;
case 2:return version = versions[2] == 3790 ? xp : invalid;
default:break;
}
break;
}
break;
case 6: {
switch (versions[1]) {
case 0: {
switch (versions[2]) {
case 6000:
case 6001:
case 6002:
return version = vista;
default:
break;
}
break;
}
break;
case 1: {
switch (versions[2]) {
case 7600:
case 7601:
return version = win7;
default:
break;
}
break;
}
break;
case 2: {
if (versions[2] == 9200)return version = win8;
break;
}
break;
case 3: {
if (versions[2] == 9600)return version = win8_1;
break;
}
break;
default:
break;
}
break;
}
break;
case 10: {
if (versions[1])break;
switch (versions[2]) {
case 10240:
case 10586: return version = win10;
case 14393: return version = win10_1;
case 15063:
case 16299:
case 17134:
case 17763:
case 18362:return version = win10_2;
default:if (RtlIsWindowsVersionOrGreater(versions[0], versions[1], 15063))return version = win10_2;
break;
}
break;
}
break;
default:
break;
}
return version = invalid;
}
-31
View File
@@ -1,31 +0,0 @@
#pragma once
#define RTL_VERIFY_FLAGS_MAJOR_VERSION 0
#define RTL_VERIFY_FLAGS_MINOR_VERSION 1
#define RTL_VERIFY_FLAGS_BUILD_NUMBERS 2
#define RTL_VERIFY_FLAGS_DEFAULT RTL_VERIFY_FLAGS_MAJOR_VERSION|RTL_VERIFY_FLAGS_MINOR_VERSION|RTL_VERIFY_FLAGS_BUILD_NUMBERS
bool NTAPI RtlVerifyVersion(IN DWORD MajorVersion, IN DWORD MinorVersion OPTIONAL, IN DWORD BuildNumber OPTIONAL, IN BYTE Flags);
bool NTAPI RtlIsWindowsVersionOrGreater(IN DWORD MajorVersion, IN DWORD MinorVersion, IN DWORD BuildNumber);
bool NTAPI RtlIsWindowsVersionInScope(
IN DWORD MinMajorVersion, IN DWORD MinMinorVersion, IN DWORD MinBuildNumber,
IN DWORD MaxMajorVersion, IN DWORD MaxMinorVersion, IN DWORD MaxBuildNumber
);
typedef enum _WINDOWS_VERSION {
null,
xp,
vista,
win7,
win8,
win8_1,
win10,
win10_1,
win10_2,
invalid
}WINDOWS_VERSION;
WINDOWS_VERSION NTAPI NtWindowsVersion();
+14 -16
View File
@@ -1,38 +1,36 @@
#pragma once
#pragma warning (disable:4005)
#ifndef WIN32_NO_STATUS
#define WIN32_NO_STATUS
#include <Windows.h>
#include "../3rdparty/phnt/include/phnt_windows.h"
#include "../3rdparty/phnt/include/phnt.h"
#undef WIN32_NO_STATUS
#include <ntstatus.h>
#endif
#pragma warning (default:4005)
// offsetof()
#include <cstddef>
//memory module base support
#include "MemoryModule.h"
//nt layer support
#include "Native.h"
//memory block pattern search support
#include "rtlsearch.h"
//windows nt version support
#include "rtlver.h"
//LDR_DATA_TABLE_ENTRY
#include "rtlldr.h"
#include "LdrEntry.h"
//rtl inverted function table for exception handling
#include "rtlinv.h"
#include "InvertedFunctionTable.h"
//base address index
#include "BaseAddressIndex.h"
//tls support
#include "rtltls.h"
#include "MmpTls.h"
//DotNet support
#include "MmpDotNet.h"
//MemoryModulePP api interface
#include "NativeFunctionsInternal.h"
#include "Loader.h"
//utils
#include "Utils.h"