mirror of
https://github.com/bb107/MemoryModulePP
synced 2026-06-08 13:15:33 +00:00
279 lines
8.2 KiB
C++
279 lines
8.2 KiB
C++
#include "stdafx.h"
|
|
|
|
static NTSTATUS NTAPI LdrMapDllMemory(
|
|
_In_ HMEMORYMODULE ViewBase,
|
|
_In_ DWORD dwFlags,
|
|
_In_opt_ PCWSTR DllName,
|
|
_In_opt_ PCWSTR lpFullDllName,
|
|
_Out_opt_ PLDR_DATA_TABLE_ENTRY* DataTableEntry) {
|
|
|
|
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 (!NT_SUCCESS(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 LdrLoadDllMemoryExW(
|
|
_Out_ HMEMORYMODULE* BaseAddress,
|
|
_Out_opt_ PVOID* LdrEntry,
|
|
_In_ DWORD dwFlags,
|
|
_In_ LPVOID BufferAddress,
|
|
_In_ size_t BufferSize,
|
|
_In_opt_ LPCWSTR DllName,
|
|
_In_opt_ LPCWSTR DllFullName) {
|
|
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 (!RtlIsValidImageBuffer(BufferAddress, &BufferSize) && !(dwFlags & LOAD_FLAGS_PASS_IMAGE_CHECK))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 = &NtCurrentPeb()->Ldr->InLoadOrderModuleList, ListEntry = ListHead->Flink;
|
|
PIMAGE_NT_HEADERS h1 = RtlImageNtHeader(BufferAddress), h2 = nullptr;
|
|
if (!h1)return STATUS_INVALID_IMAGE_FORMAT;
|
|
|
|
while (ListEntry != ListHead) {
|
|
PLDR_DATA_TABLE_ENTRY 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, (DWORD)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->loadFromLdrLoadDllMemory = 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;
|
|
module->LdrEntry = ModuleEntry;
|
|
|
|
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 LdrUnloadDllMemory(_In_ HMEMORYMODULE BaseAddress) {
|
|
PLDR_DATA_TABLE_ENTRY CurEntry;
|
|
ULONG count = 0;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PMEMORYMODULE module = MapMemoryModuleHandle(BaseAddress);
|
|
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(BaseAddress);
|
|
|
|
do {
|
|
|
|
//Not a memory module loaded via LdrLoadDllMemory
|
|
if (!module || !module->loadFromLdrLoadDllMemory) {
|
|
status = STATUS_INVALID_HANDLE;
|
|
break;
|
|
}
|
|
|
|
//Mapping dll failed
|
|
if (!module->MappedDll) {
|
|
module->underUnload = true;
|
|
status = (MemoryFreeLibrary(BaseAddress) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
|
|
break;
|
|
}
|
|
|
|
CurEntry = (PLDR_DATA_TABLE_ENTRY)module->LdrEntry;
|
|
|
|
if (headers->OptionalHeader.SizeOfImage != CurEntry->SizeOfImage) __fastfail(FAST_FAIL_FATAL_APP_EXIT);
|
|
|
|
if (module->UseReferenceCount) {
|
|
status = RtlGetReferenceCount(module, &count);
|
|
if (!NT_SUCCESS(status)) break;
|
|
}
|
|
|
|
if (count & ~1) {
|
|
status = RtlUpdateReferenceCount(module, FLAG_DEREFERENCE);
|
|
break;
|
|
}
|
|
|
|
module->underUnload = true;
|
|
if (module->initialized) {
|
|
PLDR_INIT_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);
|
|
|
|
} while (false);
|
|
|
|
return status;
|
|
}
|
|
|
|
DECLSPEC_NORETURN
|
|
VOID NTAPI LdrUnloadDllMemoryAndExitThread(_In_ HMEMORYMODULE BaseAddress, _In_ DWORD dwExitCode) {
|
|
LdrUnloadDllMemory(BaseAddress);
|
|
RtlExitUserThread(dwExitCode);
|
|
}
|
|
|
|
NTSTATUS NTAPI LdrQuerySystemMemoryModuleFeatures(_Out_ PDWORD pFeatures) {
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
__try {
|
|
*pFeatures = MmpGlobalDataPtr->MmpFeatures;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
status = GetExceptionCode();
|
|
}
|
|
return status;
|
|
}
|