【PE文件】TLS
TLS表位置
IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER32.IMAGE_DATA_DIRECTORY_ARRAY[9].VirtualAddress

TLS表结构
TLS(Thread Local Storage,线程局部存储)以一个 IMAGE_TLS_DIRECTORY 结构体开始,TLS是各线程独立的数据存储空间,可以将数据与特定线程进行关联。
1 struct _IMAGE_TLS_DIRECTORY 2 { 3 0x00 DWORD StartAddressOfRawData; //内存起始地址 4 0x04 DWORD EndAddressOfRawData; //内存终止地址 5 0x08 LPDWORD AddressOfIndex; //地址索引,运行库用该索引来定位线程局部数据 6 0x0c PIMAGE_TLS_CALLBACK *AddressOfCallBacks; //地址数组,保存所有TLS回调函数地址,数组以NULL结尾 7 0x10 DWORD SizeOfZeroFill; //后面跟0的个数 8 0x14 DWORD Characteristics; //保留 9 }; 10 11 //回调函数原型: 12 typedef VOID (NTAPI *PIMAGE_TLS_CALLBACK) 13 ( 14 PVOID DllHandle, //模块基址 15 DWORD Reason, //调用原因 16 PVOID Reserved //保留 17 ); 18 19 //调用原因 20 { 21 DLL_PROCESS_ATTACH //1: 进程创建 22 DLL_THREAD_ATTACH //2: 线程创建 23 DLL_THREAD_DETACH //3: 线程结束 24 DLL_PROCESS_DETACH //0: 进程结束 25 } 26 27 //注意: 28 1、_IMAGE_TLS_DIRECTORY结构中的地址都是VA(虚拟地址)而不是RVA,如果PE文件开启基址重定位则这些地址也需要进行修正。 29 2、AddressOfCallBacks是线程建立和退出时的回调函数,当一个线程被创建或销毁时,数组中的函数都会被调用。 30 3、程序运行时,TLS数据的初始化和回调函数都会在入口点(EntryPoint)之前执行。恶意程序经常使用该特性执行反调试等操作。
示例代码
1 // TLS Tset.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <windows.h> 6 #pragma comment(linker, "/INCLUDE:__tls_used") 7 8 9 // TLS回调_1 10 void NTAPI TLS_CALLBACK1(PVOID DllHandle, DWORD Reason, PVOID Reserved) 11 { 12 char szMsg[80] = { 0, }; 13 wsprintfA(szMsg, "TLS_CALLBACK1() : DllHandle = %X, Reason = %d\n", DllHandle, Reason); 14 OutputDebugString(szMsg); 15 } 16 17 // TLS回调_2 18 void NTAPI TLS_CALLBACK2(PVOID DllHandle, DWORD Reason, PVOID Reserved) 19 { 20 char szMsg[80] = { 0, }; 21 wsprintfA(szMsg, "TLS_CALLBACK2() : DllHandle = %X, Reason = %d\n", DllHandle, Reason); 22 OutputDebugString(szMsg); 23 } 24 25 // 注册TLS回调 26 #pragma data_seg(".CRT$XLX") 27 PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { TLS_CALLBACK1, TLS_CALLBACK2, 0 }; 28 #pragma data_seg() 29 30 // 线程回调 31 DWORD WINAPI ThreadProc(LPVOID lParam) 32 { 33 OutputDebugString("ThreadProc() start\n"); 34 OutputDebugString("ThreadProc() end\n"); 35 return 0; 36 } 37 38 // Main 39 int _tmain(int argc, _TCHAR* argv[]) 40 { 41 OutputDebugString("main() start\n"); 42 43 //创建测试线程 44 HANDLE hThread = NULL; 45 hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); 46 WaitForSingleObject(hThread, 60 * 1000); 47 CloseHandle(hThread); 48 49 OutputDebugString("main() end\n"); 50 51 system("pause"); 52 return 0; 53 }
2个TLS回调分别被调用执行4次,共8次:
1 // 进程创建 2 [15920] TLS_CALLBACK1() : DllHandle = 520000, Reason = 1 3 [15920] TLS_CALLBACK2() : DllHandle = 520000, Reason = 1 4 [15920] main() start 5 6 // 线程创建 7 [15920] TLS_CALLBACK1() : DllHandle = 520000, Reason = 2 8 [15920] TLS_CALLBACK2() : DllHandle = 520000, Reason = 2 9 [15920] ThreadProc() start 10 [15920] ThreadProc() end 11 // 线程结束 12 [15920] TLS_CALLBACK1() : DllHandle = 520000, Reason = 3 13 [15920] TLS_CALLBACK2() : DllHandle = 520000, Reason = 3 14 [15920] main() end 15 16 // 进程结束 17 [15920] TLS_CALLBACK1() : DllHandle = 520000, Reason = 0 18 [15920] TLS_CALLBACK2() : DllHandle = 520000, Reason = 0

浙公网安备 33010602011771号