線程本地存儲tls

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

相關文章
相關標籤/搜索