1.動態tls介紹windows
windows爲每一個進程分配一組線程本地存儲的標記. 至少有64個標記,若是程序使用超過了64個將動態增加.函數
這些標記有2種狀態: free和inuse. 全部標記的狀態對該進程中全部線程都是可見的.測試
程序中每一個線程會對應每一個標記一個slot,這個slot是個lpvoid的值加密
程序經過調用DWORD TlsAlloc(void) 來獲取一個free狀態的索引,並遍歷該進程全部線程對其slot賦值爲0,而後每一個線程就能夠經過spa
這個標記值(該標記的索引dword),來對本身的slot賦值,索引是每一個線程可見的,可是每一個線程本身的slot是隻有本身可見的,這個slot就能夠線程
理解爲線程本地存儲.指針
每一個線程能夠經過下面的函數對本身的slot賦值:調試
BOOL
WINAPI
TlsSetValue(
_In_ DWORD dwTlsIndex, //標記的索引值
_In_opt_ LPVOID lpTlsValue //給slot賦的值
)code
或者獲取slot的值:blog
LPVOID //返回slot的值
WINAPI
TlsGetValue(
_In_ DWORD dwTlsIndex //標記的索引值
)
因此通常用slot來存儲指針
前面說過,標記對全部線程可見,若是有任何線程經過下面函數來釋放標記,那麼全部線程的對應於該標記的slot值將不可用
BOOL
WINAPI
TlsFree(
_In_ DWORD dwTlsIndex //標記的索引值
)
2.測試代碼
DWORD threadProc(LPVOID param) { DWORD index = *(DWORD*)param; printf("tls1 [%d] value is %s\n", index, (char*)TlsGetValue(index)); TlsSetValue(index, "thread"); printf("tls2 [%d] value is %s\n", index, (char*)TlsGetValue(index)); return 0; } int main() { DWORD index; index=TlsAlloc(); TlsSetValue(index, "tls"); printf("main1 tls value is %s\n", (char*)TlsGetValue(index)); CreateThread(0, 0, (LPTHREAD_START_ROUTINE)threadProc, &index, 0, 0); Sleep(100); printf("main2 tls value is %s\n", (char*)TlsGetValue(index)); DWORD ret = TlsFree(index); system("pause"); return 0; }
執行結果:
main1 tls value is tls tls1 [1] value is (null) tls2 [1] value is thread main2 tls value is tls 請按任意鍵繼續. . .
3.tls回調函數及靜態TLS
tls回調函數會在線程建立和銷燬時執行,所以能夠用於反調試和軟件加密解密
使用連接指令:#pragma comment(linker,"/include:__tls_used") 開啓tls節
經過#pragma data_seg(".CRT$XLX")將回調函數填入tls節區中
#pragma data_seg(".CRT$XLX")
PIMAGE_TLS_CALLBACK callbacks[] = { callback1 ,callback2 ,0 };
#pragma data_seg()
回調函數原型:
void NTAPI callback1(PVOID hmodule, DWORD reason, PVOID reserved);