-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1f01599
commit 0efdd31
Showing
4 changed files
with
302 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,296 @@ | ||
#if defined(YY_Thunks_Implemented) && YY_Thunks_Support_Version < NTDDI_WIN6 | ||
|
||
namespace YY::Thunks::internal | ||
{ | ||
extern "C" BOOL WINAPI _DllMainCRTStartup( | ||
HINSTANCE const instance, | ||
DWORD const reason, | ||
LPVOID const reserved | ||
); | ||
|
||
extern "C" ULONG _tls_index; | ||
static ULONG _tls_index_old; | ||
#ifdef _WIN64 | ||
extern "C" const IMAGE_TLS_DIRECTORY64 _tls_used; | ||
#else | ||
extern "C" const IMAGE_TLS_DIRECTORY _tls_used; | ||
#endif | ||
|
||
struct TlsRawItem | ||
{ | ||
TlsRawItem* pNext; | ||
TlsRawItem* pPrev; | ||
BYTE* pBase; | ||
}; | ||
static thread_local TlsRawItem s_CurrentNode; | ||
|
||
static volatile LONG uStatus = 0; | ||
static TlsRawItem* volatile pRoot = nullptr; | ||
|
||
static ULONG __fastcall GetTlsIndexBufferCount(TEB* _pTeb) | ||
{ | ||
auto _ppThreadLocalStoragePointer = (void**)_pTeb->ThreadLocalStoragePointer; | ||
if (!_ppThreadLocalStoragePointer) | ||
return 0; | ||
|
||
return HeapSize(_pTeb->ProcessEnvironmentBlock->ProcessHeap, 0, _ppThreadLocalStoragePointer) / sizeof(void*); | ||
} | ||
static PVOID NTAPI RtlImageDirectoryEntryToData( | ||
__in PVOID pBaseAddress, | ||
__in ULONG dwDirectory, | ||
__out PULONG pSize | ||
) | ||
{ | ||
auto _pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress; | ||
auto _pNtHerder = reinterpret_cast<PIMAGE_NT_HEADERS>(PBYTE(pBaseAddress) + _pDosHeader->e_lfanew); | ||
auto& _DataDirectory = _pNtHerder->OptionalHeader.DataDirectory[dwDirectory]; | ||
|
||
*pSize = _DataDirectory.Size; | ||
if (_DataDirectory.Size == 0 || _DataDirectory.VirtualAddress == 0) | ||
return nullptr; | ||
|
||
return PBYTE(pBaseAddress) + _DataDirectory.VirtualAddress; | ||
} | ||
|
||
static ULONG __fastcall GetMaxTlsIndex() noexcept | ||
{ | ||
ULONG uMaxTlsIndex = 0; | ||
|
||
auto _pLdr = (_PEB_LDR_DATA_XP*)(TEB*)NtCurrentTeb()->ProcessEnvironmentBlock->Ldr; | ||
auto _pHerder = &_pLdr->InLoadOrderModuleList; | ||
for (auto _pItem = _pHerder->Flink; _pItem != _pHerder; ) | ||
{ | ||
auto _pEntry = CONTAINING_RECORD(_pItem, _LDR_DATA_TABLE_ENTRY_XP, InLoadOrderModuleList); | ||
_pItem = _pItem->Flink; | ||
|
||
/*if (!_pEntry->TlsIndex) | ||
continue;*/ | ||
|
||
ULONG TlsSize; | ||
auto pTlsImage = (PIMAGE_TLS_DIRECTORY)RtlImageDirectoryEntryToData( | ||
_pEntry->BaseAddress, | ||
IMAGE_DIRECTORY_ENTRY_TLS, | ||
&TlsSize); | ||
|
||
if (pTlsImage == nullptr || pTlsImage->AddressOfIndex == 0) | ||
{ | ||
continue; | ||
} | ||
|
||
|
||
__try | ||
{ | ||
|
||
const auto _TlsIndex = *(ULONG*)pTlsImage->AddressOfIndex; | ||
if (uMaxTlsIndex < _TlsIndex) | ||
uMaxTlsIndex = _TlsIndex; | ||
} | ||
__except (EXCEPTION_EXECUTE_HANDLER) | ||
{ | ||
} | ||
} | ||
|
||
return uMaxTlsIndex; | ||
|
||
} | ||
|
||
static bool __fastcall AllocTlsData() noexcept | ||
{ | ||
if (_tls_index == 0) | ||
return false; | ||
|
||
auto _pTeb= (TEB*)NtCurrentTeb(); | ||
auto _pTlsIndex = (void**)_pTeb->ThreadLocalStoragePointer; | ||
auto _cTlsIndexLength = GetTlsIndexBufferCount(_pTeb); | ||
if (_cTlsIndexLength <= _tls_index) | ||
{ | ||
// Index不足,扩充…… | ||
auto _cNewTlsIndexLength = _tls_index + 128; | ||
auto _pNewTlsIndex = (void**)Alloc(_cNewTlsIndexLength * sizeof(void*), HEAP_ZERO_MEMORY); | ||
if (!_pNewTlsIndex) | ||
return false; | ||
|
||
memcpy(_pNewTlsIndex, _pTlsIndex, _cTlsIndexLength * sizeof(void*)); | ||
if ((void*)InterlockedCompareExchange((uintptr_t*)&_pTeb->ThreadLocalStoragePointer, (uintptr_t)_pNewTlsIndex, (uintptr_t)_pTlsIndex) != _pTlsIndex) | ||
{ | ||
Free(_pNewTlsIndex); | ||
return false; | ||
} | ||
Free(_pTlsIndex); | ||
_pTlsIndex = _pNewTlsIndex; | ||
} | ||
const size_t _cbTlsRaw = _tls_used.EndAddressOfRawData - _tls_used.StartAddressOfRawData; | ||
auto _pRawTlsData = (BYTE*)Alloc(_cbTlsRaw, HEAP_ZERO_MEMORY); | ||
if (!_pRawTlsData) | ||
return false; | ||
|
||
memcpy(_pRawTlsData, (void*)_tls_used.StartAddressOfRawData, _cbTlsRaw); | ||
InterlockedExchange((uintptr_t*)&_pTlsIndex[_tls_index], (uintptr_t)_pRawTlsData); | ||
|
||
s_CurrentNode.pBase = _pRawTlsData; | ||
for (;;) | ||
{ | ||
if (!_interlockedbittestandset(&uStatus, 0)) | ||
{ | ||
s_CurrentNode.pNext = pRoot; | ||
if (pRoot) | ||
{ | ||
pRoot->pPrev = &s_CurrentNode; | ||
} | ||
pRoot = &s_CurrentNode; | ||
_interlockedbittestandreset(&uStatus, 0); | ||
break; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
static void __fastcall FreeTlsData() | ||
{ | ||
if (_tls_index == 0) | ||
return; | ||
auto _pTeb = (TEB*)NtCurrentTeb(); | ||
if (_tls_index >= GetTlsIndexBufferCount(_pTeb)) | ||
return; | ||
|
||
auto _ppTlsIndex = (void**)_pTeb->ThreadLocalStoragePointer; | ||
if (_ppTlsIndex[_tls_index] == nullptr) | ||
return; | ||
|
||
if (s_CurrentNode.pBase != _ppTlsIndex[_tls_index]) | ||
return; | ||
|
||
s_CurrentNode.pBase = nullptr; | ||
|
||
for (;;) | ||
{ | ||
if (!_interlockedbittestandset(&uStatus, 0)) | ||
{ | ||
auto pPrev = s_CurrentNode.pPrev; | ||
auto pNext = s_CurrentNode.pNext; | ||
if (pPrev) | ||
{ | ||
pPrev->pNext = pNext; | ||
} | ||
else | ||
{ | ||
pRoot = pNext; | ||
} | ||
|
||
if (pNext) | ||
{ | ||
pNext->pPrev = pPrev; | ||
} | ||
_interlockedbittestandreset(&uStatus, 0); | ||
|
||
auto _pTlsRawData = (void*)InterlockedExchange((uintptr_t*)&_ppTlsIndex[_tls_index], 0); | ||
Free(_pTlsRawData); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
static ULONG __fastcall CreateTlsIndex() noexcept | ||
{ | ||
return GetMaxTlsIndex() + 1; | ||
} | ||
|
||
static void __fastcall FreeTlsIndex() noexcept | ||
{ | ||
if (_tls_index == 0) | ||
return; | ||
|
||
// 故意不加锁…… | ||
for (auto _pItem = pRoot; _pItem;) | ||
{ | ||
auto _pNext = _pItem->pNext; | ||
Free(_pItem->pBase); | ||
_pItem = _pNext; | ||
} | ||
} | ||
|
||
static void __fastcall CallTlsCallback( | ||
HINSTANCE const _hInstance, | ||
DWORD const _uReason) | ||
{ | ||
if (_tls_index == 0) | ||
return; | ||
|
||
auto _pTeb = (TEB*)NtCurrentTeb(); | ||
auto _ppThreadLocalStoragePointer = (void**)_pTeb->ThreadLocalStoragePointer; | ||
if (!_ppThreadLocalStoragePointer) | ||
return; | ||
|
||
if (_tls_index >= GetTlsIndexBufferCount(_pTeb)) | ||
return; | ||
|
||
if (!_ppThreadLocalStoragePointer[_tls_index]) | ||
return; | ||
|
||
__try | ||
{ | ||
auto _pfnTlsCallbacks = reinterpret_cast<PIMAGE_TLS_CALLBACK*>(_tls_used.AddressOfCallBacks); | ||
if (_pfnTlsCallbacks) | ||
{ | ||
for (; *_pfnTlsCallbacks; ++_pfnTlsCallbacks) | ||
{ | ||
(*_pfnTlsCallbacks)(_hInstance, _uReason, nullptr); | ||
} | ||
} | ||
} | ||
__except (EXCEPTION_EXECUTE_HANDLER) | ||
{ | ||
|
||
} | ||
} | ||
|
||
extern "C" BOOL WINAPI DllMainCRTStartupForYY_Thunks( | ||
HINSTANCE const _hInstance, | ||
DWORD const _uReason, | ||
LPVOID const _pReserved | ||
) | ||
{ | ||
if (internal::GetSystemVersion() < internal::MakeVersion(6, 0)) | ||
{ | ||
// Vista开始已经可以动态的处理TLS问题了,所以这里只针对老系统处理。 | ||
switch (_uReason) | ||
{ | ||
case DLL_PROCESS_ATTACH: | ||
_tls_index_old = _tls_index; | ||
if (_tls_index == 0) | ||
{ | ||
_tls_index = CreateTlsIndex(); | ||
AllocTlsData(); | ||
} | ||
break; | ||
case DLL_THREAD_ATTACH: | ||
if (_tls_index_old == 0) | ||
{ | ||
AllocTlsData(); | ||
CallTlsCallback(_hInstance, _uReason); | ||
} | ||
break; | ||
case DLL_THREAD_DETACH: | ||
if (_tls_index_old == 0) | ||
{ | ||
CallTlsCallback(_hInstance, _uReason); | ||
FreeTlsData(); | ||
} | ||
break; | ||
case DLL_PROCESS_DETACH: | ||
#if (YY_Thunks_Support_Version < NTDDI_WINXP) | ||
__YY_Thunks_Process_Terminating = _pReserved != nullptr; | ||
#endif | ||
if (_tls_index_old == 0) | ||
{ | ||
CallTlsCallback(_hInstance, _uReason); | ||
FreeTlsIndex(); | ||
} | ||
break; | ||
} | ||
} | ||
|
||
return _DllMainCRTStartup(_hInstance, _uReason, _pReserved); | ||
} | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters