Resolve IAT after insert LdrDataTableEntry

This commit is contained in:
Boring
2022-07-11 13:33:59 +08:00
parent a74d29ec5d
commit 446bb917d9
5 changed files with 238 additions and 247 deletions
+124 -115
View File
@@ -62,6 +62,129 @@ static SYSTEM_INFO sysInfo = []()->SYSTEM_INFO {
return tmp;
}();
NTSTATUS MemoryResolveImportTable(
_In_ LPBYTE base,
_In_ PIMAGE_NT_HEADERS lpNtHeaders,
_In_ PMEMORYMODULE hMemoryModule) {
NTSTATUS status = STATUS_SUCCESS;
PIMAGE_IMPORT_DESCRIPTOR importDesc = nullptr;
DWORD count = 0;
do {
__try {
PIMAGE_DATA_DIRECTORY dir = GET_HEADER_DICTIONARY(lpNtHeaders, IMAGE_DIRECTORY_ENTRY_IMPORT);
PIMAGE_IMPORT_DESCRIPTOR iat = nullptr;
if (dir && dir->Size) {
iat = importDesc = PIMAGE_IMPORT_DESCRIPTOR(lpNtHeaders->OptionalHeader.ImageBase + dir->VirtualAddress);
}
if (iat) {
while (iat->Name) {
++count;
++iat;
}
}
if (importDesc && count) {
if (!(hMemoryModule->hModulesList = new HMODULE[count])) {
status = STATUS_NO_MEMORY;
break;
}
RtlZeroMemory(
hMemoryModule->hModulesList,
sizeof(HMODULE) * count
);
for (DWORD i = 0; i < count; ++i, ++importDesc) {
uintptr_t* thunkRef;
FARPROC* funcRef;
HMODULE handle = LoadLibraryA((LPCSTR)(base + importDesc->Name));
if (!handle) {
status = STATUS_DLL_NOT_FOUND;
break;
}
hMemoryModule->hModulesList[hMemoryModule->dwModulesCount++] = handle;
thunkRef = (uintptr_t*)(base + (importDesc->OriginalFirstThunk ? importDesc->OriginalFirstThunk : importDesc->FirstThunk));
funcRef = (FARPROC*)(base + importDesc->FirstThunk);
while (*thunkRef) {
*funcRef = GetProcAddress(
handle,
IMAGE_SNAP_BY_ORDINAL(*thunkRef) ? (LPCSTR)IMAGE_ORDINAL(*thunkRef) : (LPCSTR)PIMAGE_IMPORT_BY_NAME(base + (*thunkRef))->Name
);
if (!*funcRef) {
status = STATUS_ENTRYPOINT_NOT_FOUND;
break;
}
++thunkRef;
++funcRef;
}
if (!NT_SUCCESS(status))break;
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
} while (false);
if (!NT_SUCCESS(status)) {
for (DWORD i = 0; i < hMemoryModule->dwModulesCount; ++i)
FreeLibrary(hMemoryModule->hModulesList[i]);
delete[]hMemoryModule->hModulesList;
hMemoryModule->hModulesList = nullptr;
hMemoryModule->dwModulesCount = 0;
}
return status;
}
NTSTATUS MemorySetSectionProtection(
_In_ LPBYTE base,
_In_ PIMAGE_NT_HEADERS lpNtHeaders) {
NTSTATUS status = STATUS_SUCCESS;
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(lpNtHeaders);
//
// Determine whether it is a .NET assembly
//
auto& com = lpNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
bool CorImage = com.Size && com.VirtualAddress;
for (DWORD i = 0; i < lpNtHeaders->FileHeader.NumberOfSections; ++i, ++section) {
LPVOID address = LPBYTE(base) + section->VirtualAddress;
SIZE_T size = AlignValueUp(section->Misc.VirtualSize, lpNtHeaders->OptionalHeader.SectionAlignment);
if (section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE && !CorImage) {
//
// If it is a .NET assembly, we cannot release this memory block
//
#pragma warning(disable:6250)
VirtualFree(address, size, MEM_DECOMMIT);
#pragma warning(default:6250)
}
else {
BOOL executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0,
readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0,
writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0;
DWORD protect = ProtectionFlags[executable][readable][writeable], oldProtect;
if (section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) protect |= PAGE_NOCACHE;
status = NtProtectVirtualMemory(NtCurrentProcess(), &address, &size, protect, &oldProtect);
if (!NT_SUCCESS(status))break;
}
}
return status;
}
NTSTATUS MemoryLoadLibrary(
_Out_ HMEMORYMODULE* MemoryModuleHandle,
_In_ LPCVOID data,
@@ -98,12 +221,6 @@ NTSTATUS MemoryLoadLibrary(
__leave;
}
//
// Determine whether it is a .NET assembly
//
auto& com = old_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
CorImage = com.Size && com.VirtualAddress;
//
// Match machine type
//
@@ -183,6 +300,7 @@ NTSTATUS MemoryLoadLibrary(
hMemoryModule->Signature = MEMORY_MODULE_SIGNATURE;
hMemoryModule->SizeofHeaders = old_header->OptionalHeader.SizeOfHeaders;
hMemoryModule->lpReserved = (LPVOID)data;
hMemoryModule->dwReferenceCount = 1;
do {
//
@@ -267,115 +385,6 @@ NTSTATUS MemoryLoadLibrary(
}
if (!NT_SUCCESS(status))break;
//
// Build import table
//
PIMAGE_IMPORT_DESCRIPTOR importDesc = nullptr;
DWORD count = 0;
__try {
PIMAGE_DATA_DIRECTORY dir = GET_HEADER_DICTIONARY(new_header, IMAGE_DIRECTORY_ENTRY_IMPORT);
PIMAGE_IMPORT_DESCRIPTOR iat = nullptr;
status = STATUS_SUCCESS;
if (dir && dir->Size) {
iat = importDesc = PIMAGE_IMPORT_DESCRIPTOR(new_header->OptionalHeader.ImageBase + dir->VirtualAddress);
}
if (iat) {
while (iat->Name) {
++count;
++iat;
}
}
if (importDesc && count) {
if (!(hMemoryModule->hModulesList = new HMODULE[count])) {
status = STATUS_NO_MEMORY;
break;
}
RtlZeroMemory(
hMemoryModule->hModulesList,
sizeof(HMODULE) * count
);
for (DWORD i = 0; i < count; ++i, ++importDesc) {
uintptr_t* thunkRef;
FARPROC* funcRef;
HMODULE handle = LoadLibraryA((LPCSTR)(base + importDesc->Name));
if (!handle) {
status = STATUS_DLL_NOT_FOUND;
break;
}
hMemoryModule->hModulesList[hMemoryModule->dwModulesCount++] = handle;
thunkRef = (uintptr_t*)(base + (importDesc->OriginalFirstThunk ? importDesc->OriginalFirstThunk : importDesc->FirstThunk));
funcRef = (FARPROC*)(base + importDesc->FirstThunk);
while (*thunkRef) {
*funcRef = GetProcAddress(
handle,
IMAGE_SNAP_BY_ORDINAL(*thunkRef) ? (LPCSTR)IMAGE_ORDINAL(*thunkRef) : (LPCSTR)PIMAGE_IMPORT_BY_NAME(base + (*thunkRef))->Name
);
if (!*funcRef) {
status = STATUS_ENTRYPOINT_NOT_FOUND;
break;
}
++thunkRef;
++funcRef;
}
if (!NT_SUCCESS(status))break;
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
if (!NT_SUCCESS(status)) {
for (DWORD i = 0; i < hMemoryModule->dwModulesCount; ++i)
FreeLibrary(hMemoryModule->hModulesList[i]);
delete[]hMemoryModule->hModulesList;
hMemoryModule->hModulesList = nullptr;
hMemoryModule->dwModulesCount = 0;
break;
}
//
// Set section memory protect
//
section = IMAGE_FIRST_SECTION(new_header);
for (DWORD i = 0; i < new_header->FileHeader.NumberOfSections; ++i, ++section) {
LPVOID address = LPBYTE(base) + section->VirtualAddress;
SIZE_T size = AlignValueUp(section->Misc.VirtualSize, new_header->OptionalHeader.SectionAlignment);
if (section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE && !CorImage) {
//
// If it is a .NET assembly, we cannot release this memory block
//
#pragma warning(disable:6250)
VirtualFree(address, size, MEM_DECOMMIT);
#pragma warning(default:6250)
}
else {
BOOL executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0,
readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0,
writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0;
DWORD protect = ProtectionFlags[executable][readable][writeable], oldProtect;
if (section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) protect |= PAGE_NOCACHE;
status = NtProtectVirtualMemory(NtCurrentProcess(), &address, &size, protect, &oldProtect);
if (!NT_SUCCESS(status))break;
}
}
if (!NT_SUCCESS(status))break;
__try {
*MemoryModuleHandle = (HMEMORYMODULE)base;
}
+12 -1
View File
@@ -50,7 +50,7 @@ typedef struct _MEMORYMODULE {
HMODULE* hModulesList; //Import module handles
DWORD dwModulesCount; //number of module handles
DWORD dwReserved;
DWORD dwReferenceCount;
DWORD dwImageFileSize;
DWORD headers_align; //headers_align == OptionalHeaders.BaseOfCode;
@@ -70,6 +70,17 @@ extern "C" {
_In_ DWORD size
);
NTSTATUS MemoryResolveImportTable(
_In_ LPBYTE base,
_In_ PIMAGE_NT_HEADERS lpNtHeaders,
_In_ PMEMORYMODULE hMemoryModule
);
NTSTATUS MemorySetSectionProtection(
_In_ LPBYTE base,
_In_ PIMAGE_NT_HEADERS lpNtHeaders
);
bool MemoryFreeLibrary(HMEMORYMODULE);
bool WINAPI IsValidMemoryModuleHandle(HMEMORYMODULE hModule);
-8
View File
@@ -297,8 +297,6 @@ NTSTATUS NTAPI HookNtCreateThread(
Context.Rdx = ULONG64(_Context);
#endif
EnterCriticalSection(&MmpTlspLock);
status = OriginNtCreateThread(
ThreadHandle,
DesiredAccess,
@@ -313,8 +311,6 @@ NTSTATUS NTAPI HookNtCreateThread(
RtlFreeHeap(RtlProcessHeap(), 0, _Context);
}
LeaveCriticalSection(&MmpTlspLock);
return status;
}
@@ -338,8 +334,6 @@ NTSTATUS NTAPI HookNtCreateThreadEx(
Context->ThreadStartRoutine = PTHREAD_START_ROUTINE(StartRoutine);
Context->ThreadParameter = Argument;
EnterCriticalSection(&MmpTlspLock);
NTSTATUS status = OriginNtCreateThreadEx(
ThreadHandle,
DesiredAccess,
@@ -357,8 +351,6 @@ NTSTATUS NTAPI HookNtCreateThreadEx(
RtlFreeHeap(RtlProcessHeap(), 0, Context);
}
LeaveCriticalSection(&MmpTlspLock);
return status;
}
+84 -106
View File
@@ -280,57 +280,20 @@ static bool NTAPI RtlFreeLdrDataTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) {
#define FLAG_REFERENCE 0
#define FLAG_DEREFERENCE 1
static NTSTATUS NTAPI RtlUpdateReferenceCount(IN OUT PLDR_DATA_TABLE_ENTRY LdrEntry, IN DWORD Flags) {
static NTSTATUS NTAPI RtlUpdateReferenceCount(IN OUT PMEMORYMODULE pModule, IN DWORD Flags) {
if (Flags != FLAG_REFERENCE && Flags != FLAG_DEREFERENCE)return STATUS_INVALID_PARAMETER_2;
switch (NtWindowsVersion()) {
case xp:
case vista:
case win7: {
if (Flags == FLAG_REFERENCE && LdrEntry->LoadCount != 0xffff)
++LdrEntry->LoadCount;
if (Flags == FLAG_DEREFERENCE && LdrEntry->LoadCount)
--LdrEntry->LoadCount;
break;
}
case win8:
case win8_1:
case win10:
case win10_1:
case win10_2: {
auto entry = (PLDR_DATA_TABLE_ENTRY_WIN10)LdrEntry;
if (Flags == FLAG_REFERENCE) {
if (entry->ObsoleteLoadCount != 0xffff)++entry->ObsoleteLoadCount;
if (entry->DdagNode->LoadCount != 0xffffffff)++entry->DdagNode->LoadCount;
}
if (Flags == FLAG_DEREFERENCE) {
if (entry->ObsoleteLoadCount)--entry->ObsoleteLoadCount;
if (entry->DdagNode->LoadCount)--entry->DdagNode->LoadCount;
}
break;
}
default:return STATUS_UNSUCCESSFUL;
}
if (Flags == FLAG_REFERENCE && pModule->dwReferenceCount != 0xffffffff)
++pModule->dwReferenceCount;
if (Flags == FLAG_DEREFERENCE && pModule->dwReferenceCount)
--pModule->dwReferenceCount;
return STATUS_SUCCESS;
}
static NTSTATUS NTAPI RtlGetReferenceCount(IN PLDR_DATA_TABLE_ENTRY LdrEntry, OUT PULONG Count) {
switch (NtWindowsVersion()) {
case xp:
case vista:
case win7: {
*Count = LdrEntry->LoadCount;
break;
}
case win8:
case win8_1:
case win10:
case win10_1:
case win10_2: {
auto entry = (PLDR_DATA_TABLE_ENTRY_WIN8)LdrEntry;
*Count = entry->DdagNode->LoadCount == entry->ObsoleteLoadCount ? entry->ObsoleteLoadCount : entry->DdagNode->LoadCount;
break;
}
default:return STATUS_UNSUCCESSFUL;
}
static NTSTATUS NTAPI RtlGetReferenceCount(IN PMEMORYMODULE pModule, OUT PULONG Count) {
*Count = pModule->dwReferenceCount;
return STATUS_SUCCESS;
}
@@ -366,7 +329,7 @@ static bool NTAPI RtlResolveDllNameUnicodeString(
FullLength += Length;
}
wcscpy(_DllFullName = new wchar_t[++FullLength], DllFullName);
if (add) wsprintfW(_DllFullName, L"%s\\%s", _DllFullName, _DllName);
if (add) swprintf(_DllFullName, L"%s\\%s", _DllFullName, _DllName);
}
else {
FullLength = 16 + 1 + Length; //hex(ULONG64) + '\\' + _DllName
@@ -631,7 +594,7 @@ NTSTATUS NTAPI LdrLoadDllMemoryExW(
(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(CurEntry, FLAG_REFERENCE);
RtlUpdateReferenceCount(module, FLAG_REFERENCE);
*BaseAddress = (HMEMORYMODULE)CurEntry->DllBase;
if (LdrEntry)*LdrEntry = CurEntry;
return STATUS_SUCCESS;
@@ -650,72 +613,87 @@ NTSTATUS NTAPI LdrLoadDllMemoryExW(
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) {
if (!LdrpExecuteTLS(module) || !LdrpCallInitializers(module, DLL_PROCESS_ATTACH)) {
status = STATUS_DLL_INIT_FAILED;
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;
}
status = LdrMapDllMemory(*BaseAddress, dwFlags, DllName, DllFullName, &ModuleEntry);
if (!NT_SUCCESS(status)) {
do {
status = LdrMapDllMemory(*BaseAddress, dwFlags, DllName, DllFullName, &ModuleEntry);
if (!NT_SUCCESS(status))break;
module->MappedDll = true;
status = MemoryResolveImportTable(LPBYTE(*BaseAddress), headers, module);
if (!NT_SUCCESS(status))break;
status = MemorySetSectionProtection(LPBYTE(*BaseAddress), headers);
if (!NT_SUCCESS(status))break;
if (!(dwFlags & LOAD_FLAGS_NOT_USE_REFERENCE_COUNT))module->UseReferenceCount = true;
if (!(dwFlags & LOAD_FLAGS_NOT_ADD_INVERTED_FUNCTION)) {
status = RtlInsertInvertedFunctionTable((PVOID)module->codeBase, headers->OptionalHeader.SizeOfImage);
if (!NT_SUCCESS(status)) break;
module->InsertInvertedFunctionTableEntry = true;
}
if (!(dwFlags & LOAD_FLAGS_NOT_HANDLE_TLS)) {
status = LdrpHandleTlsData(ModuleEntry);
if (!NT_SUCCESS(status)) {
if (dwFlags & LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS) status = 0x7fffffff;
if (!NT_SUCCESS(status))break;
}
else {
module->TlsHandled = true;
}
}
if (dwFlags & LOAD_FLAGS_HOOK_DOT_NET) {
MmpPreInitializeHooksForDotNet();
}
if (!LdrpExecuteTLS(module) || !LdrpCallInitializers(module, DLL_PROCESS_ATTACH)) {
status = STATUS_DLL_INIT_FAILED;
break;
}
if (dwFlags & LOAD_FLAGS_HOOK_DOT_NET) {
MmpInitializeHooksForDotNet();
}
} while (false);
if (NT_SUCCESS(status)) {
if (LdrEntry)*LdrEntry = ModuleEntry;
}
else {
LdrUnloadDllMemory(*BaseAddress);
*BaseAddress = nullptr;
return status;
}
module->MappedDll = true;
if (LdrEntry)*LdrEntry = ModuleEntry;
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)) {
LdrUnloadDllMemory(*BaseAddress);
*BaseAddress = nullptr;
if (LdrEntry)*LdrEntry = nullptr;
return status;
}
module->InsertInvertedFunctionTableEntry = true;
}
if (!(dwFlags & LOAD_FLAGS_NOT_HANDLE_TLS)) {
status = LdrpHandleTlsData(ModuleEntry);
if (!NT_SUCCESS(status)) {
do {
if (dwFlags & LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS) {
status = 0x7fffffff;
break;
}
LdrUnloadDllMemory(*BaseAddress);
*BaseAddress = nullptr;
if (LdrEntry)*LdrEntry = nullptr;
return status;
} while (false);
}
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;
LdrUnloadDllMemory(*BaseAddress);
return status;
}
if (dwFlags & LOAD_FLAGS_HOOK_DOT_NET) {
MmpInitializeHooksForDotNet();
}
return status;
@@ -774,7 +752,7 @@ NTSTATUS NTAPI LdrUnloadDllMemory(IN HMEMORYMODULE BaseAddress) {
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(BaseAddress);
if (headers->OptionalHeader.SizeOfImage == CurEntry->SizeOfImage) {
if (module->UseReferenceCount) {
status = RtlGetReferenceCount(CurEntry, &count);
status = RtlGetReferenceCount(module, &count);
if (!NT_SUCCESS(status))return status;
}
if (!(count & ~1)) {
@@ -802,7 +780,7 @@ NTSTATUS NTAPI LdrUnloadDllMemory(IN HMEMORYMODULE BaseAddress) {
return STATUS_SUCCESS;
}
else {
return RtlUpdateReferenceCount(CurEntry, FLAG_DEREFERENCE);
return RtlUpdateReferenceCount(module, FLAG_DEREFERENCE);
}
}
}
+18 -17
View File
@@ -19,31 +19,32 @@ static PVOID ReadDllFile(LPCSTR FileName) {
}
int main() {
HMEMORYMODULE hModule;
HMODULE hModule;
NTSTATUS status;
PVOID buffer = ReadDllFile("ManagedLib_x64.dll");
PVOID buffer = ReadDllFile("C:\\Windows\\System32\\user32.dll");
if (!buffer) return 0;
if (!buffer) {
return 0;
}
hModule = GetModuleHandleA("user32.dll");
if (hModule)return 0;
status = LdrLoadDllMemoryExW(
&hModule, // ModuleHandle
nullptr, // LdrEntry
LOAD_FLAGS_HOOK_DOT_NET, // Flags
buffer, // Buffer
0, // Reserved
nullptr, // DllBaseName
nullptr // DllFullName
&hModule, // ModuleHandle
nullptr, // LdrEntry
0, // Flags
buffer, // Buffer
0, // Reserved
L"user32.dll", // DllBaseName
L"C:\\Windows\\System32\\user32.dll" // DllFullName
);
if (NT_SUCCESS(status) && status != STATUS_IMAGE_MACHINE_TYPE_MISMATCH) {
int result = 0;
typedef VOID(WINAPI* func)(LPCSTR);
func f = (func)GetProcAddress(hModule, "ManagedExportFunc");
if (f)f("Hello World!");
auto _MessageBoxW = (decltype(&MessageBoxW))GetProcAddress(hModule, "MessageBoxW");
_MessageBoxW(nullptr, L"Hello, from memory user32!", L"Caption", MB_OK);
LdrUnloadDllMemory(hModule);
//
// After calling MessageBox, we can't free it.
//
//LdrUnloadDllMemory(hModule);
}
return 0;