TLS(Thread Local Storage)用來在進程內部每個線程中存儲私有的數據。每個線程都會擁有獨立的TLS
存儲空間,可以在TLS
存儲空間中保存線程的上下文信息、變量、函數指針等。TLS其目的是爲了解決多線程變量同步問題,聲明爲TLS變量後,當線程去訪問全局變量時,會將這個變量拷貝到自己線程中的TLS空間中,以防止同一時刻內多次修改全局變量導致變量不穩定的情況,先來看一段簡單的案例:
#include <Windows.h>
#include <stdio.h>
#pragma comment(linker, "/INCLUDE:__tls_used")
// TLS變量
__declspec (thread) int g_nNum = 0x11111111;
__declspec (thread) char g_szStr[] = "TLS g_nNum = 0x%p ...\r\n";
// 當有線程訪問tls變量時,該線程會複製一份tls變量到自己tls空間
// 線程只能修改自己的空間tls變量,不會修改到全局變量
// TLS回調函數A
void NTAPI t_TlsCallBack_A(PVOID DllHandle, DWORD Reason, PVOID Red)
{
if (DLL_THREAD_DETACH == Reason) // 如果線程退出則打印信息
printf("t_TlsCallBack_A -> ThreadDetach!\r\n");
return;
}
// TLS回調函數B
void NTAPI t_TlsCallBack_B(PVOID DllHandle, DWORD Reason, PVOID Red)
{
if (DLL_THREAD_DETACH == Reason) // 如果線程退出則打印信息
printf("t_TlsCallBack_B -> ThreadDetach!\r\n");
/* Reason 什麼事件觸發的
DLL_PROCESS_ATTACH 1
DLL_THREAD_ATTACH 2
DLL_THREAD_DETACH 3
DLL_PROCESS_DETACH 0 */
return;
}
// 註冊TLS回調函數,".CRT$XLB"
#pragma data_seg(".CRT$XLB")
PIMAGE_TLS_CALLBACK p_thread_callback[] = { t_TlsCallBack_A, t_TlsCallBack_B, };
#pragma data_seg()
DWORD WINAPI t_ThreadFun(PVOID pParam)
{
printf(g_szStr, g_nNum);
g_nNum = 0x22222222;
printf(g_szStr, g_nNum);
return 0;
}
int main(int argc, char * argv[])
{
CreateThread(NULL, 0, t_ThreadFun, NULL, 0, 0);
Sleep(100);
CreateThread(NULL, 0, t_ThreadFun, NULL, 0, 0);
system("pause");
return 0;
}
TLS(Thread Local Storage)中斷是另一種反調試技術,它利用進程中的線程來執行自定義的中斷處理函數,TLS中斷處理函數會被在程序加載之前就運行,並能夠搶在調試器對程序進行跟蹤之前終止執行,這使得它成爲一種相對安全的反調試技術。當程序被加載時,TLS中斷會自動執行,而對於調試器來說,默認情況下是不會運行TLS中斷處理函數的,因此可以利用這一點來判斷程序是否正在運行在調試器下。
#include <Windows.h>
#include <stdio.h>
// linker spec 通知鏈接器PE文件要創建TLS目錄
#ifdef _M_IX86
#pragma comment (linker, "/INCLUDE:__tls_used")
#pragma comment (linker, "/INCLUDE:__tls_callback")
#else
#pragma comment (linker, "/INCLUDE:_tls_used")
#pragma comment (linker, "/INCLUDE:_tls_callback")
#endif
void NTAPI __stdcall TLS_CALLBACK(PVOID DllHandle, DWORD dwReason, PVOID Reserved)
{
if (IsDebuggerPresent())
{
MessageBox(NULL, " TLS_CALLBACK: 請勿調試本程序 !", "TLS Callback", MB_ICONSTOP);
ExitProcess(0);
}
}
// 創建TLS段
EXTERN_C
#ifdef _M_X64
#pragma const_seg (".CRT$XLB")
PIMAGE_TLS_CALLBACK _tls_callback = TLS_CALLBACK;
#else
#pragma data_seg (".CRT$XLB")
PIMAGE_TLS_CALLBACK _tls_callback = TLS_CALLBACK;
#endif
int main(int argc, char * argv[])
{
system("pause");
return 0;
}