diff --git a/MemoryModule/LoadDllMemoryApi.h b/MemoryModule/LoadDllMemoryApi.h index 9987f57..f31a078 100644 --- a/MemoryModule/LoadDllMemoryApi.h +++ b/MemoryModule/LoadDllMemoryApi.h @@ -52,6 +52,7 @@ int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int); */ int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD); + NTSTATUS NTAPI NtLoadDllMemory( OUT HMEMORYMODULE* BaseAddress, IN LPVOID BufferAddress, @@ -59,7 +60,7 @@ NTSTATUS NTAPI NtLoadDllMemory( ); /* - NtLoadDllMemoryEx dwFlags + NtLoadDllMemoryEx dwFlags */ //If this flag is specified, all subsequent flags will be ignored. @@ -77,12 +78,15 @@ NTSTATUS NTAPI NtLoadDllMemory( //If this flag is specified, DllName and DllFullName cannot be nullptr, // they can be arbitrary strings without having to be correct file names and paths. //Otherwise, DllName and DllFullName will use random names if they are nullptr. -//For compatibility with GetModuleHandle, DllName and DllFullName should be guaranteed to always end in .dll +//For compatibility with GetModuleHandle, DllName and DllFullName should be guaranteed to always end in ".dll" #define LOAD_FLAGS_USE_DLL_NAME 0x00000004 +//Dont call LdrpHandleTlsData routine if this flag is specified. +#define LOAD_FLAGS_NOT_HANDLE_TLS 0x00000008 + NTSTATUS NTAPI NtLoadDllMemoryExW( OUT HMEMORYMODULE* BaseAddress, - OUT PLDR_DATA_TABLE_ENTRY* LdrEntry OPTIONAL, + OUT PVOID* LdrEntry OPTIONAL, IN DWORD dwFlags, IN LPVOID BufferAddress, IN size_t BufferSize, @@ -91,7 +95,7 @@ NTSTATUS NTAPI NtLoadDllMemoryExW( ); NTSTATUS NTAPI NtLoadDllMemoryExA( OUT HMEMORYMODULE* BaseAddress, - OUT PLDR_DATA_TABLE_ENTRY* LdrEntry OPTIONAL, + OUT PVOID* LdrEntry OPTIONAL, IN DWORD dwFlags, IN LPVOID BufferAddress, IN size_t BufferSize, diff --git a/MemoryModule/MemoryModule.vcxproj b/MemoryModule/MemoryModule.vcxproj index 50fcccf..4882657 100644 --- a/MemoryModule/MemoryModule.vcxproj +++ b/MemoryModule/MemoryModule.vcxproj @@ -30,6 +30,9 @@ + + + 16.0 {5B1F46DB-036E-4A50-AF5F-F5D6584D42C6} diff --git a/MemoryModule/MemoryModule.vcxproj.filters b/MemoryModule/MemoryModule.vcxproj.filters index e397dd5..52ad386 100644 --- a/MemoryModule/MemoryModule.vcxproj.filters +++ b/MemoryModule/MemoryModule.vcxproj.filters @@ -42,4 +42,9 @@ Header Files + + + Resource Files + + \ No newline at end of file diff --git a/MemoryModule/NativeFunctionsInternal.cpp b/MemoryModule/NativeFunctionsInternal.cpp index 557890e..d9af99d 100644 --- a/MemoryModule/NativeFunctionsInternal.cpp +++ b/MemoryModule/NativeFunctionsInternal.cpp @@ -274,15 +274,15 @@ static NTSTATUS NTAPI NtRemoveModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTR static bool NTAPI NtInitializeLdrDataTableEntry( OUT PLDR_DATA_TABLE_ENTRY LdrEntry, + IN DWORD dwFlags, IN PVOID BaseAddress, - IN ULONG SizeofImage, - IN DWORD TimeDateStamp, IN UNICODE_STRING &DllBaseName, - IN UNICODE_STRING &DllFullName, - IN PVOID EntryPoint) { - + IN UNICODE_STRING &DllFullName) { + UNREFERENCED_PARAMETER(dwFlags); RtlZeroMemory(LdrEntry, NtLdrDataTableEntrySize()); PIMAGE_NT_HEADERS headers = RtlImageNtHeader(BaseAddress); + if (!headers)return false; + bool FlagsProcessed = false; switch (NtWindowsVersion()) { case win10: @@ -300,11 +300,16 @@ static bool NTAPI NtInitializeLdrDataTableEntry( entry->LoadReason = LoadReasonDynamicLoad; if (!NT_SUCCESS(NtInsertModuleBaseAddressIndexNode(LdrEntry, BaseAddress)))return false; if (!(entry->DdagNode = (decltype(entry->DdagNode))NtAllocateLdrpHeap(sizeof(_LDR_DDAG_NODE))))return false; - NtInitializeListEntry(&entry->NodeModuleLink); - NtInitializeListEntry(&entry->DdagNode->Modules); - NtInitializeSingleEntry(&entry->DdagNode->CondenseLink); + //NtInitializeListEntry(&entry->NodeModuleLink); + //NtInitializeListEntry(&entry->DdagNode->Modules); + entry->NodeModuleLink.Flink = &entry->DdagNode->Modules; + entry->NodeModuleLink.Blink = &entry->DdagNode->Modules; + entry->DdagNode->Modules.Flink = &entry->NodeModuleLink; + entry->DdagNode->Modules.Blink = &entry->NodeModuleLink; entry->DdagNode->State = LdrModulesReadyToRun; entry->DdagNode->LoadCount = 0; + + NtInitializeSingleEntry(&entry->DdagNode->CondenseLink); } case win7: { @@ -325,12 +330,13 @@ static bool NTAPI NtInitializeLdrDataTableEntry( } case xp: { LdrEntry->DllBase = BaseAddress; - LdrEntry->SizeOfImage = SizeofImage; - LdrEntry->TimeDateStamp = TimeDateStamp; + LdrEntry->SizeOfImage = headers->OptionalHeader.SizeOfImage; + LdrEntry->TimeDateStamp = headers->FileHeader.TimeDateStamp; LdrEntry->BaseDllName = DllBaseName; LdrEntry->FullDllName = DllFullName; - LdrEntry->EntryPoint = EntryPoint; - if (headers->OptionalHeader.DllCharacteristics & IMAGE_FILE_DLL)LdrEntry->Flags |= LDRP_IMAGE_DLL; + LdrEntry->EntryPoint = (PVOID)((size_t)BaseAddress + headers->OptionalHeader.AddressOfEntryPoint); + if (!FlagsProcessed) LdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_INSERTED | LDRP_ENTRY_PROCESSED | LDRP_PROCESS_ATTACH_CALLED; + NtInitializeListEntry(&LdrEntry->HashLinks); return true; } default:return false; @@ -355,6 +361,7 @@ static bool NTAPI NtFreeLdrDataTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) { NtFreeLdrpHeap(LdrEntry->FullDllName.Buffer); RemoveEntryList(&LdrEntry->InLoadOrderLinks); RemoveEntryList(&LdrEntry->InMemoryOrderLinks); + RemoveEntryList(&LdrEntry->InInitializationOrderLinks); RemoveEntryList(&LdrEntry->HashLinks); NtFreeLdrpHeap(LdrEntry); return true; @@ -508,9 +515,10 @@ static VOID NTAPI NtInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) { /* Insert into other lists */ InsertTailList(&PebData->InLoadOrderModuleList, &LdrEntry->InLoadOrderLinks); InsertTailList(&PebData->InMemoryOrderModuleList, &LdrEntry->InMemoryOrderLinks); + InsertTailList(&PebData->InInitializationOrderModuleList, &LdrEntry->InInitializationOrderLinks); } -static NTSTATUS NTAPI NtMapDllMemory(IN HMEMORYMODULE ViewBase, IN PCWSTR DllName OPTIONAL, +static NTSTATUS NTAPI NtMapDllMemory(IN HMEMORYMODULE ViewBase, IN DWORD dwFlags, IN PCWSTR DllName OPTIONAL, IN PCWSTR lpFullDllName OPTIONAL, OUT PLDR_DATA_TABLE_ENTRY* DataTableEntry OPTIONAL) { UNICODE_STRING FullDllName, BaseDllName; @@ -526,11 +534,7 @@ static NTSTATUS NTAPI NtMapDllMemory(IN HMEMORYMODULE ViewBase, IN PCWSTR DllNam return STATUS_NO_MEMORY; } - if (!NtInitializeLdrDataTableEntry(LdrEntry, ViewBase, - NtHeaders->OptionalHeader.SizeOfImage, - NtHeaders->FileHeader.TimeDateStamp, - BaseDllName, FullDllName, - (PVOID)(NtHeaders->OptionalHeader.AddressOfEntryPoint + NtHeaders->OptionalHeader.ImageBase))) { + if (!NtInitializeLdrDataTableEntry(LdrEntry, dwFlags, ViewBase, BaseDllName, FullDllName)) { NtFreeLdrpHeap(LdrEntry); NtFreeLdrpHeap(BaseDllName.Buffer); NtFreeLdrpHeap(FullDllName.Buffer); @@ -548,16 +552,25 @@ NTSTATUS NTAPI NtLoadDllMemory(OUT HMEMORYMODULE* BaseAddress, IN LPVOID BufferA NTSTATUS NTAPI NtLoadDllMemoryExW( OUT HMEMORYMODULE* BaseAddress, - OUT PLDR_DATA_TABLE_ENTRY* LdrEntry OPTIONAL, + OUT PVOID* LdrEntry OPTIONAL, IN DWORD dwFlags, IN LPVOID BufferAddress, IN size_t BufferSize, IN LPCWSTR DllName OPTIONAL, IN LPCWSTR DllFullName OPTIONAL) { - if (IsBadReadPtr(BufferAddress, BufferSize) || IsBadWritePtr(BaseAddress, sizeof(HMEMORYMODULE)))return STATUS_ACCESS_VIOLATION; - *BaseAddress = nullptr; PMEMORYMODULE module = nullptr; NTSTATUS status = STATUS_SUCCESS; + PLDR_DATA_TABLE_ENTRY ModuleEntry = nullptr; + + __try { + if (IsBadReadPtr(BufferAddress, BufferSize))status = STATUS_ACCESS_VIOLATION; + *BaseAddress = nullptr; + if (LdrEntry)*LdrEntry = nullptr; + } + __except (EXCEPTION_EXECUTE_HANDLER) { + status = GetExceptionCode(); + } + if (!NT_SUCCESS(status))return status; if (dwFlags & LOAD_FLAGS_NOT_MAP_DLL) { dwFlags &= LOAD_FLAGS_NOT_MAP_DLL; @@ -612,28 +625,44 @@ NTSTATUS NTAPI NtLoadDllMemoryExW( } module->loadFromNtLoadDllMemory = true; if (dwFlags & LOAD_FLAGS_NOT_MAP_DLL) return STATUS_SUCCESS; - status = NtMapDllMemory(*BaseAddress, DllName, DllFullName, LdrEntry); + + status = NtMapDllMemory(*BaseAddress, dwFlags, DllName, DllFullName, &ModuleEntry); if (!NT_SUCCESS(status)) { NtUnloadDllMemory(*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)return STATUS_SUCCESS; status = RtlInsertInvertedFunctionTable((PVOID)module->codeBase, RtlImageNtHeader(*BaseAddress)->OptionalHeader.SizeOfImage); if (!NT_SUCCESS(status)) { NtUnloadDllMemory(*BaseAddress); *BaseAddress = nullptr; + if (LdrEntry)*LdrEntry = nullptr; return status; } module->InsertInvertedFunctionTableEntry = true; + + if (dwFlags & LOAD_FLAGS_NOT_HANDLE_TLS)return STATUS_SUCCESS; + status = LdrpHandleTlsData(ModuleEntry); + if (!NT_SUCCESS(status)) { + NtUnloadDllMemory(*BaseAddress); + *BaseAddress = nullptr; + if (LdrEntry)*LdrEntry = nullptr; + return status; + } + return STATUS_SUCCESS; } NTSTATUS NtLoadDllMemoryExA( OUT HMEMORYMODULE* BaseAddress, - OUT PLDR_DATA_TABLE_ENTRY* LdrEntry OPTIONAL, + OUT PVOID* LdrEntry OPTIONAL, IN DWORD dwFlags, IN LPVOID BufferAddress, IN size_t BufferSize, @@ -907,7 +936,7 @@ static NTSTATUS NTAPI RtlProtectMrdata(IN SIZE_T Protect) { NTSTATUS NTAPI RtlInsertInvertedFunctionTable(IN PVOID BaseAddress, IN size_t ImageSize) { static auto table = PRTL_INVERTED_FUNCTION_TABLE(RtlFindLdrpInvertedFunctionTable()); if (!table)return STATUS_NOT_SUPPORTED; - bool need_virtual_protect = RtlIsWindowsVersionOrGreater(10, 0, 0); + bool need_virtual_protect = RtlIsWindowsVersionOrGreater(8, 3, 0); NTSTATUS status; if (need_virtual_protect) { @@ -940,3 +969,144 @@ NTSTATUS NTAPI RtlRemoveInvertedFunctionTable(IN PVOID ImageBase) { return STATUS_SUCCESS; } + +static NTSTATUS NTAPI LdrpHandleTlsDataXp(PLDR_DATA_TABLE_ENTRY LdrEntry) { + return STATUS_NOT_SUPPORTED; +} +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; + } + operator bool() { + return this->Default != nullptr; + } + }; + static _FUNCTION_SET _LdrpHandleTlsData{}; + static bool stdcall = false; + if (_LdrpHandleTlsData) + return stdcall ? _LdrpHandleTlsData.Default(LdrEntry) : _LdrpHandleTlsData.Win8_1_OrGreater(LdrEntry); + + 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])return STATUS_NOT_SUPPORTED; + + //RS3 + if (Versions[2] >= 16299) { + Size = 7; + //19H2 + if (Versions[2] >= 18363)Feature = "\x74\x33\x44\x8D\x43\x09"; + //RS5 + else if (Versions[2] >= 17763) Feature = "\x8b\xc1\x8d\x4d\xbc\x51"; + //RS4 + else if (Versions[2] >= 17134) Feature = "\x33\xf6\x85\xc0\x79\x03"; + //RS3 + else Feature = "\x8b\xc1\x8d\x4d\xac\x51"; +#ifdef _WIN64 + //RS6(19H1) + if (Versions[2] >= 18362) OffsetOfFunctionBegin = 0x46; + //RS4 + else if (Versions[2] >= 17134) OffsetOfFunctionBegin = 0x44; + //RS3 + else OffsetOfFunctionBegin = 0x43; +#else + //RS6(19H1) + if (Versions[2] >= 18362) OffsetOfFunctionBegin = 0x2E; + //RS5 + else if (Versions[2] >= 17763) OffsetOfFunctionBegin = 0x2C; + //RS3,4 + else OffsetOfFunctionBegin = 0x18; +#endif + break; + } + //RS2 + else if (Versions[2] >= 15063) { + Size = 7; +#ifdef _WIN64 + OffsetOfFunctionBegin = 0x43; + Feature = "\x74\x33\x44\x8d\x43\x09"; +#else + OffsetOfFunctionBegin = 0x18; + Feature = "\x8b\xc1\x8d\x4d\xbc\x51"; +#endif + break; + } + + // NO BREAK + } + case 6: { + switch (Versions[1]) { + //8.1 + case 3: { +#ifdef _WIN64 + Size = 10; + OffsetOfFunctionBegin = 0x43; + Feature = "\x44\x8d\x43\x09\x4c\x8d\x4c\x24\x38"; +#else + Size = 8; + OffsetOfFunctionBegin = 0x1B; + Feature = "\x50\x6a\x09\x6a\x01\x8b\xc1"; +#endif + break; + } + //8 + case 2: { +#ifdef _WIN64 + Size = 9; + OffsetOfFunctionBegin = 0x49; + Feature = "\x48\x8b\x79\x30\x45\x8d\x66\x01"; +#else + Size = 7; + OffsetOfFunctionBegin = 0xC; + Feature = "\x8b\x45\x08\x89\x45\xa0"; +#endif + break; + } + //7 + case 1: { +#ifdef _WIN64 + Size = 12; + OffsetOfFunctionBegin = 0x27; + Feature = "\x41\xb8\x09\x00\x00\x00\x48\x8d\x44\x24\x38"; +#else + Size = 9; + OffsetOfFunctionBegin = 0x14; + Feature = "\x74\x20\x8d\x45\xd4\x50\x6a\x09"; +#endif + break; + } + default:return STATUS_NOT_SUPPORTED; + } + break; + } + + default: { + _LdrpHandleTlsData.Default = LdrpHandleTlsDataXp; + stdcall = true; + return LdrpHandleTlsDataXp(LdrEntry); + } + } + + HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); + PIMAGE_NT_HEADERS headers = RtlImageNtHeader(ntdll); + if (!Feature || !headers)return STATUS_NOT_SUPPORTED; + Size--; + for (size_t i = 0; i < headers->OptionalHeader.SizeOfCode - Size; ++i) { + if (RtlCompareMemory((PBYTE)ntdll + i, Feature, Size) == Size) { + _LdrpHandleTlsData.Default = (_PTR_WIN)((PBYTE)ntdll + i - OffsetOfFunctionBegin); + break; + } + } + if (!_LdrpHandleTlsData)return STATUS_NOT_SUPPORTED; + stdcall = !RtlIsWindowsVersionOrGreater(6, 3, 0); + return stdcall ? _LdrpHandleTlsData.Default(LdrEntry) : _LdrpHandleTlsData.Win8_1_OrGreater(LdrEntry); +} diff --git a/MemoryModule/NativeFunctionsInternal.h b/MemoryModule/NativeFunctionsInternal.h index 672a3ce..ef1ce73 100644 --- a/MemoryModule/NativeFunctionsInternal.h +++ b/MemoryModule/NativeFunctionsInternal.h @@ -393,6 +393,7 @@ NTSTATUS NTAPI NtLoadDllMemory( /* NtLoadDllMemoryEx dwFlags */ + //If this flag is specified, all subsequent flags will be ignored. //Also, will be incompatible with Win32 API. #define LOAD_FLAGS_NOT_MAP_DLL 0x10000000 @@ -408,13 +409,16 @@ NTSTATUS NTAPI NtLoadDllMemory( //If this flag is specified, DllName and DllFullName cannot be nullptr, // they can be arbitrary strings without having to be correct file names and paths. //Otherwise, DllName and DllFullName will use random names if they are nullptr. -//For compatibility with GetModuleHandle, DllName and DllFullName should be guaranteed to always end in .dll +//For compatibility with GetModuleHandle, DllName and DllFullName should be guaranteed to always end in ".dll" #define LOAD_FLAGS_USE_DLL_NAME 0x00000004 +//Dont call LdrpHandleTlsData routine if this flag is specified. +#define LOAD_FLAGS_NOT_HANDLE_TLS 0x00000008 + NTSTATUS NTAPI NtLoadDllMemoryExW( OUT HMEMORYMODULE* BaseAddress, - OUT PLDR_DATA_TABLE_ENTRY* LdrEntry OPTIONAL, + OUT PVOID* LdrEntry OPTIONAL, IN DWORD dwFlags, IN LPVOID BufferAddress, IN size_t BufferSize, @@ -449,3 +453,4 @@ typedef struct _RTL_INVERTED_FUNCTION_TABLE { NTSTATUS NTAPI RtlInsertInvertedFunctionTable(IN PVOID BaseAddress, IN size_t ImageSize); NTSTATUS NTAPI RtlRemoveInvertedFunctionTable(IN PVOID ImageBase); +NTSTATUS NTAPI LdrpHandleTlsData(IN PLDR_DATA_TABLE_ENTRY LdrEntry); diff --git a/README.md b/README.md index 4e56457..adec574 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,11 @@ MemoryModulePP, used to load a DLL from memory. MemoryModulePP is compatible wit **This repository is under development.** +# NewFeatures + - Compatible with Win32 API: LoadStringA/W + - Support for TLS(Thread Local Storage) + - DllMain can receive four types of notifications + # Features - Compatible with Win32 API (GetModuleHandleA/W/Ex GetModuleFileNameA/W/Ex GetProcAddress) - Support for C ++ exceptions and SEH diff --git a/test/Header.h b/test/Header.h index 3843ac1..c1f17d6 100644 --- a/test/Header.h +++ b/test/Header.h @@ -1,35 +1,538 @@ -struct FuncInfoHeader -{ - union - { - struct - { - uint8_t isCatch : 1; // 1 if this represents a catch funclet, 0 otherwise - uint8_t isSeparated : 1; // 1 if this function has separated code segments, 0 otherwise - uint8_t BBT : 1; // Flags set by Basic Block Transformations - uint8_t UnwindMap : 1; // Existence of Unwind Map RVA - uint8_t TryBlockMap : 1; // Existence of Try Block Map RVA - uint8_t EHs : 1; // EHs flag set - uint8_t NoExcept : 1; // NoExcept flag set - uint8_t reserved : 1; - }; - uint8_t value; - }; -}; -struct FuncInfo4 -{ - FuncInfoHeader header; - uint32_t bbtFlags; // flags that may be set by BBT processing +#include +#include "../MemoryModule/NativeFunctionsInternal.h" - int32_t dispUnwindMap; // Image relative offset of the unwind map - int32_t dispTryBlockMap; // Image relative offset of the handler map - int32_t dispIPtoStateMap; // Image relative offset of the IP to state map - uint32_t dispFrame; // displacement of address of function frame wrt establisher frame, only used for catch funclets +typedef struct _THREAD_TLS_INFORMATION { + ULONG Flags; + union { + PVOID* TlsVector; + PVOID TlsModulePointer; + }; + HANDLE ThreadId; +} THREAD_TLS_INFORMATION, * PTHREAD_TLS_INFORMATION; + +typedef enum _PROCESS_TLS_INFORMATION_TYPE { + ProcessTlsReplaceIndex, + ProcessTlsReplaceVector, + MaxProcessTlsOperation +} PROCESS_TLS_INFORMATION_TYPE, * PPROCESS_TLS_INFORMATION_TYPE; + +typedef struct _PROCESS_TLS_INFORMATION { + ULONG Reserved; // Reserved bitmask + ULONG OperationType; + ULONG ThreadDataCount; + union { + ULONG TlsIndex; + ULONG TlsVectorLength; + }; + THREAD_TLS_INFORMATION ThreadData[ANYSIZE_ARRAY]; +} PROCESS_TLS_INFORMATION, * PPROCESS_TLS_INFORMATION; + +// Need struct name +typedef struct _TLS_VECTOR { + union { + ULONG Length; + HANDLE ThreadId; + }; + + struct _TLS_VECTOR* PreviousDeferredTlsVector; + PVOID ModuleTlsData[ANYSIZE_ARRAY]; +} TLS_VECTOR, * PTLS_VECTOR; + +// Need struct name +typedef struct _TLS_RECLAIM_TABLE_ENTRY { + PTLS_VECTOR TlsVector; + RTL_SRWLOCK Lock; +} TLS_RECLAIM_TABLE_ENTRY, * PTLS_RECLAIM_TABLE_ENTRY; + +// Need struct name +typedef struct _TLS_ENTRY { + LIST_ENTRY TlsEntryLinks; + IMAGE_TLS_DIRECTORY TlsDirectory; + PLDR_DATA_TABLE_ENTRY ModuleEntry; +} TLS_ENTRY, * PTLS_ENTRY; + +//0x10 bytes (sizeof) +typedef struct _RTL_BITMAP { + ULONG SizeOfBitMap; //0x0 + ULONG* Buffer; //0x8 +}RTL_BITMAP, * PRTL_BITMAP; + +VOID RtlClearBit( + PRTL_BITMAP BitMapHeader, + ULONG BitNumber +); + +VOID RtlInitializeBitMap( + PRTL_BITMAP BitMapHeader, + PULONG BitMapBuffer, + ULONG SizeOfBitMap +); + +ULONG RtlFindClearBitsAndSet( + PRTL_BITMAP BitMapHeader, + ULONG NumberToFind, + ULONG HintIndex +); + +VOID RtlClearBits( + PRTL_BITMAP BitMapHeader, + ULONG StartingIndex, + ULONG NumberToClear +); + +VOID RtlSetBit( + PRTL_BITMAP BitMapHeader, + ULONG BitNumber +); + +BOOLEAN RemoveEntryList( + PLIST_ENTRY Entry +); + +VOID NTAPI RtlAcquireSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock); +VOID NTAPI RtlReleaseSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock); + +NTSTATUS NTAPI NtSetInformationProcess( + IN HANDLE ProcessHandle, + IN ULONG ProcessInformationClass, + IN PVOID ProcessInformation, + IN ULONG ProcessInformationLength); + +#define ProcessTlsInformation ProcessResourceManagement + +PUCHAR NtdllBaseTag = 0; +ULONG LdrpActiveThreadCount = 0; +ULONG LdrpPotentialTlsLeaks = 0; +RTL_BITMAP LdrpTlsBitmap; +LIST_ENTRY LdrpTlsList; + +TLS_RECLAIM_TABLE_ENTRY LdrpDelayedTlsReclaimTable[16]; + +ULONG LdrpStaticTlsBitmapVector[4]; +ULONG LdrpActualBitmapSize = 0; + + +VOID LdrpInit() { + RtlCopyMemory(&LdrpTlsBitmap, NtCurrentPeb()->TlsBitmap, sizeof(RTL_BITMAP)); + PROCESS_TLS_INFORMATION pti; + +} + +VOID LdrpReleaseTlsIndex(ULONG TlsIndex) { + RtlClearBit(&LdrpTlsBitmap, TlsIndex); +} + +#define LDRP_BITMAP_INCREMENT (0x27 - sizeof( PVOID )) + +NTSTATUS LdrpAcquireTlsIndex(PULONG TlsIndex, PBOOLEAN AllocatedBitmap) { + ULONG Length; + ULONG Index; + PULONG NewBitmapBuffer; + + Length = LdrpTlsBitmap.SizeOfBitMap; + + if (Length == 0) { + // + // If we're the first caller, then we shall need to be initializing the + // bitmap. + // + // This implies that we don't need to expand as by definition, there + // shall exist space for ourselves at the start of the bitmap now. + // + RtlInitializeBitMap(&LdrpTlsBitmap, LdrpStaticTlsBitmapVector, 4); + LdrpActualBitmapSize = 1; + } + else { + Index = RtlFindClearBitsAndSet(&LdrpTlsBitmap, 1, 0); + + // + // If we found space in the existing bitmap then there is no reason to + // expand buffers, so we'll just return with the existing data. + // + if (Index != 0xFFFFFFFF) { + *TlsIndex = Index; + *AllocatedBitmap = FALSE; + return STATUS_SUCCESS; + } + + // + // Check if we need to grow the bitmap itself or if the bitmap still + // has space. + // + if (((LdrpTlsBitmap.SizeOfBitMap + LDRP_BITMAP_INCREMENT) >> 5) > LdrpActualBitmapSize) { + // + // We'll need to grow it. Let's go do so now. + // + + // + // BUG: We set the new size before checking the allocation. If we + // fail, then we leave the TLS variables in an inconsistant state. + // + LdrpActualBitmapSize = (Length + LDRP_BITMAP_INCREMENT) >> 5; + NewBitmapBuffer = (PULONG)RtlAllocateHeap(GetProcessHeap(), (ULONG_PTR)((PUCHAR)NtdllBaseTag + 0x000C0000), LdrpActualBitmapSize); + if (!NewBitmapBuffer) return STATUS_NO_MEMORY; + + // + // Copy the contents of the previous buffer into the new one. + // + RtlCopyMemory(NewBitmapBuffer, LdrpTlsBitmap.Buffer, Length + 7); + + // + // Free the old buffer if it wasn't the initial static buffer. + // + if (LdrpTlsBitmap.Buffer != LdrpStaticTlsBitmapVector) { + RtlFreeHeap(GetProcessHeap(), 0, LdrpTlsBitmap.Buffer); + } + + // + // Reinitialize the bitmap as we've changed the buffer pointer. + // + RtlInitializeBitMap(&LdrpTlsBitmap, NewBitmapBuffer, Length + 4); + } + else { + LdrpTlsBitmap.SizeOfBitMap += 4; + } + } + + RtlClearBits(&LdrpTlsBitmap, Length + 1, 3); + RtlSetBit(&LdrpTlsBitmap, Length); + + *TlsIndex = Index; + *AllocatedBitmap = TRUE; + + return STATUS_SUCCESS; +} + +NTSTATUS LdrpAllocateTlsEntry(PIMAGE_TLS_DIRECTORY TlsDirectory, PLDR_DATA_TABLE_ENTRY ModuleEntry, PULONG TlsIndex, PBOOLEAN AllocatedBitmap, PTLS_ENTRY* TlsEntry) { + + PTLS_ENTRY Entry = nullptr; + NTSTATUS Status; + + __try { + Entry = (PTLS_ENTRY)RtlAllocateHeap(GetProcessHeap(), (ULONG_PTR)((PUCHAR)NtdllBaseTag + 0x000C0000), sizeof(TLS_ENTRY)); + if (!Entry) return STATUS_NO_MEMORY; + Status = STATUS_SUCCESS; + RtlCopyMemory(&Entry->TlsDirectory, TlsDirectory, sizeof(IMAGE_TLS_DIRECTORY)); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + // + // Also print string and complain. + // + Status = GetExceptionCode(); + } + + if (!NT_SUCCESS(Status)) { + RtlFreeHeap(GetProcessHeap(), 0, Entry); + return Status; + } + + // + // Validate that the TLS directory entry is sane. + // + if (Entry->TlsDirectory.StartAddressOfRawData < Entry->TlsDirectory.EndAddressOfRawData) { + RtlFreeHeap(GetProcessHeap(), 0, Entry); + return STATUS_INVALID_IMAGE_FORMAT; + } + Entry->ModuleEntry = ModuleEntry; + + // + // Insert the entry into our list. + // + + InsertTailList(&LdrpTlsList, &Entry->TlsEntryLinks); + if (AllocatedBitmap) { + Status = LdrpAcquireTlsIndex(TlsIndex, AllocatedBitmap); + if (!NT_SUCCESS(Status)) { + // + // BUG: We don't remove the entry from LdrpTlsList + // + RtlFreeHeap(GetProcessHeap(), 0, Entry); + return Status; + } + } + else { + *TlsIndex += 1; + } + + // + // We reuse the 'Characteristics' field for the real TLS index. + // + Entry->TlsDirectory.Characteristics = *TlsIndex; + __try { + *(PULONG)Entry->TlsDirectory.AddressOfIndex = *TlsIndex; + } + __except (EXCEPTION_EXECUTE_HANDLER) { + Status = GetExceptionCode(); + } + if (!NT_SUCCESS(Status)) { + if (AllocatedBitmap) { + LdrpReleaseTlsIndex(*TlsIndex); + if (*AllocatedBitmap) LdrpTlsBitmap.SizeOfBitMap -= 4; + } + + // + // BUG: We don't remove the entry from LdrpTlsList + // + RtlFreeHeap(GetProcessHeap(), 0, Entry); + return Status; + } + + if (TlsEntry) *TlsEntry = Entry; + return STATUS_SUCCESS; +} + +PTLS_ENTRY __fastcall LdrpFindTlsEntry(PLDR_DATA_TABLE_ENTRY ModuleEntry) { + PTLS_ENTRY TlsEntry; + PLIST_ENTRY ListHead; + + ListHead = &LdrpTlsList; + + for (TlsEntry = CONTAINING_RECORD(LdrpTlsList.Flink, TLS_ENTRY, TlsEntryLinks); + &TlsEntry->TlsEntryLinks != ListHead; + TlsEntry = CONTAINING_RECORD(TlsEntry->TlsEntryLinks.Flink, TLS_ENTRY, TlsEntryLinks)) { + + if (TlsEntry->ModuleEntry == ModuleEntry) return TlsEntry; + } + + return 0; +} + +NTSTATUS LdrpReleaseTlsEntry(PLDR_DATA_TABLE_ENTRY ModuleEntry) { + PTLS_ENTRY TlsEntry; + + // + // Find the corresponding TLS_ENTRY for this module entry. + // + TlsEntry = LdrpFindTlsEntry(ModuleEntry); + if (!TlsEntry) return STATUS_NOT_FOUND; + + // + // Remove it from the global list of outstanding TLS entries. + // + RemoveEntryList(&TlsEntry->TlsEntryLinks); + + // + // Deallocate the TLS index. + // + LdrpReleaseTlsIndex(TlsEntry->TlsDirectory.Characteristics); + + // + // Deallocate the TLS_ENTRY object itself. + // + RtlFreeHeap(GetProcessHeap(), 0, TlsEntry); + + // + // We're done. + // + return STATUS_SUCCESS; +} + +PVOID* __fastcall LdrpGetNewTlsVector(ULONG TlsBitmapLength) { + PTLS_VECTOR TlsVector; + + TlsVector = (PTLS_VECTOR)RtlAllocateHeap(GetProcessHeap(), (ULONG_PTR)((PUCHAR)NtdllBaseTag + 0x000C0000), + sizeof(TLS_VECTOR) + (sizeof(PVOID) * TlsBitmapLength) - sizeof(PVOID)); + if (!TlsVector) return 0; + TlsVector->Length = TlsBitmapLength; + RtlZeroMemory(TlsVector->ModuleTlsData, TlsBitmapLength * sizeof(PVOID)); + return TlsVector->ModuleTlsData; +} + +VOID LdrpQueueDeferredTlsData(PVOID TlsVector, PVOID ThreadId) { + PTLS_VECTOR RealTlsVector; + PTLS_RECLAIM_TABLE_ENTRY ReclaimEntry; + + RealTlsVector = CONTAINING_RECORD(TlsVector, TLS_VECTOR, ModuleTlsData); + + RealTlsVector->ThreadId = ThreadId; + + ReclaimEntry = &LdrpDelayedTlsReclaimTable[((ULONG_PTR)(ThreadId) >> 2) & 0xF]; + + RtlAcquireSRWLockExclusive(&ReclaimEntry->Lock); + + RealTlsVector->PreviousDeferredTlsVector = ReclaimEntry->TlsVector; + ReclaimEntry->TlsVector = RealTlsVector; + + RtlReleaseSRWLockExclusive(&ReclaimEntry->Lock); +} + +#define SIZEOF_TLS_INFO(_ThreadCount_) (_ThreadCount_==0)?sizeof(PROCESS_TLS_INFORMATION)-sizeof(THREAD_TLS_INFORMATION):(_ThreadCount_-1)*sizeof(THREAD_TLS_INFORMATION)+sizeof(PROCESS_TLS_INFORMATION) +NTSTATUS LdrpHandleTlsData(PLDR_DATA_TABLE_ENTRY ModuleEntry) { + PIMAGE_TLS_DIRECTORY TlsDirectory; + ULONG DirectorySize; + ULONG TlsIndex; + HANDLE Heap; + PPROCESS_TLS_INFORMATION TlsInfo; + PROCESS_TLS_INFORMATION OneThreadTlsInfo; + NTSTATUS Status; + BOOLEAN AllocatedBitmap; + PTLS_ENTRY TlsEntry; + ULONG TlsBitmapLength; + SIZE_T TlsRawDataLength; + ULONG ThreadIndex; + PVOID TlsData = nullptr; + PVOID* TlsVector; + PTHREAD_TLS_INFORMATION ThreadTlsData; + ULONG ThreadsCleanedUp; + + if (LdrpActiveThreadCount == 0) return STATUS_SUCCESS; + TlsDirectory = (PIMAGE_TLS_DIRECTORY)RtlImageDirectoryEntryToData(ModuleEntry->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &DirectorySize); + if (!TlsDirectory) return STATUS_SUCCESS; + Heap = NtCurrentPeb()->ProcessHeap; + + TlsInfo = LdrpActiveThreadCount == 1 ? &OneThreadTlsInfo : + (decltype(TlsInfo))RtlAllocateHeap(Heap, (ULONG)NtdllBaseTag + 0x000C0000, SIZEOF_TLS_INFO(LdrpActiveThreadCount)); + if (!TlsInfo) return STATUS_NO_MEMORY; + + do { + TlsBitmapLength = LdrpTlsBitmap.SizeOfBitMap; + Status = LdrpAllocateTlsEntry(TlsDirectory, ModuleEntry, &TlsIndex, &AllocatedBitmap, &TlsEntry); + if (!NT_SUCCESS(Status)) break; + TlsInfo->ThreadDataCount = LdrpActiveThreadCount; + if (AllocatedBitmap) { + TlsInfo->OperationType = ProcessTlsReplaceVector; + TlsInfo->TlsVectorLength = TlsBitmapLength; + TlsBitmapLength = LdrpTlsBitmap.SizeOfBitMap; + } + else { + TlsInfo->OperationType = ProcessTlsReplaceIndex; + TlsInfo->TlsIndex = TlsIndex; + } + Status = STATUS_SUCCESS; + ThreadsCleanedUp = 0; + + // + // Calculate the size of the raw TLS data for this module. + // + TlsRawDataLength = TlsEntry->TlsDirectory.EndAddressOfRawData - TlsEntry->TlsDirectory.StartAddressOfRawData; + + // + // Prepare data for each running thread. + // + for (ThreadIndex = 0; ThreadIndex < TlsInfo->ThreadDataCount; ++ThreadIndex) { + TlsData = RtlAllocateHeap(Heap, (ULONG_PTR)((PUCHAR)NtdllBaseTag + 0x000C0000), TlsRawDataLength); + if (!TlsData) { + Status = STATUS_NO_MEMORY; + break; + } + __try { + RtlCopyMemory(TlsData, (PVOID)TlsEntry->TlsDirectory.StartAddressOfRawData, TlsRawDataLength); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + Status = GetExceptionCode(); + } + if (!NT_SUCCESS(Status)) { + RtlFreeHeap(Heap, 0, TlsData); + break; + } + + if (AllocatedBitmap) { + TlsVector = LdrpGetNewTlsVector(TlsBitmapLength); + if (!TlsVector) { + RtlFreeHeap(Heap, 0, TlsData); + break; + } + TlsVector[TlsIndex] = TlsData; + TlsInfo->ThreadData[ThreadIndex].TlsVector = TlsVector; + } + else { + TlsInfo->ThreadData[ThreadIndex].TlsModulePointer = TlsData; + } + + TlsInfo->ThreadData[ThreadIndex].Flags = 0; + } + + // + // This is awkward; all the 'break' above really are either goto or + // __leave, but we aren't using those. This is really supposed to + // just happen on normal for loop exit. + // + if (ThreadIndex == TlsInfo->ThreadDataCount) { + TlsInfo->Reserved = 0; + Status = NtSetInformationProcess(GetCurrentProcess(), ProcessTlsInformation, TlsInfo, + TlsInfo->ThreadDataCount * sizeof(THREAD_TLS_INFORMATION) + sizeof(PROCESS_TLS_INFORMATION) - sizeof(THREAD_TLS_INFORMATION)); + } + + // + // Let's handle each thread that we replaced, as the + // ProcessTlsInformation call fills our buffer with the old data + // after performing a swap. + // + for (ThreadTlsData = &TlsInfo->ThreadData[ThreadIndex]; ThreadIndex > 0;) { + ThreadIndex -= 1; + ThreadTlsData -= 1; + + if (ThreadTlsData->Flags & 0x2) { + if (!ThreadTlsData->TlsVector) continue; + + if (!AllocatedBitmap) { + RtlFreeHeap(Heap, 0, ThreadTlsData->TlsVector); + continue; + } + else { + LdrpQueueDeferredTlsData(ThreadTlsData->TlsVector, ThreadTlsData->ThreadId); + continue; + } + } + else { + if (ThreadTlsData->Flags & 0x1) { + ++LdrpPotentialTlsLeaks; + continue; + } + else { + ++ThreadsCleanedUp; + if (AllocatedBitmap) { + TlsData = ThreadTlsData->TlsVector[TlsIndex]; + RtlFreeHeap(Heap, 0, CONTAINING_RECORD(ThreadTlsData->TlsVector, TLS_VECTOR, ModuleTlsData)); + } + RtlFreeHeap(Heap, 0, TlsData); + continue; + } + } + } + + if (!NT_SUCCESS(Status)) { + LdrpReleaseTlsEntry(ModuleEntry); + if (AllocatedBitmap) LdrpTlsBitmap.SizeOfBitMap -= 4; + } + else if (ThreadsCleanedUp > 0) { + LdrpActiveThreadCount -= ThreadsCleanedUp; + } + } while (0); + + if (TlsInfo != &OneThreadTlsInfo) RtlFreeHeap(Heap, 0, TlsInfo); + if (!NT_SUCCESS(Status)) return Status; + ModuleEntry->TlsIndex = 0xFFFF; + return STATUS_SUCCESS; +} + +//struct UNKNOWN { +// PVOID unknown1; //+0x0 +// PVOID unknown2; //+0x8 +// PVOID unknown3; //+0x10 +// struct { +// DWORD dwFlags; //+0x14 +// DWORD unknown4; //+0x18 +// }; +// PWSTR DllName; //+0x20 +// PVOID unknown[11]; +//}; +// +////#include "../MemoryModule/Native.h" +// +////size = 0xC0 + DllName->Length + sizeof(wchar_t) +//typedef struct _ALLOCATE_ENTRY_PARAMETER { +// UNICODE_STRING DllName; //+0x0 +// UNKNOWN* unknown_structure; //+0x10 +// PVOID reserved1; //+0x18 +// struct { +// DWORD ProcessStatus; //+0x20 +// DWORD reserved2; //+0x24 +// }; +// PVOID reserved3; //+0x28 +// PVOID reserved4; //+0x30 +// PVOID LdrEntry; //+0x38 +// PVOID reserved[16]; //+0x40 +// BYTE UnicodeStringBuffer[1]; //+0xC0 +//}ALLOCATE_ENTRY_PARAMETER, * PALLOCATE_ENTRY_PARAMETER; -}; -struct EHRegistrationNode { - /* void * stackPtr */ // Stack ptr at entry to try (below address point) - EHRegistrationNode* pNext; // Next node in the chain - void* frameHandler; // The handler function for this frame - int state; // The current state of this function -}; diff --git a/test/test.cpp b/test/test.cpp index 7b20cf7..c31a728 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1,10 +1,16 @@ #include "../MemoryModule/NativeFunctionsInternal.h" +//#include "../MemoryModule/LoadDllMemoryApi.h" +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +#endif #include +#pragma warning(disable:4996) int main() { + //GetProcAddress(LoadLibraryA("a.dll"), "thread")(); LPVOID buffer; size_t size; - FILE* f = fopen("d.dll", "rb"); + FILE* f = fopen("a.dll", "rb"); if (!f)return 0; _fseeki64(f, 0, SEEK_END); if (!(size = _ftelli64(f))) { @@ -23,37 +29,105 @@ int main() { _exception exception = nullptr; if (!NT_SUCCESS(NtLoadDllMemoryExW(&m1, nullptr, 0, buffer, size, L"kernel64", nullptr))) goto end; - if (!NT_SUCCESS(NtLoadDllMemoryExW(&_m1, nullptr, 0, buffer, size, L"kernel64.dll", nullptr))) goto end; - if (!NT_SUCCESS(NtLoadDllMemoryExW(&m2, nullptr, 0, buffer, size, L"kernel128.dll", L"\\?\\kernel512.dll"))) goto end; + //if (!NT_SUCCESS(NtLoadDllMemoryExW(&_m1, nullptr, 0, buffer, size, L"kernel64.dll", nullptr))) goto end; + //if (!NT_SUCCESS(NtLoadDllMemoryExW(&m2, nullptr, 0, buffer, size, L"kernel128.dll", L"\\?\\kernel512.dll"))) goto end; + + char t[100]; + LoadStringA((HINSTANCE)m1, 101, t, 100); + printf("%s\n", t); hModule = GetModuleHandleA("kernel64.dll"); GetModuleFileNameA(hModule, name, MAX_PATH); - if (hModule)test = GetProcAddress(hModule, "test"); + if (hModule)test = GetProcAddress(hModule, "thread"); printf("m1:\n\tHMEMORYMODULE\t= 0x%p\n\tHMODULE\t\t= 0x%p\n\tModuleFileName\t= %s\n\ttest\t\t= 0x%p\n\n", m1, hModule, name, test); - if (test)test(); + if (test) test(); - GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR)test, &hModule); - GetModuleFileNameA(hModule, name, MAX_PATH); - test = GetProcAddress(hModule, "test"); - printf("_m1:\n\tHMEMORYMODULE\t= 0x%p\n\tHMODULE\t\t= 0x%p\n\tModuleFileName\t= %s\n\ttest\t\t= 0x%p\n\n", _m1, hModule, name, test); - if (test)test(); + //GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR)test, &hModule); + //GetModuleFileNameA(hModule, name, MAX_PATH); + //test = GetProcAddress(hModule, "test"); + //printf("_m1:\n\tHMEMORYMODULE\t= 0x%p\n\tHMODULE\t\t= 0x%p\n\tModuleFileName\t= %s\n\ttest\t\t= 0x%p\n\n", _m1, hModule, name, test); + //if (test)test(); - hModule = GetModuleHandleA("kernel128"); - GetModuleFileNameA(hModule, name, MAX_PATH); - if (hModule)exception = (_exception)GetProcAddress(hModule, "exception"); - printf("m2:\n\tHMEMORYMODULE\t= 0x%p\n\tHMODULE\t\t= 0x%p\n\tModuleFileName\t= %s\n\ttest\t\t= 0x%p\n\n", m2, hModule, name, test); - if (exception) { - exception(0); - exception(1); - exception(2); - exception(3); - } + //hModule = GetModuleHandleA("kernel128"); + //GetModuleFileNameA(hModule, name, MAX_PATH); + //if (hModule)exception = (_exception)GetProcAddress(hModule, "exception"); + //printf("m2:\n\tHMEMORYMODULE\t= 0x%p\n\tHMODULE\t\t= 0x%p\n\tModuleFileName\t= %s\n\ttest\t\t= 0x%p\n\n", m2, hModule, name, test); + //if (exception) { + // exception(0); + // exception(1); + // exception(2); + // exception(3); + //} end: delete[]buffer; if (m1)NtUnloadDllMemory(m1); - if (_m1)NtUnloadDllMemory(_m1); - if (m2)NtUnloadDllMemory(m2); + //if (_m1)NtUnloadDllMemory(_m1); + //if (m2)NtUnloadDllMemory(m2); return 0; } + +//#include +//#include "../MemoryModule/NativeFunctionsInternal.h" +// +//bool c; +//static thread_local int x = -1; +// +//DWORD WINAPI Thread(PVOID) { +// printf("[1] x = %d\n", x); +// x = 0; +// c = true; +// while (c)Sleep(100); +// return x; +//} +// +//int main() { +// x = 1; +// c = false; +// HANDLE hThread = CreateThread(nullptr, 0, Thread, nullptr, 0, nullptr); +// DWORD ex = 0; +// if (hThread) { +// while (!c)Sleep(100); +// printf("[0] x = %d\n", x); +// c = false; +// WaitForSingleObject(hThread, 0xffffffff); +// GetExitCodeThread(hThread, &ex); +// CloseHandle(hThread); +// printf("[0] Exit = %d\n", ex); +// } +// +// PLIST_ENTRY entry = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; +// PLDR_DATA_TABLE_ENTRY_WIN7 data = nullptr; +// +// while (entry != entry->Flink) { +// entry = entry->Flink; +// data = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY_WIN7, InLoadOrderLinks); +// } +// +// return 0; +//} + +//#include "../MemoryModule/Native.h" +//#include +// +//static thread_local int x = 0xffccffdd; +// +//DWORD WINAPI Thread(PVOID) { +// printf("[1] ThreadLocalStoragePointer = %p\n", NtCurrentTeb()->ThreadLocalStoragePointer); +// return x == 0xffccffdd ? 0 : 1; +//} +// +//int main() { +// x = 2; +// printf("[0] ThreadLocalStoragePointer = %p\n", NtCurrentTeb()->ThreadLocalStoragePointer); +// HANDLE hThread = CreateThread(nullptr, 0, Thread, nullptr, 0, nullptr); +// DWORD ret = -1; +// if (hThread) { +// WaitForSingleObject(hThread, 0xffffffff); +// GetExitCodeThread(hThread, &ret); +// CloseHandle(hThread); +// return ret; +// } +// return -1; +//}