TLS反调试

TLS反调试

TLS(Thread Local Storage,线程局部储存),主要用于给线程独立的传值。由于线程不拥有进程的资源,所以几个同一进程的几个线程需要独立赋值时的需要通过TLS技术。每个线程创建时都会分配一个index。所以,这个索引index是全局变量,线程根据index来获取其他线程传过来的返回值。

TLS为什么能被用于反调试

AddressOfCallBacks 是线程建立和退出时的回调函数。包括主线程和其他线程。而且,因为程序运行时TLS数据初始化和TLS回调函数都在AddressOfEntryPoint之前,因此若将反调试代码插入到TLS回调函数,则可以在程序执行之前进行操作

TLS反调试示例

静态TLS反调试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <Windows.h>
#include <tchar.h>

#pragma comment(linker,"/INCLUDE:__tls_used")

void NTAPI TLS_CALLBACK_2(PVOID DllHandle, DWORD Reason, PVOID Reserved);
void NTAPI TLS_CALLBACK_1(PVOID DllHandle, DWORD Reason, PVOID Reserved);

#pragma data_seg(".CRT$XLB")
PIMAGE_TLS_CALLBACK pTLS_CALLBACK[] = {TLS_CALLBACK_1, NULL};
#pragma data_seg()

DWORD isBeingDebug = 0;
void NTAPI TLS_CALLBACK_1(PVOID DllHandle, DWORD Reason, PVOID Reserved){
if(IsDebuggerPresent()){
MessageBoxA(NULL, "我什么都逆不出来", "TLS_CALLBACK", MB_OK);
}
else{
MessageBoxA(NULL, "拜托了另一个我", "TLS_CALLBACK", MB_OK);
VirtualProtect(&pTLS_CALLBACK[1], sizeof(PIMAGE_TLS_CALLBACK), PAGE_EXECUTE_READWRITE, &isBeingDebug);
pTLS_CALLBACK[1] = {TLS_CALLBACK_2};
VirtualProtect(&pTLS_CALLBACK[1], sizeof(PIMAGE_TLS_CALLBACK), isBeingDebug, &isBeingDebug);
}
}

void NTAPI TLS_CALLBACK_2(PVOID DllHandle, DWORD Reason, PVOID Reserved) {
MessageBoxA(NULL, "是是是", "TLS_CALLBACK", MB_OK);
}

int main(){
MessageBoxA(NULL, "main", "main", MB_OK);
return 0;
}

应对

在可执行文件中,TLS储存在数据目录表中。可以通过CFFF等PE工具来提前发现。

image-20230306210515171