From 446bb917d96a34344ff4e381141d0c8bb644f5a5 Mon Sep 17 00:00:00 2001 From: Boring <1079299053@qq.com> Date: Mon, 11 Jul 2022 13:33:59 +0800 Subject: [PATCH] Resolve IAT after insert LdrDataTableEntry --- MemoryModule/MemoryModule.cpp | 239 ++++++++++++----------- MemoryModule/MemoryModule.h | 13 +- MemoryModule/MmpTls.cpp | 8 - MemoryModule/NativeFunctionsInternal.cpp | 190 ++++++++---------- test/test.cpp | 35 ++-- 5 files changed, 238 insertions(+), 247 deletions(-) diff --git a/MemoryModule/MemoryModule.cpp b/MemoryModule/MemoryModule.cpp index f975b08..9483431 100644 --- a/MemoryModule/MemoryModule.cpp +++ b/MemoryModule/MemoryModule.cpp @@ -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; } diff --git a/MemoryModule/MemoryModule.h b/MemoryModule/MemoryModule.h index c1d9b4b..947ee51 100644 --- a/MemoryModule/MemoryModule.h +++ b/MemoryModule/MemoryModule.h @@ -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); diff --git a/MemoryModule/MmpTls.cpp b/MemoryModule/MmpTls.cpp index bf62d6c..3e36b7f 100644 --- a/MemoryModule/MmpTls.cpp +++ b/MemoryModule/MmpTls.cpp @@ -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; } diff --git a/MemoryModule/NativeFunctionsInternal.cpp b/MemoryModule/NativeFunctionsInternal.cpp index ba1a0a9..dfd6a21 100644 --- a/MemoryModule/NativeFunctionsInternal.cpp +++ b/MemoryModule/NativeFunctionsInternal.cpp @@ -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); } } } diff --git a/test/test.cpp b/test/test.cpp index ed64684..dcb4256 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -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;