mirror of
https://github.com/bb107/MemoryModulePP
synced 2026-06-08 13:15:33 +00:00
support win8.1
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
/*
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -6,25 +6,18 @@ MemoryModulePP, used to load a DLL from memory. MemoryModulePP is compatible wit
|
||||
|
||||
**MemoryModulePP is developed based on [MemoryModule][ref1].**
|
||||
|
||||
**This repository is under development.**
|
||||
|
||||
|
||||
> In order to support 32-bit dll exception handling, the dll should enable the /SAFESEH linker option,
|
||||
> otherwise the exception handler cannot pass the RtlIsValidHandler () check when an exception occurs
|
||||
|
||||
## New Features
|
||||
- Support Win8
|
||||
|
||||
## Features
|
||||
- Compatible with Win32 API (GetModuleHandleA/W/Ex GetModuleFileNameA/W/Ex GetProcAddress and any Resource API)
|
||||
- Compatible with Win32 API (GetModuleHandle, GetModuleFileName, GetProcAddress and any Resource API)
|
||||
- Support for C++ exceptions and SEH
|
||||
- Compatible with Win7 and Win10
|
||||
- Optimized MEMORYMODULE structure
|
||||
- Use reference counting, repeated loading of the same module will update the reference counting, please refer to NtLoadDllMemoryExW
|
||||
- The above features can be turned off through the dwFlags parameter of NtLoadDllMemoryExW
|
||||
- Support for TLS(Thread Local Storage)
|
||||
- DllMain can receive four types of notifications
|
||||
- Support Win10 forward export
|
||||
- Support forward export
|
||||
|
||||
## Tech
|
||||
|
||||
@@ -34,13 +27,11 @@ MemoryModulePP uses many open source projects and references to work properly:
|
||||
* [MemoryModule][ref1] - Load dll from memory, reference and improve part of this repository's code.
|
||||
* [Blackbone][ref2] - Windows memory hacking library, Referenced the idea of exception handling.
|
||||
* [Exceptions on Windows x64][ref3] - How Windows x64 Exception Handling Works. (Russian)
|
||||
* [Reactos][ref4] - How WIndows loads dll.
|
||||
* [Reactos][ref4] - How Windows loads dll.
|
||||
|
||||
## Todos
|
||||
- Looking for a good way to locate the LdrpHandleTlsData function, or implement this function.
|
||||
|
||||
- Compatible with Win8 and x86 architecture
|
||||
- Improve MEMORYPODULE structure
|
||||
- Improve NtLoadDllMemoryExW function
|
||||
|
||||
|
||||
[ref0]: <https://www.vergiliusproject.com>
|
||||
@@ -48,4 +39,5 @@ MemoryModulePP uses many open source projects and references to work properly:
|
||||
[ref2]: <https://github.com/DarthTon/Blackbone.git>
|
||||
[ref3]: <https://habr.com/en/company/aladdinrd/blog/321868/>
|
||||
[ref4]: <https://doxygen.reactos.org/>
|
||||
[ref5]: <https://github.com/processhacker/processhacker.git>
|
||||
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ int __test__() {
|
||||
static thread_local int x = 0xffccffdd;
|
||||
DWORD WINAPI Thread(PVOID) {
|
||||
printf("[1] ThreadLocalStoragePointer = %p\n", NtCurrentTeb()->ThreadLocalStoragePointer);
|
||||
return x == 0xffccffdd ? 0 : 1; const auto i = offsetof(CONTEXT, Dr0);
|
||||
return x == 0xffccffdd ? 0 : 1;
|
||||
}
|
||||
|
||||
int thread() {
|
||||
|
||||
+72
-69
@@ -1,16 +1,11 @@
|
||||
//#include "../MemoryModule/NativeFunctionsInternal.h"
|
||||
#include "../MemoryModule/LoadDllMemoryApi.h"
|
||||
#ifndef NT_SUCCESS
|
||||
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
|
||||
#endif
|
||||
#include <cstdio>
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
int main() {
|
||||
//return ((int(*)(int))GetProcAddress(LoadLibraryW(L"a.dll"), "exception"))(0);
|
||||
static PVOID ReadDllFile(LPCSTR FileName) {
|
||||
LPVOID buffer;
|
||||
size_t size;
|
||||
FILE* f = fopen("a.dll", "rb");
|
||||
FILE* f = fopen(FileName, "rb");
|
||||
if (!f)return 0;
|
||||
_fseeki64(f, 0, SEEK_END);
|
||||
if (!(size = _ftelli64(f))) {
|
||||
@@ -20,6 +15,11 @@ int main() {
|
||||
_fseeki64(f, 0, SEEK_SET);
|
||||
fread(buffer = new char[size], 1, size, f);
|
||||
fclose(f);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int test_default() {
|
||||
LPVOID buffer = ReadDllFile("a.dll");
|
||||
|
||||
HMEMORYMODULE m1 = nullptr, m2 = m1;
|
||||
HMODULE hModule = nullptr;
|
||||
@@ -93,73 +93,76 @@ int main() {
|
||||
end:
|
||||
delete[]buffer;
|
||||
if (m1)NtUnloadDllMemory(m1);
|
||||
FreeLibrary(LoadLibraryW(L"wininet.dll"));
|
||||
FreeLibrary(GetModuleHandleW(L"wininet.dll"));
|
||||
if (m2)NtUnloadDllMemory(m2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define WSADESCRIPTION_LEN 256
|
||||
#define WSASYS_STATUS_LEN 128
|
||||
typedef USHORT ADDRESS_FAMILY;
|
||||
typedef int (PASCAL* WSAStartup_t)(WORD wVersionRequired, LPWSADATA lpWSAData);
|
||||
typedef int (PASCAL* WSACleanup_t)(void);
|
||||
typedef SOCKET (PASCAL* socket_t)(int af, int type, int protocol);
|
||||
typedef int (PASCAL* closesocket_t)(SOCKET s);
|
||||
typedef int (PASCAL* connect_t)(SOCKET s, const struct sockaddr FAR* name, int namelen);
|
||||
typedef unsigned long (PASCAL* inet_addr_t)(const char FAR* cp);
|
||||
typedef u_short (PASCAL* htons_t)(u_short hostshort);
|
||||
|
||||
//#include <cstdio>
|
||||
//#include "../MemoryModule/NativeFunctionsInternal.h"
|
||||
//
|
||||
//bool c;
|
||||
//static thread_local int x = -1;
|
||||
//
|
||||
//DWORD WINAPI Thread(PVOID) {
|
||||
// printf("[1] x = %d\n", x);
|
||||
// x = 0;
|
||||
// c = true;
|
||||
// while (c)Sleep(100);
|
||||
// return x;
|
||||
//}
|
||||
//
|
||||
//int main() {
|
||||
// x = 1;
|
||||
// c = false;
|
||||
// HANDLE hThread = CreateThread(nullptr, 0, Thread, nullptr, 0, nullptr);
|
||||
// DWORD ex = 0;
|
||||
// if (hThread) {
|
||||
// while (!c)Sleep(100);
|
||||
// printf("[0] x = %d\n", x);
|
||||
// c = false;
|
||||
// WaitForSingleObject(hThread, 0xffffffff);
|
||||
// GetExitCodeThread(hThread, &ex);
|
||||
// CloseHandle(hThread);
|
||||
// printf("[0] Exit = %d\n", ex);
|
||||
// }
|
||||
//
|
||||
// PLIST_ENTRY entry = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
|
||||
// PLDR_DATA_TABLE_ENTRY_WIN7 data = nullptr;
|
||||
//
|
||||
// while (entry != entry->Flink) {
|
||||
// entry = entry->Flink;
|
||||
// data = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY_WIN7, InLoadOrderLinks);
|
||||
// }
|
||||
//
|
||||
// return 0;
|
||||
//}
|
||||
int test_ws2_32() {
|
||||
PVOID buffer = ReadDllFile("C:\\Windows\\system32\\ws2_32.dll");
|
||||
|
||||
//#include "../MemoryModule/Native.h"
|
||||
//#include <cstdio>
|
||||
//
|
||||
//static thread_local int x = 0xffccffdd;
|
||||
//
|
||||
//DWORD WINAPI Thread(PVOID) {
|
||||
// printf("[1] ThreadLocalStoragePointer = %p\n", NtCurrentTeb()->ThreadLocalStoragePointer);
|
||||
// return x == 0xffccffdd ? 0 : 1;
|
||||
//}
|
||||
//
|
||||
//int main() {
|
||||
// x = 2;
|
||||
// printf("[0] ThreadLocalStoragePointer = %p\n", NtCurrentTeb()->ThreadLocalStoragePointer);
|
||||
// HANDLE hThread = CreateThread(nullptr, 0, Thread, nullptr, 0, nullptr);
|
||||
// DWORD ret = -1;
|
||||
// if (hThread) {
|
||||
// WaitForSingleObject(hThread, 0xffffffff);
|
||||
// GetExitCodeThread(hThread, &ret);
|
||||
// CloseHandle(hThread);
|
||||
// return ret;
|
||||
// }
|
||||
// return -1;
|
||||
//}
|
||||
HMEMORYMODULE hMemoryModule = nullptr;
|
||||
HMODULE hModule = nullptr;
|
||||
NTSTATUS status;
|
||||
|
||||
WSAData data{};
|
||||
SOCKET sock = INVALID_SOCKET;
|
||||
sockaddr_in addr{};
|
||||
WSAStartup_t _WSAStartup = nullptr;
|
||||
WSACleanup_t _WSACleanup = nullptr;
|
||||
socket_t _socket = nullptr;
|
||||
closesocket_t _closesocket = nullptr;
|
||||
connect_t _connect = nullptr;
|
||||
inet_addr_t _inet_addr = nullptr;
|
||||
htons_t _htons = nullptr;
|
||||
|
||||
hMemoryModule = LoadLibraryMemoryExW(buffer, 0, L"ws2.dll", nullptr, LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS);
|
||||
hModule = MemoryModuleToModule(hMemoryModule);
|
||||
if (buffer)delete[]buffer;
|
||||
if (!hModule)return 0;
|
||||
|
||||
_WSAStartup = (decltype(_WSAStartup)(GetProcAddress(hModule, "WSAStartup")));
|
||||
_WSACleanup = (decltype(_WSACleanup)(GetProcAddress(hModule, "WSACleanup")));
|
||||
_socket = (decltype(_socket)(GetProcAddress(hModule, "socket")));
|
||||
_closesocket = (decltype(_closesocket)(GetProcAddress(hModule, "closesocket")));
|
||||
_connect = (decltype(_connect)(GetProcAddress(hModule, "connect")));
|
||||
_inet_addr = (decltype(_inet_addr)(GetProcAddress(hModule, "inet_addr")));
|
||||
_htons = (decltype(_htons)(GetProcAddress(hModule, "htons")));
|
||||
if (!_WSAStartup || !_WSACleanup || !_socket || !_closesocket || !_connect || !_inet_addr || !_htons)goto end;
|
||||
|
||||
if (_WSAStartup(MAKEWORD(2, 2), &data) != 0)goto end;
|
||||
if ((sock = _socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)goto end;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = _htons(80);
|
||||
addr.sin_addr.S_un.S_addr = _inet_addr("1.1.1.1");
|
||||
if (_connect(sock, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)goto end;
|
||||
|
||||
//success
|
||||
printf("ws2_32 completed successfully.\n");
|
||||
|
||||
end:
|
||||
if (sock != INVALID_SOCKET && _closesocket)_closesocket(sock);
|
||||
if (_WSACleanup)_WSACleanup();
|
||||
FreeLibraryMemory(hMemoryModule);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_default();
|
||||
test_ws2_32();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user