support win8.1

This commit is contained in:
Boring
2020-02-26 17:26:24 +08:00
parent e69080df11
commit 5f3472df47
11 changed files with 361 additions and 270 deletions
+38
View File
@@ -0,0 +1,38 @@
#include "LoadDllMemoryApi.h"
#include "Native.h"
HMEMORYMODULE WINAPI LoadLibraryMemory(PVOID BufferAddress) {
HMEMORYMODULE hMemoryModule = nullptr;
NTSTATUS status = NtLoadDllMemory(&hMemoryModule, BufferAddress, 0);
if (!NT_SUCCESS(status)) {
SetLastError(RtlNtStatusToDosError(status));
}
return hMemoryModule;
}
HMEMORYMODULE WINAPI LoadLibraryMemoryExA(PVOID BufferAddress, size_t Reserved, LPCSTR DllBaseName, LPCSTR DllFullName, DWORD Flags) {
HMEMORYMODULE hMemoryModule = nullptr;
NTSTATUS status = NtLoadDllMemoryExA(&hMemoryModule, nullptr, Flags, BufferAddress, Reserved, DllBaseName, DllFullName);
if (!NT_SUCCESS(status)) {
SetLastError(RtlNtStatusToDosError(status));
}
return hMemoryModule;
}
HMEMORYMODULE WINAPI LoadLibraryMemoryExW(PVOID BufferAddress, size_t Reserved, LPCWSTR DllBaseName, LPCWSTR DllFullName, DWORD Flags) {
HMEMORYMODULE hMemoryModule = nullptr;
NTSTATUS status = NtLoadDllMemoryExW(&hMemoryModule, nullptr, Flags, BufferAddress, Reserved, DllBaseName, DllFullName);
if (!NT_SUCCESS(status)) {
SetLastError(RtlNtStatusToDosError(status));
}
return hMemoryModule;
}
BOOL WINAPI FreeLibraryMemory(HMEMORYMODULE hMemoryModule) {
NTSTATUS status = NtUnloadDllMemory(hMemoryModule);
if (!NT_SUCCESS(status)) {
SetLastError(RtlNtStatusToDosError(status));
return FALSE;
}
return TRUE;
}
+24 -38
View File
@@ -1,72 +1,49 @@
#pragma once
#include <Windows.h>
typedef PVOID HMEMORYMODULE, HMEMORYRSRC;
typedef HMODULE HMEMORYMODULE;
typedef PVOID HMEMORYRSRC;
#define MemoryModuleToModule(_hMemoryModule_) (HMODULE(_hMemoryModule_))
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
//Deprecated API
#ifndef _DEPRECATED
/**
* Load DLL from memory location with the given size.
*
* All dependencies are resolved using default LoadLibrary/GetProcAddress
* calls through the Windows API.
*/
NOT_BUILD_WINDOWS_DEPRECATE
__drv_preferredFunction("NtLoadDllMemory*", "Deprecated. Use NtLoadDllMemory or NtLoadDllMemoryEx.")
__drv_preferredFunction("LoadLibraryMemory", "Deprecated. Use LoadLibraryMemory.")
HMEMORYMODULE MemoryLoadLibrary(const void*);
/**
* Get address of exported method. Supports loading both by name and by
* ordinal value.
*/
NOT_BUILD_WINDOWS_DEPRECATE
__drv_preferredFunction("GetProcAddress", "Deprecated. Use Win32API GetProcAddress.")
FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR);
/**
* Free previously loaded DLL.
*/
NOT_BUILD_WINDOWS_DEPRECATE
__drv_preferredFunction("NtUnloadDllMemory", "Deprecated. Use NtUnloadDllMemory.")
__drv_preferredFunction("FreeLibrayMemory", "Deprecated. Use FreeLibrayMemory.")
bool MemoryFreeLibrary(HMEMORYMODULE);
/**
* Find the location of a resource with the specified type and name.
*/
NOT_BUILD_WINDOWS_DEPRECATE
__drv_preferredFunction("FindResource", "Deprecated. Use Win32API FindResource.")
HMEMORYRSRC MemoryFindResource(HMEMORYMODULE, LPCTSTR, LPCTSTR);
/**
* Find the location of a resource with the specified type, name and language.
*/
NOT_BUILD_WINDOWS_DEPRECATE
__drv_preferredFunction("FindResourceEx", "Deprecated. Use Win32API FindResourceEx.")
HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE, LPCTSTR, LPCTSTR, WORD);
/**
* Get the size of the resource in bytes.
*/
NOT_BUILD_WINDOWS_DEPRECATE
__drv_preferredFunction("SizeofResource", "Deprecated. Use Win32API SizeofResource.")
DWORD MemorySizeofResource(HMEMORYMODULE, HMEMORYRSRC);
/**
* Get a pointer to the contents of the resource.
*/
NOT_BUILD_WINDOWS_DEPRECATE
__drv_preferredFunction("LoadResource", "Deprecated. Use Win32API LoadResource.")
LPVOID MemoryLoadResource(HMEMORYMODULE, HMEMORYRSRC);
/**
* Load a string resource.
*/
NOT_BUILD_WINDOWS_DEPRECATE
__drv_preferredFunction("LoadString*", "Deprecated. Use Win32API LoadStringA or LoadStringW.")
int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int);
/**
* Load a string resource with a given language.
*/
NOT_BUILD_WINDOWS_DEPRECATE
__drv_preferredFunction("LoadString*", "Deprecated. Use Win32API LoadStringA or LoadStringW.")
int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD);
@@ -104,6 +81,9 @@ NTSTATUS NTAPI NtLoadDllMemory(
//If this flag is specified, this routine will not fail even if the call to LdrpTlsData fails.
#define LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS 0x20000000
//If this flag is specified, the input image buffer will not be checked before loading.
#define LOAD_FLAGS_PASS_IMAGE_CHECK 0x40000000
//If this flag is specified, exception handling will not be supported.
#define LOAD_FLAGS_NOT_ADD_INVERTED_FUNCTION 0x00000001
@@ -157,15 +137,21 @@ extern "C" {
__declspec(noreturn) VOID NTAPI NtUnloadDllMemoryAndExitThread(IN HMEMORYMODULE BaseAddress, IN DWORD dwExitCode);
}
#define LoadLibraryMemory NtLoadDllMemory
#define FreeLibraryMemory NtUnloadDllMemory
HMEMORYMODULE WINAPI LoadLibraryMemory(PVOID BufferAddress);
HMEMORYMODULE WINAPI LoadLibraryMemoryExA(PVOID BufferAddress, size_t Reserved, LPCSTR DllBaseName, LPCSTR DllFullName, DWORD Flags);
HMEMORYMODULE WINAPI LoadLibraryMemoryExW(PVOID BufferAddress, size_t Reserved, LPCWSTR DllBaseName, LPCWSTR DllFullName, DWORD Flags);
BOOL WINAPI FreeLibraryMemory(HMEMORYMODULE hMemoryModule);
#define FreeLibraryMemoryAndExitThread NtUnloadDllMemoryAndExitThread
#ifdef UNICODE
#define NtLoadDllMemoryEx NtLoadDllMemoryExW
#define LoadLibraryMemoryEx NtLoadDllMemoryExW
#define LoadLibraryMemoryEx LoadLibraryMemoryExW
#else
#define NtLoadDllMemoryEx NtLoadDllMemoryExA
#define LoadLibraryMemoryEx NtLoadDllMemoryExA
#define LoadLibraryMemoryEx LoadLibraryMemoryExA
#endif
+121 -103
View File
@@ -28,7 +28,7 @@ static PIMAGE_NT_HEADERS WINAPI GetImageNtHeaders(PMEMORYMODULE pModule) {
if (pModule->Signature != MEMORY_MODULE_SIGNATURE)return nullptr;
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)((LPBYTE)pModule - pModule->SizeofHeaders);
PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)((LPBYTE)dos + dos->e_lfanew);
if (headers->OptionalHeader.ImageBase /*+ pModule->headers_align*/ != (ULONG64)pModule->codeBase)return nullptr;
if (headers->OptionalHeader.ImageBase != (ULONG64)pModule->codeBase)return nullptr;
return headers;
}
@@ -109,53 +109,35 @@ static int ProtectionFlags[2][2][2] = {
{PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE},
},
};
static SIZE_T GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER section);
static VOID FinalSectionsProtect(PMEMORYMODULE module) {
PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module);
PIMAGE_SECTION_HEADER sections = IMAGE_FIRST_SECTION(headers);
DWORD protect, oldProtect;
bool executable, readable, writeable;
#ifdef _WIN64
uintptr_t imageOffset = ((uintptr_t)headers->OptionalHeader.ImageBase & 0xffffffff00000000);
#else
static const uintptr_t imageOffset = 0;
#endif
for (WORD i = 0; i < headers->FileHeader.NumberOfSections; ++i, ++sections) {
executable = (sections->Characteristics & IMAGE_SCN_MEM_EXECUTE);
readable = (sections->Characteristics & IMAGE_SCN_MEM_READ);
writeable = (sections->Characteristics & IMAGE_SCN_MEM_WRITE);
protect = ProtectionFlags[executable][readable][writeable];
if (sections->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) protect |= PAGE_NOCACHE;
VirtualProtect((LPVOID)((uintptr_t)sections->Misc.PhysicalAddress | imageOffset),
GetRealSectionSize(module, sections), protect, &oldProtect);
}
return;
}
static BOOL CopySections(const unsigned char* data, PMEMORYMODULE module) {
LPBYTE codeBase = module->codeBase;
LPVOID dest;
PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module);
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(headers);
PIMAGE_SECTION_HEADER section = headers ? IMAGE_FIRST_SECTION(headers) : nullptr;
size_t alloc_size = 0;
bool cp = false;
if (!headers) {
SetLastError(ERROR_BAD_EXE_FORMAT);
return FALSE;
}
for (int i = 0; i < headers->FileHeader.NumberOfSections; i++, section++) {
alloc_size = headers->OptionalHeader.SectionAlignment;
cp = false;
if (section->SizeOfRawData) {
__try {
ProbeForRead(data, static_cast<size_t>(section->PointerToRawData) + section->SizeOfRawData);
ProbeForRead(data + static_cast<size_t>(section->PointerToRawData), section->SizeOfRawData);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError(ERROR_BAD_EXE_FORMAT);
return FALSE;
}
alloc_size = section->SizeOfRawData;
cp = true;
}
if (alloc_size) {
if (!(dest = VirtualAlloc(codeBase + section->VirtualAddress, alloc_size, MEM_COMMIT, PAGE_READWRITE))) {
//section = IMAGE_FIRST_SECTION(headers);
//for (int j = 0; j < i; ++j, ++section)VirtualFree(codeBase + section->VirtualAddress, 0, MEM_RELEASE);
if (!(dest = VirtualAlloc((LPSTR)headers->OptionalHeader.ImageBase + section->VirtualAddress, alloc_size, MEM_COMMIT, PAGE_READWRITE))) {
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
section->Misc.PhysicalAddress = (DWORD)((uintptr_t)dest & 0xffffffff);
@@ -184,18 +166,34 @@ static SIZE_T GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER sec
}
static BOOL FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) {
DWORD protect, oldProtect;
BOOL executable;
BOOL readable;
BOOL writeable;
PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module);
if (!sectionData->size) return TRUE;
if (sectionData->characteristics & IMAGE_SCN_MEM_DISCARDABLE) {
// section is not needed any more and can safely be freed
if (sectionData->address == sectionData->alignedAddress &&
(sectionData->last || GetImageNtHeaders(module)->OptionalHeader.SectionAlignment == module->pageSize || !(sectionData->size % module->pageSize))) {
#pragma warning (disable:6250)
(sectionData->last || headers->OptionalHeader.SectionAlignment == module->pageSize ||
(sectionData->size % module->pageSize) == 0)
)
#pragma warning(disable:6250)
VirtualFree(sectionData->address, sectionData->size, MEM_DECOMMIT);
#pragma warning (default:6250)
}
#pragma warning(default:6250)
return TRUE;
}
return TRUE;
// determine protection flags based on characteristics
executable = (sectionData->characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
readable = (sectionData->characteristics & IMAGE_SCN_MEM_READ) != 0;
writeable = (sectionData->characteristics & IMAGE_SCN_MEM_WRITE) != 0;
protect = ProtectionFlags[executable][readable][writeable];
if (sectionData->characteristics & IMAGE_SCN_MEM_NOT_CACHED) protect |= PAGE_NOCACHE;
// change memory access flags
return VirtualProtect(sectionData->address, sectionData->size, protect, &oldProtect);
}
static BOOL FinalizeSections(PMEMORYMODULE module) {
@@ -214,16 +212,17 @@ static BOOL FinalizeSections(PMEMORYMODULE module) {
sectionData.last = FALSE;
section++;
// loop through all sections and change access flags
for (int i = 1; i < headers->FileHeader.NumberOfSections; i++, section++) {
LPVOID sectionAddress = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset);
LPVOID alignedAddress = AlignAddressDown(sectionAddress, module->pageSize);
SIZE_T sectionSize = GetRealSectionSize(module, section);
if (sectionData.alignedAddress == alignedAddress || (uintptr_t)sectionData.address + sectionData.size > (uintptr_t) alignedAddress) {
if (!(section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) || !(sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE))
if ((section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0 || (sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) {
sectionData.characteristics = (sectionData.characteristics | section->Characteristics) & ~IMAGE_SCN_MEM_DISCARDABLE;
else
}
else {
sectionData.characteristics |= section->Characteristics;
}
sectionData.size = (((uintptr_t)sectionAddress) + ((uintptr_t)sectionSize)) - (uintptr_t)sectionData.address;
continue;
}
@@ -293,68 +292,80 @@ static BOOL PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta) {
return TRUE;
}
static BOOL GetImportAddressTableEntryCountAndVerify(PMEMORYMODULE module, LPDWORD Count, PIMAGE_IMPORT_DESCRIPTOR* IAT) {
__try {
PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module);
PIMAGE_DATA_DIRECTORY dir = GET_HEADER_DICTIONARY(headers, IMAGE_DIRECTORY_ENTRY_IMPORT);
PIMAGE_IMPORT_DESCRIPTOR iat = *IAT = (dir && dir->Size) ? decltype(iat)(headers->OptionalHeader.ImageBase + dir->VirtualAddress) : nullptr;
*Count = 0;
if (!iat)return TRUE;
ProbeForRead(iat, sizeof(IMAGE_IMPORT_DESCRIPTOR));
while (iat->Name) {
++*Count;
++iat;
ProbeForRead(iat, sizeof(IMAGE_IMPORT_DESCRIPTOR));
}
return TRUE;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError(RtlNtStatusToDosError(GetExceptionCode()));
return FALSE;
}
}
static void FreeLoadedModule(PMEMORYMODULE module) {
for (DWORD i = 0; i < module->dwModulesCount; ++i) FreeLibrary(module->hModulesList[i]);
delete[]module->hModulesList;
module->hModulesList = nullptr;
module->dwModulesCount = 0;
return;
}
static BOOL BuildImportTable(PMEMORYMODULE module) {
unsigned char* codeBase = module->codeBase;
PIMAGE_IMPORT_DESCRIPTOR importDesc;
BOOL result = TRUE;
PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module);
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(headers, IMAGE_DIRECTORY_ENTRY_IMPORT);
if (directory->Size == 0) {
return TRUE;
DWORD count;
if (!GetImportAddressTableEntryCountAndVerify(module, &count, &importDesc)) {
SetLastError(ERROR_BAD_EXE_FORMAT);
return FALSE;
}
importDesc = (PIMAGE_IMPORT_DESCRIPTOR)(codeBase + directory->VirtualAddress);
for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) {
uintptr_t* thunkRef;
FARPROC* funcRef;
HMODULE* tmp;
HMODULE handle = LoadLibraryA((LPCSTR)(codeBase + importDesc->Name));
if (!handle) {
SetLastError(ERROR_MOD_NOT_FOUND);
result = FALSE;
break;
}
if (!(tmp = (HMODULE*)realloc(module->hModulesList, (static_cast<size_t>(module->dwModulesCount) + 1)* (sizeof(HMODULE))))) {
FreeLibrary(handle);
SetLastError(ERROR_OUTOFMEMORY);
result = FALSE;
break;
}
module->hModulesList = tmp;
module->hModulesList[module->dwModulesCount++] = handle;
if (importDesc->OriginalFirstThunk) {
thunkRef = (uintptr_t*)(codeBase + importDesc->OriginalFirstThunk);
if (!importDesc || !count)return TRUE;
if (!(module->hModulesList = new HMODULE[count])) {
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
RtlZeroMemory(module->hModulesList, sizeof(HMODULE) * count);
__try {
for (DWORD i = 0; i < count; ++i, ++importDesc) {
uintptr_t* thunkRef;
FARPROC* funcRef;
HMODULE handle = LoadLibraryA((LPCSTR)(codeBase + importDesc->Name));
if (!handle) {
FreeLoadedModule(module);
SetLastError(ERROR_MOD_NOT_FOUND);
return FALSE;
}
module->hModulesList[module->dwModulesCount++] = handle;
thunkRef = (uintptr_t*)(codeBase + (importDesc->OriginalFirstThunk ? importDesc->OriginalFirstThunk : importDesc->FirstThunk));
funcRef = (FARPROC*)(codeBase + importDesc->FirstThunk);
}
else {
// no hint table
thunkRef = (uintptr_t*)(codeBase + importDesc->FirstThunk);
funcRef = (FARPROC*)(codeBase + importDesc->FirstThunk);
}
for (; *thunkRef; thunkRef++, funcRef++) {
if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) {
*funcRef = GetProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef));
while (*thunkRef) {
*funcRef = GetProcAddress(
handle,
IMAGE_SNAP_BY_ORDINAL(*thunkRef) ? (LPCSTR)IMAGE_ORDINAL(*thunkRef) : (LPCSTR)PIMAGE_IMPORT_BY_NAME(codeBase + (*thunkRef))->Name
);
if (!*funcRef) {
FreeLoadedModule(module);
SetLastError(ERROR_PROC_NOT_FOUND);
return FALSE;
}
++thunkRef;
++funcRef;
}
else {
PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME)(codeBase + (*thunkRef));
*funcRef = GetProcAddress(handle, (LPCSTR)&thunkData->Name);
}
if (*funcRef == 0) {
result = FALSE;
break;
}
}
if (!result) {
FreeLibrary(handle);
SetLastError(ERROR_PROC_NOT_FOUND);
break;
}
}
return result;
__except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError(RtlNtStatusToDosError(GetExceptionCode()));
return FALSE;
}
return TRUE;
}
HMEMORYMODULE MemoryLoadLibrary(const void* data) {
@@ -423,7 +434,7 @@ HMEMORYMODULE MemoryLoadLibrary(const void* data) {
SetLastError(ERROR_BAD_EXE_FORMAT);
return nullptr;
}
alignedImageSize += headers_align = (DWORD)AlignValueUp(sizeof(HMEMORYMODULE) + old_header->OptionalHeader.SizeOfHeaders, sysInfo.dwPageSize);
alignedImageSize += headers_align = (DWORD)AlignValueUp(sizeof(MEMORYMODULE) + old_header->OptionalHeader.SizeOfHeaders, sysInfo.dwPageSize);
// reserve memory for image of library
// XXX: is it correct to commit the complete memory region at once?
@@ -494,7 +505,6 @@ HMEMORYMODULE MemoryLoadLibrary(const void* data) {
// mark memory pages depending on section headers and release
// sections that are marked as "discardable"
if (!FinalizeSections(hMemoryModule)) goto error;
FinalSectionsProtect(hMemoryModule);
// TLS callbacks are executed BEFORE the main loading
if (!ExecuteTLS(hMemoryModule)) goto error;
@@ -509,16 +519,16 @@ HMEMORYMODULE MemoryLoadLibrary(const void* data) {
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError(ERROR_ACCESS_DENIED);
SetLastError(RtlNtStatusToDosError(GetExceptionCode()));
goto error;
}
hMemoryModule->initialized = TRUE;
}
return base;
return (HMEMORYMODULE)base;
error:
// cleanup
MemoryFreeLibrary(hMemoryModule);
MemoryFreeLibrary((HMEMORYMODULE)base);
return nullptr;
}
@@ -533,19 +543,18 @@ bool MemoryFreeLibrary(HMEMORYMODULE mod) {
(*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0);
}
if (module->nameExportsTable)delete[] module->nameExportsTable;
if (module->hModulesList != nullptr) {
int i;
for (i = 0; i < module->dwModulesCount; i++) {
if (module->hModulesList) {
for (DWORD i = 0; i < module->dwModulesCount; ++i) {
if (module->hModulesList[i]) {
FreeLibrary(module->hModulesList[i]);
}
}
free(module->hModulesList);
delete[] module->hModulesList;
}
#ifdef _WIN64
FreePointerList(module->blockedMemory);
#endif
if (module->codeBase != nullptr) VirtualFree(mod, 0, MEM_RELEASE);
if (module->codeBase) VirtualFree(mod, 0, MEM_RELEASE);
return true;
}
@@ -570,7 +579,11 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE mod, LPCSTR name) {
DWORD idx = 0;
PIMAGE_EXPORT_DIRECTORY exports;
PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module);
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(headers, IMAGE_DIRECTORY_ENTRY_EXPORT);
PIMAGE_DATA_DIRECTORY directory = headers ? GET_HEADER_DICTIONARY(headers, IMAGE_DIRECTORY_ENTRY_EXPORT) : nullptr;
if (!headers) {
SetLastError(ERROR_INVALID_HANDLE);
return nullptr;
}
if (directory->Size == 0) {
// no export table found
SetLastError(ERROR_PROC_NOT_FOUND);
@@ -756,13 +769,18 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry(void* root, PI
HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type, WORD language) {
PMEMORYMODULE mod = MapMemoryModuleHandle(module);
unsigned char* codeBase = mod->codeBase;
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(GetImageNtHeaders(mod), IMAGE_DIRECTORY_ENTRY_RESOURCE);
PIMAGE_NT_HEADERS headers = GetImageNtHeaders(mod);
PIMAGE_DATA_DIRECTORY directory = headers ? GET_HEADER_DICTIONARY(headers, IMAGE_DIRECTORY_ENTRY_RESOURCE) : nullptr;
PIMAGE_RESOURCE_DIRECTORY rootResources;
PIMAGE_RESOURCE_DIRECTORY nameResources;
PIMAGE_RESOURCE_DIRECTORY typeResources;
PIMAGE_RESOURCE_DIRECTORY_ENTRY foundType;
PIMAGE_RESOURCE_DIRECTORY_ENTRY foundName;
PIMAGE_RESOURCE_DIRECTORY_ENTRY foundLanguage;
if (!headers) {
SetLastError(ERROR_INVALID_HANDLE);
return nullptr;
}
if (directory->Size == 0) {
// no resource table found
SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
+1 -1
View File
@@ -24,7 +24,7 @@ typedef struct POINTER_LIST {
void* address;
} POINTER_LIST;
#endif
typedef void* HMEMORYMODULE;
typedef HMODULE HMEMORYMODULE;
typedef void* HMEMORYRSRC;
typedef struct _MEMORYMODULE {
/*
+1
View File
@@ -19,6 +19,7 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="LoadDllMemoryApi.cpp" />
<ClCompile Include="MemoryModule.cpp" />
<ClCompile Include="Native.cpp" />
<ClCompile Include="NativeFunctionsInternal.cpp" />
@@ -24,6 +24,9 @@
<ClCompile Include="NativeFunctionsInternal.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="LoadDllMemoryApi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="MemoryModule.h">
+92 -45
View File
@@ -82,7 +82,7 @@ static ULONG NTAPI LdrHashEntry(IN const UNICODE_STRING& str, IN bool _xor = tru
return result;
}
static HANDLE NTAPI RtlFindtLdrpHeap() {
static HANDLE NTAPI RtlFindLdrpHeap() {
PLIST_ENTRY ListHead, ListEntry;
PLDR_DATA_TABLE_ENTRY CurEntry;
MEMORY_BASIC_INFORMATION mbi{};
@@ -109,13 +109,13 @@ static PLIST_ENTRY NTAPI RtlFindLdrpHashTable() {
}
static PVOID NTAPI NtAllocateLdrpHeap(IN size_t size) {
HANDLE heap = RtlFindtLdrpHeap();
HANDLE heap = RtlFindLdrpHeap();
if (!heap)return nullptr;
return RtlAllocateHeap(heap, HEAP_ZERO_MEMORY, size);
}
static BOOL NTAPI NtFreeLdrpHeap(IN PVOID buffer) {
HANDLE LdrpHeap = RtlFindtLdrpHeap();
HANDLE LdrpHeap = RtlFindLdrpHeap();
if (!LdrpHeap)return FALSE;
return RtlFreeHeap(LdrpHeap, 0, buffer);
}
@@ -455,7 +455,19 @@ static bool NTAPI NtFreeLdrDataTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) {
NtRemoveModuleBaseAddressIndexNode(LdrEntry);
}
case win7:
case vista:
case vista: {
if (NtLdrDataTableEntrySize() == sizeof(LDR_DATA_TABLE_ENTRY_VISTA) ||
NtLdrDataTableEntrySize() == 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;
NtFreeLdrpHeap(next->Blink);
}
}
}
case xp: {
NtFreeLdrpHeap(LdrEntry->BaseDllName.Buffer);
NtFreeLdrpHeap(LdrEntry->FullDllName.Buffer);
@@ -646,6 +658,52 @@ static NTSTATUS NTAPI NtMapDllMemory(IN HMEMORYMODULE ViewBase, IN DWORD dwFlags
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(PVOID Buffer) {
BOOLEAN result = FALSE;
__try {
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(Buffer);
PIMAGE_SECTION_HEADER sections = headers ? IMAGE_FIRST_SECTION(headers) : nullptr;
size_t SizeofImage = headers ? headers->OptionalHeader.SizeOfHeaders : 0;
if (!sections)return result;
ProbeForRead(sections, headers->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
for (WORD i = 0; i < headers->FileHeader.NumberOfSections; ++i, ++sections)
SizeofImage += sections->SizeOfRawData;
ProbeForRead(Buffer, SizeofImage);
result = CheckSumBufferedFile(Buffer, SizeofImage);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError(RtlNtStatusToDosError(GetExceptionCode()));
}
return result;
}
NTSTATUS NTAPI NtLoadDllMemory(OUT HMEMORYMODULE* BaseAddress, IN LPVOID BufferAddress, IN size_t BufferSize) {
return NtLoadDllMemoryExW(BaseAddress, nullptr, LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS, BufferAddress, BufferSize, nullptr, nullptr);
}
@@ -662,13 +720,12 @@ NTSTATUS NTAPI NtLoadDllMemoryExW(
NTSTATUS status = STATUS_SUCCESS;
PLDR_DATA_TABLE_ENTRY ModuleEntry = nullptr;
PIMAGE_NT_HEADERS headers = nullptr;
UNREFERENCED_PARAMETER(BufferSize);
if (BufferSize)return STATUS_INVALID_PARAMETER_5;
__try {
//ProbeForRead(BufferAddress, BufferSize);
if (BufferSize)status = STATUS_INVALID_PARAMETER_5;
*BaseAddress = nullptr;
if (LdrEntry)*LdrEntry = nullptr;
if (!(dwFlags & LOAD_FLAGS_PASS_IMAGE_CHECK) && !RtlIsValidImageBuffer(BufferAddress))status = STATUS_INVALID_IMAGE_FORMAT;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
@@ -697,13 +754,13 @@ NTSTATUS NTAPI NtLoadDllMemoryExW(
!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(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;
NtUpdateReferenceCount(CurEntry, FLAG_REFERENCE);
*BaseAddress = CurEntry->DllBase;
*BaseAddress = (HMEMORYMODULE)CurEntry->DllBase;
if (LdrEntry)*LdrEntry = CurEntry;
return STATUS_SUCCESS;
}
@@ -880,14 +937,11 @@ static VOID NTAPI RtlpInsertInvertedFunctionTable(IN PRTL_INVERTED_FUNCTION_TABL
PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTable;
ULONG Index;
ULONG SizeOfTable = 0;
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(ImageBase);
PIMAGE_DATA_DIRECTORY dir = &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
bool need = RtlIsWindowsVersionOrGreater(6, 2, 0);
bool IsWin8OrGreater = RtlIsWindowsVersionOrGreater(6, 2, 0);
Index = (ULONG)need;
Index = (ULONG)IsWin8OrGreater;
CurrentSize = InvertedTable->Count;
if (CurrentSize != InvertedTable->MaxCount) {
//if (need)_InterlockedIncrement(&InvertedTable->Epoch);
if (CurrentSize != 0) {
while (Index < CurrentSize) {
if (ImageBase < InvertedTable->Entries[Index].ImageBase)break;
@@ -901,21 +955,15 @@ static VOID NTAPI RtlpInsertInvertedFunctionTable(IN PRTL_INVERTED_FUNCTION_TABL
}
}
FunctionTable = (decltype(FunctionTable))((size_t)ImageBase + dir->VirtualAddress);
if (FunctionTable != RtlImageDirectoryEntryToData(ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &SizeOfTable) || SizeOfTable != dir->Size) {
__fastfail(STATUS_BAD_DATA);
}
//SizeOfTable = dir->Size;
FunctionTable = (decltype(FunctionTable))RtlImageDirectoryEntryToData(ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &SizeOfTable);
InvertedTable->Entries[Index].ExceptionDirectory = FunctionTable;
InvertedTable->Entries[Index].ImageBase = ImageBase;
InvertedTable->Entries[Index].ImageSize = SizeOfImage;
InvertedTable->Entries[Index].ExceptionDirectorySize = SizeOfTable;
InvertedTable->Count++;
//if (need)_InterlockedIncrement(&InvertedTable->Epoch);
}
else {
need ? (InvertedTable->Overflow = TRUE) : (InvertedTable->Epoch = TRUE);
IsWin8OrGreater ? (InvertedTable->Overflow = TRUE) : (InvertedTable->Epoch = TRUE);
}
#else
@@ -1007,16 +1055,12 @@ static VOID NTAPI RtlpRemoveInvertedFunctionTable(IN PRTL_INVERTED_FUNCTION_TABL
}
if (InvertedTable->Count != InvertedTable->MaxCount) {
#ifdef _WIN64
//InvertedTable->Overflow = FALSE;
#else
if (IsWin8OrGreater) {
InvertedTable->NextEntrySEHandlerTableEncoded = FALSE;
PRTL_INVERTED_FUNCTION_TABLE_64(InvertedTable)->Overflow = FALSE;
}
else {
InvertedTable->Overflow = FALSE;
PRTL_INVERTED_FUNCTION_TABLE_WIN7_32(InvertedTable)->Overflow = FALSE;
}
#endif
}
return;
@@ -1107,7 +1151,7 @@ static __forceinline bool NTAPI RtlIsModuleUnloaded(PLDR_DATA_TABLE_ENTRY entry)
}
else {
return entry->DllBase == nullptr;
}
}
}
static PVOID FindLdrpInvertedFunctionTable32() {
// _RTL_INVERTED_FUNCTION_TABLE x86
@@ -1133,14 +1177,14 @@ static PVOID FindLdrpInvertedFunctionTable32() {
DWORD SEHTable, SEHCount;
BYTE Offset = 0x20; //sizeof(_RTL_INVERTED_FUNCTION_TABLE_ENTRY)*2
if (RtlIsWindowsVersionOrGreater(10, 0, 0)) lpSectionName = ".mrdata";
if (RtlIsWindowsVersionOrGreater(6, 3, 0)) lpSectionName = ".mrdata";
else if (!RtlIsWindowsVersionOrGreater(6, 2, 0)) Offset = 0xC;
while (ListEntry != ListHead) {
CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
ListEntry = ListEntry->Flink;
if (RtlIsModuleUnloaded(CurEntry))continue; //skip unloaded module
if (IsValidMemoryModuleHandle(CurEntry->DllBase))continue; //skip our memory module.
if (IsValidMemoryModuleHandle((HMEMORYMODULE)CurEntry->DllBase))continue; //skip our memory module.
if (CurEntry->DllBase == hNtdll && Offset == 0x20)continue; //Win10 skip first entry, if the base of ntdll is smallest.
hModule = (HMODULE)(hModule ? min(hModule, CurEntry->DllBase) : CurEntry->DllBase);
}
@@ -1200,7 +1244,7 @@ static PVOID FindLdrpInvertedFunctionTable64() {
CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
ListEntry = ListEntry->Flink;
//Make sure the smallest base address is not our memory module
if (IsValidMemoryModuleHandle(CurEntry->DllBase))continue;
if (IsValidMemoryModuleHandle((HMEMORYMODULE)CurEntry->DllBase))continue;
hModule = (HMODULE)(hModule ? min(hModule, CurEntry->DllBase) : CurEntry->DllBase);
}
ModuleHeaders = RtlImageNtHeader(hModule);
@@ -1255,7 +1299,7 @@ static NTSTATUS NTAPI RtlProtectMrdata(IN SIZE_T Protect) {
NTSTATUS NTAPI RtlInsertInvertedFunctionTable(IN PVOID BaseAddress, IN size_t ImageSize) {
static auto table = PRTL_INVERTED_FUNCTION_TABLE(RtlFindLdrpInvertedFunctionTable());
if (!table)return STATUS_NOT_SUPPORTED;
bool need_virtual_protect = RtlIsWindowsVersionOrGreater(8, 3, 0);
bool need_virtual_protect = RtlIsWindowsVersionOrGreater(6, 3, 0);
NTSTATUS status;
if (need_virtual_protect) {
@@ -1267,17 +1311,12 @@ NTSTATUS NTAPI RtlInsertInvertedFunctionTable(IN PVOID BaseAddress, IN size_t Im
status = RtlProtectMrdata(PAGE_READONLY);
if (!NT_SUCCESS(status))return status;
}
#ifdef _WIN64
if (RtlIsWindowsVersionOrGreater(6, 2, 0)) return table->Overflow ? STATUS_INVALID_ADDRESS : STATUS_SUCCESS;
else return table->Epoch ? STATUS_INVALID_ADDRESS : STATUS_SUCCESS;
#else
return (need_virtual_protect ? table->NextEntrySEHandlerTableEncoded : table->Overflow) ? STATUS_INVALID_ADDRESS : STATUS_SUCCESS;
#endif
return (RtlIsWindowsVersionOrGreater(6, 2, 0) ? PRTL_INVERTED_FUNCTION_TABLE_64(table)->Overflow : PRTL_INVERTED_FUNCTION_TABLE_WIN7_32(table)->Overflow) ?
STATUS_NO_MEMORY : STATUS_SUCCESS;
}
NTSTATUS NTAPI RtlRemoveInvertedFunctionTable(IN PVOID ImageBase) {
static auto table = PRTL_INVERTED_FUNCTION_TABLE(RtlFindLdrpInvertedFunctionTable());
bool need_virtual_protect = RtlIsWindowsVersionOrGreater(10, 0, 0);
bool need_virtual_protect = RtlIsWindowsVersionOrGreater(6, 3, 0);
NTSTATUS status;
if (need_virtual_protect) {
@@ -1297,10 +1336,18 @@ static NTSTATUS NTAPI LdrpHandleTlsDataXp(PLDR_DATA_TABLE_ENTRY LdrEntry) {
return STATUS_NOT_SUPPORTED;
}
static NTSTATUS NTAPI RtlFindLdrpHandleTlsData(PVOID* _LdrpHandleTlsData, bool* stdcall) {
static PVOID _LdrpHandleTlsData_ = (PVOID)~0;
NTSTATUS status = STATUS_SUCCESS;
__try {
*_LdrpHandleTlsData = nullptr;
*stdcall = false;
if (_LdrpHandleTlsData_ != (PVOID)~0) {
*_LdrpHandleTlsData = _LdrpHandleTlsData_;
if (_LdrpHandleTlsData_ == nullptr)status = STATUS_NOT_SUPPORTED;
}
else {
*_LdrpHandleTlsData = _LdrpHandleTlsData_ = nullptr;
*stdcall = false;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
@@ -1420,7 +1467,7 @@ static NTSTATUS NTAPI RtlFindLdrpHandleTlsData(PVOID* _LdrpHandleTlsData, bool*
SEARCH_CONTEXT SearchContext{ SearchContext.MemoryBuffer = const_cast<PVOID>(Feature),SearchContext.BufferLength = Size - 1 };
if (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(GetModuleHandleW(L"ntdll.dll"), ".text", &SearchContext)))
SearchContext.OutBufferPtr -= OffsetOfFunctionBegin;
if (!(*_LdrpHandleTlsData = SearchContext.MemoryBlockInSection))return STATUS_NOT_SUPPORTED;
if (!(*_LdrpHandleTlsData = _LdrpHandleTlsData_ = SearchContext.MemoryBlockInSection))return STATUS_NOT_SUPPORTED;
*stdcall = !RtlIsWindowsVersionOrGreater(6, 3, 0);
return status;
}
@@ -1493,7 +1540,7 @@ NTSTATUS NTAPI NtQuerySystemMemoryModuleFeatures(OUT PDWORD pFeatures) {
}
if (RtlFindLdrpModuleBaseAddressIndex())features |= MEMORY_FEATURE_MODULE_BASEADDRESS_INDEX;
if (RtlFindtLdrpHeap())features |= MEMORY_FEATURE_LDRP_HEAP;
if (RtlFindLdrpHeap())features |= MEMORY_FEATURE_LDRP_HEAP;
if (RtlFindLdrpHashTable())features |= MEMORY_FEATURE_LDRP_HASH_TABLE;
if (RtlFindLdrpInvertedFunctionTable())features |= MEMORY_FEATURE_INVERTED_FUNCTION_TABLE;
if (NT_SUCCESS(RtlFindLdrpHandleTlsData(&pfn, &value)) && pfn)features |= MEMORY_FEATURE_LDRP_HANDLE_TLS_DATA;
+3
View File
@@ -421,6 +421,9 @@ NTSTATUS NTAPI NtLoadDllMemory(
//If this flag is specified, this routine will not fail even if the call to LdrpTlsData fails.
#define LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS 0x20000000
//If this flag is specified, the input image buffer will not be checked before loading.
#define LOAD_FLAGS_PASS_IMAGE_CHECK 0x40000000
//If this flag is specified, exception handling will not be supported.
#define LOAD_FLAGS_NOT_ADD_INVERTED_FUNCTION 0x00000001