经常能看到有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        #pragma comment (linker, "/INCLUDE:_tls_used")   #else                #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 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        #pragma comment (linker, "/INCLUDE:_tls_used")   #else                #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; 		
 
 
 
 
 
 
 
 
 
 
 
 
 
  		DWORD threadId; 		HANDLE hThread = CreateThread( 			NULL,                    			0,                       			MyThreadFunction,        			&input,                  			0,                       			&threadId                		); 		 		if (hThread == NULL) { 			std::cout << "NO!\n"; 		} 		WaitForSingleObject(hThread, INFINITE); 	} 	else { 		printf("yes,yes,yes"); 		return 0; 	} }
   | 
 
注意,如果vs中需要生成Release版本,会导致TLS失效,可以从属性-C/C++-优化中把全程序优化关掉