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);