#include "stdafx.h" #include 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 LdrLoadDllMemory( _Out_ HMEMORYMODULE* BaseAddress, _In_ LPVOID BufferAddress, _In_ size_t Reserved) { return LdrLoadDllMemoryExW(BaseAddress, nullptr, 0, BufferAddress, Reserved, nullptr, nullptr); } 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 (!(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, (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->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_opt_ PVOID* LdrEntry, _In_ DWORD dwFlags, _In_ LPVOID BufferAddress, _In_ size_t BufferSize, _In_opt_ LPCSTR DllName, _In_opt_ LPCSTR DllFullName) { LPWSTR _DllName = nullptr, _DllFullName = nullptr; size_t size; NTSTATUS status; if (DllName) { size = strlen(DllName) + 1; _DllName = new wchar_t[size]; mbstowcs_s(nullptr, _DllName, size, DllName, size); } if (DllFullName) { size = strlen(DllFullName) + 1; _DllFullName = new wchar_t[size]; mbstowcs_s(nullptr, _DllFullName, size, DllFullName, size); } status = LdrLoadDllMemoryExW(BaseAddress, LdrEntry, dwFlags, BufferAddress, BufferSize, _DllName, _DllFullName); delete[]_DllName; 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) { NTSTATUS status = STATUS_SUCCESS; __try { *pFeatures = MmpGlobalDataPtr->MmpFeatures; } __except (EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); } return status; }