经常能看到有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; } }
|