8.10 TLS线程局部存储反调试

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