经常能看到有tls的题,这里研究一下tls的原理和写法

然后就发现网上已经有很全的教程了,那我就直接放教程了

【原创】反调试实战系列二 TLS反调试+CheckRemoteDebuggerPresent原理 - 『软件调试区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

写法

这个说的很清楚,要写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
//包含回调
#ifdef _WIN64 //64位
#pragma comment (linker, "/INCLUDE:_tls_used")
#else //32位
#pragma comment (linker, "/INCLUDE:__tls_used")
#endif
//创建段
#ifdef _WIN64
#pragma const_seg(".CRT$XLX")
EXTERN_C const
#else
#pragma data_seg(".CRT$XLX")
extern "C" //是c语言就不写
#endif

//前缀表示这是线程的全局变量,每个线程初始化的值都是0x1,生命仅在这个线程内
__declspec (thread) int CheckIsChildren = 0x1;

//函数定义
void NTAPI t_TlsCallBack(PVOID Dllhandle, DWORD Reason, PVOID Reserved){};

//添加函数到数组,执行时按数组元素依次执行
PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { t_TlsCallBack ,0 };
#ifdef _WIN64
#pragma const_seg()
#else
#pragma data_seg()
#endif

然后就是:

reason

Reason值对应4种调用原因,在这四个条件下,都会触发TLS回调函数

宏定义 描述
DLL_PROCESS_ATTACH 1 一个新进程已经启动,包括第一个线程
DLL_THREAD_ATTACH 2 创建了一个新线程。此通知已发送给除第一个线程外的所有线程
DLL_THREAD_DETACH 3 线程即将被终止。此通知已发送给除第一个线程外的所有线程
DLL_PROCESS_DETACH 0 进程即将终止,包括原始线程

所以内部应当使用if来判断(或者没有创建线程,就不管了)

提示

  • 在使用CreateThread后记得WaitForSingleObject防止主线程提前结束
  • 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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include<iostream>
#include<Windows.h>
#include<string>

//包含回调
#ifdef _WIN64 //64位
#pragma comment (linker, "/INCLUDE:_tls_used")
#else //32位
#pragma comment (linker, "/INCLUDE:__tls_used")
#endif
//创建段
#ifdef _WIN64
#pragma const_seg(".CRT$XLX")
EXTERN_C const
#else
#pragma data_seg(".CRT$XLX")
extern "C"
#endif
__declspec (thread) int CheckIsChildren = 0x1;

void print(const char* szMsg)
{
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsoleA(hStdout, szMsg, strlen(szMsg), NULL, NULL);
}
void NTAPI t_TlsCallBack(PVOID Dllhandle, DWORD Reason, PVOID Reserved) {
if (Reason == 1)
{
CheckIsChildren--;
print("loaded\n");
}
if (Reason == 2) {
CheckIsChildren += 7;
printf("this is %d\n", CheckIsChildren);
}
if (Reason == 3) {
printf("exit thread %d\n", CheckIsChildren);
}
if (Reason == 0) {
char szMsg[80] = { 0, };
wsprintfA(szMsg, "%d", CheckIsChildren);
print(szMsg);
}
}




PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { t_TlsCallBack ,0 };
#ifdef _WIN64
#pragma const_seg()
#else
#pragma data_seg()
#endif
DWORD WINAPI MyThreadFunction(LPVOID lpParam) {
std::cout << "Thread running with value: " << CheckIsChildren << std::endl;
std::cout << "why dont play\n";
Sleep(1000);
return 0;
}
int main(void) {
if (CheckIsChildren == 0) {
CheckIsChildren += 2;
std::cout << CheckIsChildren << "\n";
PROCESS_INFORMATION ProInfo;
STARTUPINFO StartInfo;
ZeroMemory(&StartInfo, sizeof(StartInfo));
TCHAR ModulePath[100] = {};
GetModuleFileName(NULL, ModulePath, 100);
int input = 1;
/*CreateProcess(NULL,
ModulePath,
NULL,
NULL,
TRUE,
DEBUG_PROCESS,
NULL,
NULL,
&StartInfo,
&ProInfo);
WaitForSingleObject(ProInfo.hProcess, INFINITE);

CloseHandle(ProInfo.hProcess);
CloseHandle(ProInfo.hThread);
printf("\nfinished\n");*/
DWORD threadId;
HANDLE hThread = CreateThread(
NULL, // 默认安全属性
0, // 默认堆栈大小
MyThreadFunction, // 线程函数
&input, // 传递给线程函数的参数
0, // 默认创建标志
&threadId // 返回线程ID
);
//Sleep(1000);
if (hThread == NULL) {
std::cout << "NO!\n";
}
WaitForSingleObject(hThread, INFINITE);
}
else {
printf("yes,yes,yes");
return 0;
}
}