diff --git a/MemoryModule/LoadDllMemoryApi.h b/MemoryModule/LoadDllMemoryApi.h index f6251486..0a413b50 100644 --- a/MemoryModule/LoadDllMemoryApi.h +++ b/MemoryModule/LoadDllMemoryApi.h @@ -11,25 +11,29 @@ typedef HMODULE HMEMORYMODULE; #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) #endif -HMEMORYMODULE WINAPI LoadLibraryMemory(_In_ PVOID BufferAddress); - -HMEMORYMODULE WINAPI LoadLibraryMemoryExA( - _In_ PVOID BufferAddress, - _In_ size_t Reserved, - _In_opt_ LPCSTR DllBaseName, - _In_opt_ LPCSTR DllFullName, - _In_ DWORD Flags -); - -HMEMORYMODULE WINAPI LoadLibraryMemoryExW( - _In_ PVOID BufferAddress, - _In_ size_t Reserved, - _In_opt_ LPCWSTR DllBaseName, - _In_opt_ LPCWSTR DllFullName, - _In_ DWORD Flags -); - -BOOL WINAPI FreeLibraryMemory(_In_ HMEMORYMODULE hMemoryModule); +extern "C" { + + HMEMORYMODULE WINAPI LoadLibraryMemory(_In_ PVOID BufferAddress); + + HMEMORYMODULE WINAPI LoadLibraryMemoryExA( + _In_ PVOID BufferAddress, + _In_ size_t Reserved, + _In_opt_ LPCSTR DllBaseName, + _In_opt_ LPCSTR DllFullName, + _In_ DWORD Flags + ); + + HMEMORYMODULE WINAPI LoadLibraryMemoryExW( + _In_ PVOID BufferAddress, + _In_ size_t Reserved, + _In_opt_ LPCWSTR DllBaseName, + _In_opt_ LPCWSTR DllFullName, + _In_ DWORD Flags + ); + + BOOL WINAPI FreeLibraryMemory(_In_ HMEMORYMODULE hMemoryModule); + +} #define NtLoadDllMemory LdrLoadDllMemory #define NtLoadDllMemoryExA LdrLoadDllMemoryExA diff --git a/MemoryModule/Loader.h b/MemoryModule/Loader.h index 8bdce287..a71afe7f 100644 --- a/MemoryModule/Loader.h +++ b/MemoryModule/Loader.h @@ -9,9 +9,6 @@ #define MEMORY_FEATURE_LDRP_RELEASE_TLS_ENTRY 0x00000040 #define MEMORY_FEATURE_ALL 0x0000007f -//Get the implementation of the currently running operating system. -NTSTATUS NTAPI LdrQuerySystemMemoryModuleFeatures(_Out_ PDWORD pFeatures); - /* LdrLoadDllMemoryEx dwFlags @@ -47,21 +44,24 @@ NTSTATUS NTAPI LdrQuerySystemMemoryModuleFeatures(_Out_ PDWORD pFeatures); //Hook for dotnet dlls #define LOAD_FLAGS_HOOK_DOT_NET 0x00000010 +extern "C" { -NTSTATUS NTAPI LdrLoadDllMemoryExW( - _Out_ HMEMORYMODULE* BaseAddress, // Output module base address - _Out_opt_ PVOID* LdrEntry, // Receive a pointer to the LDR node of the module - _In_ DWORD dwFlags, // Flags - _In_ LPVOID BufferAddress, // Pointer to the dll file data buffer - _In_ size_t Reserved, // Reserved parameter, must be 0 - _In_opt_ LPCWSTR DllName, // Module file name - _In_opt_ LPCWSTR DllFullName // Module file full path -); + //Get the implementation of the currently running operating system. + NTSTATUS NTAPI LdrQuerySystemMemoryModuleFeatures(_Out_ PDWORD pFeatures); + + NTSTATUS NTAPI LdrLoadDllMemoryExW( + _Out_ HMEMORYMODULE* BaseAddress, // Output module base address + _Out_opt_ PVOID* LdrEntry, // Receive a pointer to the LDR node of the module + _In_ DWORD dwFlags, // Flags + _In_ LPVOID BufferAddress, // Pointer to the dll file data buffer + _In_ size_t Reserved, // Reserved parameter, must be 0 + _In_opt_ LPCWSTR DllName, // Module file name + _In_opt_ LPCWSTR DllFullName // Module file full path + ); -//Unload modules previously loaded from memory -NTSTATUS NTAPI LdrUnloadDllMemory(_In_ HMEMORYMODULE BaseAddress); + //Unload modules previously loaded from memory + NTSTATUS NTAPI LdrUnloadDllMemory(_In_ HMEMORYMODULE BaseAddress); -extern "C" { __declspec(noreturn) VOID NTAPI LdrUnloadDllMemoryAndExitThread( _In_ HMEMORYMODULE BaseAddress, _In_ DWORD dwExitCode diff --git a/MemoryModule/MemoryModule.cpp b/MemoryModule/MemoryModule.cpp index 18db5a1f..34573acf 100644 --- a/MemoryModule/MemoryModule.cpp +++ b/MemoryModule/MemoryModule.cpp @@ -285,7 +285,7 @@ NTSTATUS MemoryLoadLibrary( PIMAGE_BASE_RELOCATION_HEADER relocation = (PIMAGE_BASE_RELOCATION_HEADER)(LPBYTE(base) + dir->VirtualAddress); if (dir->Size && dir->VirtualAddress) { - while (relocation->VirtualAddress > 0) { + while ((LPBYTE(relocation) < LPBYTE(base) + dir->VirtualAddress + dir->Size) && relocation->VirtualAddress > 0) { auto relInfo = (_REBASE_INFO*)&relocation->TypeOffset; for (DWORD i = 0; i < relocation->TypeOffsetCount(); ++i, ++relInfo) { switch (relInfo->Type) { diff --git a/MemoryModule/MemoryModulePP.def b/MemoryModule/MemoryModulePP.def index 7491bc1e..fcbae96d 100644 --- a/MemoryModule/MemoryModulePP.def +++ b/MemoryModule/MemoryModulePP.def @@ -1,5 +1,9 @@ LIBRARY EXPORTS + +MmInitialize +MmCleanup + LoadLibraryMemory LoadLibraryMemoryExA LoadLibraryMemoryExW diff --git a/MemoryModule/MmpLdrpTls.cpp b/MemoryModule/MmpLdrpTls.cpp index 9b97cf60..286ddd51 100644 --- a/MemoryModule/MmpLdrpTls.cpp +++ b/MemoryModule/MmpLdrpTls.cpp @@ -6,35 +6,13 @@ static bool stdcall; static PVOID LdrpHandleTlsData; static PVOID LdrpReleaseTlsEntry; -static NTSTATUS NTAPI RtlFindLdrpHandleTlsData() { +static NTSTATUS NTAPI RtlFindLdrpHandleTlsDataOld() { NTSTATUS status = STATUS_SUCCESS; LPCVOID Feature = nullptr; BYTE Size = 0; WORD OffsetOfFunctionBegin = 0; switch (MmpGlobalDataPtr->NtVersions.MajorVersion) { - case 10: { - if (MmpGlobalDataPtr->NtVersions.MinorVersion)return STATUS_NOT_SUPPORTED; - - if (MmpGlobalDataPtr->NtVersions.BuildNumber >= 22621) { -#ifdef _WIN64 - Feature = "\x39\x1D\x23\xFC\x17\x00\x74\x37\x44\x8D\x43\x09\x44\x39\x81\x0C\x01\x00\x00\x74\x2A"; - Size = 22; - OffsetOfFunctionBegin = 0x43; -#else - return STATUS_NOT_SUPPORTED; -#endif - } - // - // Add more conditions here. - // - // else if (MmpGlobalDataPtr->NtVersions.BuildNumber >= XXXXXXXXX) - else { - return STATUS_NOT_SUPPORTED; - } - - break; - } case 6: { switch (MmpGlobalDataPtr->NtVersions.MinorVersion) { //8.1 @@ -94,6 +72,83 @@ static NTSTATUS NTAPI RtlFindLdrpHandleTlsData() { return status; } +static NTSTATUS NTAPI RtlFindLdrpHandleTlsData10() { + LPVOID DllBase = MmpGlobalDataPtr->MmpBaseAddressIndex->NtdllLdrEntry->DllBase; +#ifdef _WIN64 + // search for LdrpHandleTls string literal + SEARCH_CONTEXT SearchContext{ SearchContext.SearchPattern = LPBYTE("LdrpHandleTlsData\x00"), SearchContext.PatternSize = 18 }; + if (!NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(HMODULE(DllBase), ".rdata", &SearchContext))) + return STATUS_NOT_SUPPORTED; + LPBYTE StringOffset = SearchContext.Result; + + SearchContext.Result = nullptr; + SearchContext.PatternSize = 3; + SearchContext.SearchPattern = LPBYTE("\x48\x8D\x15"); + LPBYTE ExceptionBlock = nullptr; + + // Search for lea rdx,[rip+0x????] + // ???? is the relative offset from RIP to LdrpHandleTls string literal + while (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(HMODULE(DllBase), ".text", &SearchContext))) { + DWORD InsOff = *(DWORD*)(SearchContext.Result + 3); + if (StringOffset == SearchContext.Result + InsOff + 7) { + ExceptionBlock = SearchContext.Result; + break; + } + } + if (!ExceptionBlock) return STATUS_NOT_SUPPORTED; + + // Search back for exception block function header + while (*ExceptionBlock != 0xcc) { + // Normally ~13 bytes, but just in case... + if (SearchContext.Result - ExceptionBlock > 0x50) return STATUS_NOT_SUPPORTED; + ExceptionBlock--; + } + ExceptionBlock++; + + // search for C_SCOPE_TABLE + union Converter { + BYTE Bytes[4]; + DWORD Dword; + }; + Converter ExceptionBlockAddress{}; // { .Dword = DWORD(ExceptionBlock - LPBYTE(DllBase)) }; + ExceptionBlockAddress.Dword = DWORD(ExceptionBlock - LPBYTE(DllBase)); + + SearchContext.Result = nullptr; + SearchContext.PatternSize = 4; + SearchContext.SearchPattern = ExceptionBlockAddress.Bytes; + if (!NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(HMODULE(DllBase), ".rdata", &SearchContext))) + return STATUS_NOT_SUPPORTED; + + // C_SCOPE_TABLE$$Begin + LPDWORD LdrpHandleTlsBlock = LPDWORD(*(LPDWORD)(SearchContext.Result - 8) + LPBYTE(DllBase)); + // Pad to 0x04 + LdrpHandleTlsBlock = LPDWORD(LONGLONG(LdrpHandleTlsBlock) / 0x04 * 0x04); + LPDWORD LdrpHandleTlsBlockBackup = LdrpHandleTlsBlock; + + // Search back for LdrpHandleTls + // Search up for 4 consecutive 0xCC + while (*LdrpHandleTlsBlock != 0xcccccccc) { + // Normally ~0x140 bytes + if (LdrpHandleTlsBlockBackup - LdrpHandleTlsBlock > 0x400) return STATUS_NOT_SUPPORTED; + LdrpHandleTlsBlock--; + } + LdrpHandleTlsBlock++; + LdrpHandleTlsData = LdrpHandleTlsBlock; + return STATUS_SUCCESS; +#else + return STATUS_NOT_SUPPORTED; +#endif +} + +static NTSTATUS NTAPI RtlFindLdrpHandleTlsData() { + if (MmpGlobalDataPtr->NtVersions.MajorVersion >= 10) { + return RtlFindLdrpHandleTlsData10(); + } + else { + return RtlFindLdrpHandleTlsDataOld(); + } +} + static NTSTATUS NTAPI RtlFindLdrpReleaseTlsEntry() { NTSTATUS status = STATUS_SUCCESS; LPCVOID Feature = nullptr; @@ -104,23 +159,12 @@ static NTSTATUS NTAPI RtlFindLdrpReleaseTlsEntry() { case 10: { if (MmpGlobalDataPtr->NtVersions.MinorVersion) return STATUS_NOT_SUPPORTED; - if (MmpGlobalDataPtr->NtVersions.BuildNumber >= 22621) { #ifdef _WIN64 - Feature = "\x74\x34\x48\x8B\x08\x48\x39\x41\x08\x75\x65\x48\x8B\x40\x08\x48\x39\x18\x75\x5C\x48\x89\x08"; - Size = 24; - OffsetOfFunctionBegin = 0x2F; + Feature = "\x48\x89\x5c\x24\x08\x57\x48\x83\xec\x20\x48\x8b\xfa\x48\x8b\xd9\x48\x85\xd2\x75\x0c"; + Size = 21; #else - return STATUS_NOT_SUPPORTED; + return STATUS_NOT_SUPPORTED; #endif - } - // - // Add more conditions here. - // - // else if (MmpGlobalDataPtr->NtVersions.BuildNumber >= XXXXXXXXX) - else { - return STATUS_NOT_SUPPORTED; - } - break; } default: @@ -150,6 +194,10 @@ BOOL NTAPI MmpTlsInitialize() { return TRUE; } +VOID NTAPI MmpTlsCleanup() { + ; +} + NTSTATUS NTAPI MmpReleaseTlsEntry(_In_ PLDR_DATA_TABLE_ENTRY lpModuleEntry) { typedef NTSTATUS(__stdcall* STDCALL)(PLDR_DATA_TABLE_ENTRY, PVOID*); typedef NTSTATUS(__thiscall* THISCALL)(PLDR_DATA_TABLE_ENTRY, PVOID*); diff --git a/MemoryModule/MmpTls.cpp b/MemoryModule/MmpTls.cpp index 733e6b27..71f7d358 100644 --- a/MemoryModule/MmpTls.cpp +++ b/MemoryModule/MmpTls.cpp @@ -7,6 +7,7 @@ #include #include #include <3rdparty/Detours/detours.h> +#include PVOID NTAPI MmpQuerySystemInformation( @@ -402,6 +403,96 @@ BOOL NTAPI PreHookNtSetInformationProcess() { return success; } +int MmpSyncThreadTlsData() { + PSYSTEM_PROCESS_INFORMATION pspi = (PSYSTEM_PROCESS_INFORMATION)MmpQuerySystemInformation(SYSTEM_INFORMATION_CLASS::SystemProcessInformation, nullptr); + PSYSTEM_PROCESS_INFORMATION current = pspi; + std::setthreads; + int count = 0; + + // + // Build thread id set. + // + + PLIST_ENTRY entry = MmpGlobalDataPtr->MmpTls->MmpThreadLocalStoragePointer.Flink; + while (entry != &MmpGlobalDataPtr->MmpTls->MmpThreadLocalStoragePointer) { + PMMP_TLSP_RECORD j = CONTAINING_RECORD(entry, MMP_TLSP_RECORD, InMmpThreadLocalStoragePointer); + threads.insert(j->UniqueThread); + + entry = entry->Flink; + } + + while (pspi) { + + if (current->UniqueProcessId == NtCurrentTeb()->ClientId.UniqueProcess) { + + for (ULONG index = 0; index < current->NumberOfThreads; ++index) { + CLIENT_ID cid = current->Threads[index].ClientId; + + if (threads.find(cid.UniqueThread) == threads.end()) { + + HANDLE hThread; + OBJECT_ATTRIBUTES oa{}; + NTSTATUS status = NtOpenThread(&hThread, THREAD_QUERY_INFORMATION, &oa, &cid); + if (NT_SUCCESS(status)) { + + THREAD_BASIC_INFORMATION tbi{}; + status = NtQueryInformationThread(hThread, THREADINFOCLASS::ThreadBasicInformation, &tbi, sizeof(tbi), nullptr); + if (NT_SUCCESS(status)) { + + PTEB teb = tbi.TebBaseAddress; + if (teb->ThreadLocalStoragePointer) { + + // + // Allocate TLS record + // + + auto record = PMMP_TLSP_RECORD(RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(MMP_TLSP_RECORD))); + if (record) { + record->TlspLdrBlock = (PVOID*)teb->ThreadLocalStoragePointer; + record->TlspMmpBlock = (PVOID*)MmpAllocateTlsp(); + record->UniqueThread = cid.UniqueThread; + if (record->TlspMmpBlock) { + record->TlspMmpBlock = ((PTLS_VECTOR)record->TlspMmpBlock)->ModuleTlsData; + + auto size = CONTAINING_RECORD(record->TlspLdrBlock, TLS_VECTOR, ModuleTlsData)->Length; + if ((HANDLE)(ULONG_PTR)size != record->UniqueThread) { + RtlCopyMemory( + record->TlspMmpBlock, + record->TlspLdrBlock, + size * sizeof(PVOID) + ); + } + + teb->ThreadLocalStoragePointer = record->TlspMmpBlock; + InsertTailList(&MmpGlobalDataPtr->MmpTls->MmpThreadLocalStoragePointer, &record->InMmpThreadLocalStoragePointer); + InterlockedIncrement(&MmpGlobalDataPtr->MmpTls->MmpActiveThreadCount); + + ++count; + } + else { + RtlFreeHeap(RtlProcessHeap(), 0, record); + } + } + } + } + + NtClose(hThread); + } + + } + } + + break; + } + + if (!current->NextEntryOffset)break; + current = (PSYSTEM_PROCESS_INFORMATION)((PBYTE)current + current->NextEntryOffset); + } + + RtlFreeHeap(RtlProcessHeap(), 0, pspi); + return count; +} + NTSTATUS NTAPI HookNtSetInformationProcess( _In_opt_ HANDLE ProcessHandle, _In_ PROCESSINFOCLASS ProcessInformationClass, @@ -423,6 +514,12 @@ NTSTATUS NTAPI HookNtSetInformationProcess( PPROCESS_TLS_INFORMATION Tls = nullptr; NTSTATUS status = STATUS_SUCCESS; + // + // Sync thread data with ntdll!Ldr. + // + + MmpSyncThreadTlsData(); + do { if (ProcessTlsInformation->OperationType >= MaxProcessTlsOperation) { status = STATUS_INVALID_PARAMETER; @@ -456,7 +553,7 @@ NTSTATUS NTAPI HookNtSetInformationProcess( break; } - // reserved 0x50 PVOID for ntdll loader + // reserved 0x80 PVOID for ntdll loader if (ProcessTlsInformation->TlsVectorLength >= MMP_START_TLS_INDEX) { status = STATUS_NO_MEMORY; break; @@ -496,50 +593,55 @@ NTSTATUS NTAPI HookNtSetInformationProcess( // EnterCriticalSection(&MmpGlobalDataPtr->MmpTls->MmpTlspLock); for (ULONG i = 0; i < Tls->ThreadDataCount; ++i) { - BOOL found = FALSE; - PLIST_ENTRY entry = MmpGlobalDataPtr->MmpTls->MmpThreadLocalStoragePointer.Flink; - // Find thread-spec tlsp - while (entry != &MmpGlobalDataPtr->MmpTls->MmpThreadLocalStoragePointer) { + if (Tls->ThreadData[i].Flags == 2) { - PMMP_TLSP_RECORD j = CONTAINING_RECORD(entry, MMP_TLSP_RECORD, InMmpThreadLocalStoragePointer); + BOOL found = FALSE; + PLIST_ENTRY entry = MmpGlobalDataPtr->MmpTls->MmpThreadLocalStoragePointer.Flink; - if (ProcessTlsInformation->OperationType == ProcessTlsReplaceVector) { - if (j->TlspMmpBlock[ProcessTlsInformation->TlsVectorLength] == ProcessTlsInformation->ThreadData[i].TlsVector[ProcessTlsInformation->TlsVectorLength]) { - found = TRUE; + // Find thread-spec tlsp + while (entry != &MmpGlobalDataPtr->MmpTls->MmpThreadLocalStoragePointer) { - // Copy old data to new pointer - RtlCopyMemory( - ProcessTlsInformation->ThreadData[i].TlsVector, - j->TlspMmpBlock, - sizeof(PVOID) * ProcessTlsInformation->TlsVectorLength - ); + PMMP_TLSP_RECORD j = CONTAINING_RECORD(entry, MMP_TLSP_RECORD, InMmpThreadLocalStoragePointer); - // Swap the tlsp - std::swap( - j->TlspLdrBlock, - ProcessTlsInformation->ThreadData[i].TlsVector - ); + if (ProcessTlsInformation->OperationType == ProcessTlsReplaceVector) { + if (j->TlspMmpBlock[ProcessTlsInformation->TlsVectorLength] == ProcessTlsInformation->ThreadData[i].TlsVector[ProcessTlsInformation->TlsVectorLength]) { + found = TRUE; + + // Copy old data to new pointer + RtlCopyMemory( + ProcessTlsInformation->ThreadData[i].TlsVector, + j->TlspMmpBlock, + sizeof(PVOID) * ProcessTlsInformation->TlsVectorLength + ); + + // Swap the tlsp + std::swap( + j->TlspLdrBlock, + ProcessTlsInformation->ThreadData[i].TlsVector + ); + } } - } - else { - if (j->TlspMmpBlock[ProcessTlsInformation->TlsIndex] == ProcessTlsInformation->ThreadData[i].TlsModulePointer) { - found = TRUE; + else { + if (j->TlspMmpBlock[ProcessTlsInformation->TlsIndex] == ProcessTlsInformation->ThreadData[i].TlsModulePointer) { + found = TRUE; + + if (ProcessHandle) { + j->TlspLdrBlock[ProcessTlsInformation->TlsIndex] = ProcessTlsInformation->ThreadData[i].TlsModulePointer; + } - if (ProcessHandle) { - j->TlspLdrBlock[ProcessTlsInformation->TlsIndex] = ProcessTlsInformation->ThreadData[i].TlsModulePointer; + ProcessTlsInformation->ThreadData[i].TlsModulePointer = Tls->ThreadData[i].TlsModulePointer; } - - ProcessTlsInformation->ThreadData[i].TlsModulePointer = Tls->ThreadData[i].TlsModulePointer; } + + if (found)break; + entry = entry->Flink; } - if (found)break; - entry = entry->Flink; + ProcessTlsInformation->ThreadData[i].Flags = Tls->ThreadData[i].Flags; + ProcessTlsInformation->ThreadData[i].ThreadId = Tls->ThreadData[i].ThreadId; } - ProcessTlsInformation->ThreadData[i].Flags = Tls->ThreadData[i].Flags; - ProcessTlsInformation->ThreadData[i].ThreadId = Tls->ThreadData[i].ThreadId; } LeaveCriticalSection(&MmpGlobalDataPtr->MmpTls->MmpTlspLock);