diff --git a/MemoryModule/MemoryModule.h b/MemoryModule/MemoryModule.h index 3767cf0..504d8ea 100644 --- a/MemoryModule/MemoryModule.h +++ b/MemoryModule/MemoryModule.h @@ -57,8 +57,9 @@ typedef struct _MEMORYMODULE { //Load Flags WORD MappedDll : 1; WORD InsertInvertedFunctionTableEntry : 1; + WORD TlsHandled : 1; WORD UseReferenceCount : 1; - WORD reservedLoadFlags : 13; + WORD reservedLoadFlags : 12; }; DWORD dwFlags; diff --git a/MemoryModule/MemoryModule.vcxproj b/MemoryModule/MemoryModule.vcxproj index d69b04a..b0889c4 100644 --- a/MemoryModule/MemoryModule.vcxproj +++ b/MemoryModule/MemoryModule.vcxproj @@ -71,6 +71,7 @@ true v142 Unicode + Spectre StaticLibrary diff --git a/MemoryModule/NativeFunctionsInternal.cpp b/MemoryModule/NativeFunctionsInternal.cpp index 4d165ab..a1aacd2 100644 --- a/MemoryModule/NativeFunctionsInternal.cpp +++ b/MemoryModule/NativeFunctionsInternal.cpp @@ -71,9 +71,9 @@ static NTSTATUS NTAPI RtlInsertModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENT return STATUS_SUCCESS; } static NTSTATUS NTAPI RtlRemoveModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTRY DataTableEntry) { + DebugBreak(); static auto tree{ RtlFindLdrpModuleBaseAddressIndex() }; if (!tree->Root)return STATUS_UNSUCCESSFUL; - RtlRbRemoveNode(tree, &PLDR_DATA_TABLE_ENTRY_WIN8(DataTableEntry)->BaseAddressIndexNode); return STATUS_SUCCESS; } @@ -646,6 +646,9 @@ NTSTATUS NTAPI LdrLoadDllMemoryExW( return status; } while (false); } + else { + module->TlsHandled = true; + } } return status; @@ -713,6 +716,11 @@ NTSTATUS NTAPI LdrUnloadDllMemory(IN HMEMORYMODULE BaseAddress) { status = RtlRemoveInvertedFunctionTable(BaseAddress); if (!NT_SUCCESS(status))__fastfail(FAST_FAIL_CORRUPT_LIST_ENTRY); } + if (module->TlsHandled) { + + status = LdrpReleaseTlsEntry(CurEntry); + if (!NT_SUCCESS(status)) __fastfail(FAST_FAIL_FATAL_APP_EXIT); + } if (!RtlFreeLdrDataTableEntry(CurEntry))__fastfail(FAST_FAIL_FATAL_APP_EXIT); } if (!MemoryFreeLibrary(BaseAddress))__fastfail(FAST_FAIL_FATAL_APP_EXIT); @@ -748,7 +756,7 @@ NTSTATUS NTAPI LdrQuerySystemMemoryModuleFeatures(OUT PDWORD pFeatures) { 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; - + if (NT_SUCCESS(RtlFindLdrpReleaseTlsEntry(&pfn, &value) && pfn))features |= MEMORY_FEATURE_LDRP_RELEASE_TLS_ENTRY; if (features)features |= MEMORY_FEATURE_SUPPORT_VERSION; *pFeatures = features; } diff --git a/MemoryModule/NativeFunctionsInternal.h b/MemoryModule/NativeFunctionsInternal.h index 17962ab..9ee9ed0 100644 --- a/MemoryModule/NativeFunctionsInternal.h +++ b/MemoryModule/NativeFunctionsInternal.h @@ -20,7 +20,8 @@ NTSTATUS NTAPI LdrLoadDllMemory( #define MEMORY_FEATURE_LDRP_HASH_TABLE 0x00000008 #define MEMORY_FEATURE_INVERTED_FUNCTION_TABLE 0x00000010 #define MEMORY_FEATURE_LDRP_HANDLE_TLS_DATA 0x00000020 -#define MEMORY_FEATURE_ALL 0x0000003f +#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); diff --git a/MemoryModule/rtlldr.cpp b/MemoryModule/rtlldr.cpp index d8af206..3f0b2e6 100644 --- a/MemoryModule/rtlldr.cpp +++ b/MemoryModule/rtlldr.cpp @@ -1,6 +1,8 @@ #include "rtlldr.h" #pragma warning(disable:4996) +PLDR_DATA_TABLE_ENTRY const LdrpNtdllBase = RtlFindLdrTableEntryByBaseName(L"ntdll.dll"); + VOID NTAPI RtlRbInsertNodeEx(IN PRTL_RB_TREE Tree, IN PRTL_BALANCED_NODE Parent, IN BOOLEAN Right, OUT PRTL_BALANCED_NODE Node) { decltype(&RtlRbInsertNodeEx)_RtlRbInsertNodeEx = decltype(_RtlRbInsertNodeEx)(RtlGetNtProcAddress("RtlRbInsertNodeEx")); if (!_RtlRbInsertNodeEx)return; diff --git a/MemoryModule/rtlldr.h b/MemoryModule/rtlldr.h index c84bedb..2f2a80d 100644 --- a/MemoryModule/rtlldr.h +++ b/MemoryModule/rtlldr.h @@ -5,7 +5,9 @@ PLDR_DATA_TABLE_ENTRY NTAPI RtlFindLdrTableEntryByHandle(PVOID BaseAddress); PLDR_DATA_TABLE_ENTRY NTAPI RtlFindLdrTableEntryByBaseName(PCWSTR BaseName); -#define RtlFindNtdllLdrEntry() RtlFindLdrTableEntryByBaseName(L"ntdll.dll") +extern PLDR_DATA_TABLE_ENTRY const LdrpNtdllBase; + +#define RtlFindNtdllLdrEntry() (LdrpNtdllBase) @@ -330,6 +332,8 @@ typedef struct _LDR_DATA_TABLE_ENTRY_WIN10_1 :public _LDR_DATA_TABLE_ENTRY_WIN10 //10.0.17134 Windows 10 | 2016 1803 Redstone 4 (Spring Creators Update) //10.0.17763 Windows 10 | 2016 1809 Redstone 5 (October Update) //10.0.18362 Windows 10 | 2016 1903 19H1 (May 2019 Update) | 2016 1909 19H2 (November 2019 Update) +//10.0.19041 Windows 10 | 2016 2004 20H1 (May 2020 Update) +//10.0.19042 Windows 10 | 2016 2009 20H2 (October 2020 Update) typedef struct _LDR_DATA_TABLE_ENTRY_WIN10_2 { _LIST_ENTRY InLoadOrderLinks; //0x0 _LIST_ENTRY InMemoryOrderLinks; //0x10 diff --git a/MemoryModule/rtltls.cpp b/MemoryModule/rtltls.cpp index d795b6d..ce0fb7d 100644 --- a/MemoryModule/rtltls.cpp +++ b/MemoryModule/rtltls.cpp @@ -134,32 +134,107 @@ NTSTATUS NTAPI RtlFindLdrpHandleTlsData(PVOID* _LdrpHandleTlsData, bool* stdcall } SEARCH_CONTEXT SearchContext{ SearchContext.MemoryBuffer = const_cast(Feature),SearchContext.BufferLength = Size - 1 }; - if (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(GetModuleHandleW(L"ntdll.dll"), ".text", &SearchContext))) + if (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(HMODULE(RtlFindNtdllLdrEntry()->DllBase), ".text", &SearchContext))) SearchContext.OutBufferPtr -= OffsetOfFunctionBegin; if (!(*_LdrpHandleTlsData = _LdrpHandleTlsData_ = SearchContext.MemoryBlockInSection))return STATUS_NOT_SUPPORTED; *stdcall = !RtlIsWindowsVersionOrGreater(6, 3, 0); return status; } -NTSTATUS NTAPI LdrpHandleTlsData(IN PLDR_DATA_TABLE_ENTRY LdrEntry) { - typedef NTSTATUS(__thiscall* _PTR_WIN8_1)(PLDR_DATA_TABLE_ENTRY LdrEntry); - typedef NTSTATUS(__stdcall* _PTR_WIN)(PLDR_DATA_TABLE_ENTRY LdrEntry); - union _FUNCTION_SET { - _PTR_WIN8_1 Win8_1_OrGreater; - _PTR_WIN Default; - _FUNCTION_SET() { - this->Default = nullptr; +NTSTATUS NTAPI RtlFindLdrpReleaseTlsEntry(PVOID* _LdrpReleaseTlsEntry, bool* stdcall) { + static PVOID _LdrpReleaseTlsEntry_ = (PVOID)~0; + NTSTATUS status = STATUS_SUCCESS; + + __try { + if (_LdrpReleaseTlsEntry_ != (PVOID)~0) { + *_LdrpReleaseTlsEntry = _LdrpReleaseTlsEntry_; + if (!_LdrpReleaseTlsEntry_)status = STATUS_NOT_SUPPORTED; } - operator bool() { - return this->Default != nullptr; + else { + *_LdrpReleaseTlsEntry = _LdrpReleaseTlsEntry_ = nullptr; + *stdcall = false; } - }; - static _FUNCTION_SET _LdrpHandleTlsData{}; - static bool stdcall = false; - NTSTATUS status; - if (!_LdrpHandleTlsData) { - status = RtlFindLdrpHandleTlsData((PVOID*)&_LdrpHandleTlsData.Default, &stdcall); - if (!NT_SUCCESS(status))return status; } - return stdcall ? _LdrpHandleTlsData.Default(LdrEntry) : _LdrpHandleTlsData.Win8_1_OrGreater(LdrEntry); + __except (EXCEPTION_EXECUTE_HANDLER) { + status = GetExceptionCode(); + } + if (!NT_SUCCESS(status))return status; + + DWORD Versions[3]{}; + LPCVOID Feature = nullptr; + BYTE Size = 0; + WORD OffsetOfFunctionBegin = 0; + RtlGetNtVersionNumbers(Versions, Versions + 1, Versions + 2); + switch (Versions[0]) { + case 10: { + if (Versions[1]) { + status = STATUS_NOT_SUPPORTED; + break; + } + if (Versions[2] >= 19041) { + Size = 0x10; + OffsetOfFunctionBegin = 0x2F; + Feature = "\x74\x26\x48\x8B\x00\x48\x39\x58\x08\x75\x5D\x48\x8B\x4B\x08"; + break; + } + } + default: + status = STATUS_NOT_SUPPORTED; + } + + if (!NT_SUCCESS(status)) { + return status; + } + + SEARCH_CONTEXT SearchContext{ SearchContext.MemoryBuffer = const_cast(Feature),SearchContext.BufferLength = Size - 1 }; + if (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(HMODULE(RtlFindNtdllLdrEntry()->DllBase), ".text", &SearchContext))) + SearchContext.OutBufferPtr -= OffsetOfFunctionBegin; + if (!(*_LdrpReleaseTlsEntry = _LdrpReleaseTlsEntry_ = SearchContext.MemoryBlockInSection))return STATUS_NOT_SUPPORTED; + *stdcall = !RtlIsWindowsVersionOrGreater(6, 3, 0); + return status; +} + +static NTSTATUS NTAPI RtlInvokeTlsHandler(IN PLDR_DATA_TABLE_ENTRY LdrEntry, IN BOOLEAN Release) { + static bool stdcall = false; + union _FUNCTION_SET { + struct { + NTSTATUS(__stdcall* LdrpHandleTlsData)(PLDR_DATA_TABLE_ENTRY LdrEntry); + NTSTATUS(__stdcall* LdrpReleaseTlsEntry)(PLDR_DATA_TABLE_ENTRY LdrEntry, DWORD); + }Default; + + struct { + NTSTATUS(__thiscall* LdrpHandleTlsData)(PLDR_DATA_TABLE_ENTRY LdrEntry); + NTSTATUS(__thiscall* LdrpReleaseTlsEntry)(PLDR_DATA_TABLE_ENTRY LdrEntry, DWORD); + }WinBlue; + + _FUNCTION_SET() { + RtlFindLdrpHandleTlsData((PVOID*)(&this->Default.LdrpHandleTlsData), &stdcall); + RtlFindLdrpReleaseTlsEntry((PVOID*)(&this->Default.LdrpReleaseTlsEntry), &stdcall); + + if (!this->Default.LdrpHandleTlsData || !this->Default.LdrpReleaseTlsEntry) { + this->Default = {}; + } + } + + }static InvokeHandler; + + if (Release) { + if (InvokeHandler.Default.LdrpReleaseTlsEntry) { + return (stdcall ? InvokeHandler.Default.LdrpReleaseTlsEntry : InvokeHandler.WinBlue.LdrpReleaseTlsEntry)(LdrEntry, 0); + } + } + else { + if (InvokeHandler.Default.LdrpHandleTlsData) { + return (stdcall ? InvokeHandler.Default.LdrpHandleTlsData : InvokeHandler.WinBlue.LdrpHandleTlsData)(LdrEntry); + } + } + return STATUS_NOT_SUPPORTED; +} + +NTSTATUS NTAPI LdrpHandleTlsData(IN PLDR_DATA_TABLE_ENTRY LdrEntry) { + return RtlInvokeTlsHandler(LdrEntry, FALSE); +} + +NTSTATUS NTAPI LdrpReleaseTlsEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) { + return RtlInvokeTlsHandler(LdrEntry, TRUE); } diff --git a/MemoryModule/rtltls.h b/MemoryModule/rtltls.h index 838a8d5..4efc052 100644 --- a/MemoryModule/rtltls.h +++ b/MemoryModule/rtltls.h @@ -3,4 +3,9 @@ NTSTATUS NTAPI RtlFindLdrpHandleTlsData(PVOID* _LdrpHandleTlsData, bool* stdcall); +NTSTATUS NTAPI RtlFindLdrpReleaseTlsEntry(PVOID* _LdrpReleaseTlsEntry, bool* stdcall); + NTSTATUS NTAPI LdrpHandleTlsData(IN PLDR_DATA_TABLE_ENTRY LdrEntry); + +NTSTATUS NTAPI LdrpReleaseTlsEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry); + diff --git a/test/test.cpp b/test/test.cpp index 8e2aa28..24a55d5 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -169,19 +169,14 @@ int main() { //test_ws2_32(); auto a = ReadDllFile("a.dll"); - auto LdrpReleaseTlsEntry = (NTSTATUS(*)(PVOID, PVOID)) 0x00007FFE2BC4D4A0; //LOAD_FLAGS_NOT_HANDLE_TLS HMEMORYMODULE p1 = LoadLibraryMemoryExA(a, 0, "a.dll", nullptr, 0), - p2 = nullptr;//LoadLibraryMemoryExA(a, 0, "b.dll", nullptr, 0); - - PVOID ldr; - LdrLoadDllMemoryExW(&p2, &ldr, 0, a, 0, L"b.dll", nullptr); + p2 = LoadLibraryMemoryExA(a, 0, "b.dll", nullptr, 0); delete[]a; - //LdrpReleaseTlsEntry(ldr, nullptr); FreeLibraryMemory(p2); - + HANDLE hThread = CreateThread(nullptr, 0, thread, nullptr, 0, nullptr); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread);