TLS的特别之处在于使得程序的入口点EP不是第一条执行的指令,所以常常用于反调试检测之中。
用一个已经开启的TLS的程序来做说明。
数据结构
TLS存在于PE文件格式之中。IMAGE_DATA_DIRECTORY DataDirectory[9]
存放了TLS目录的地址。
winNT.h [F12 可得到定义位置]
#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
同其他目录表数组一样,也是8字节结构 (VA+Size)
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
从TLS的VA处,可以找到该目录的详细信息。
32位下的TLS目录详情
typedef struct _IMAGE_TLS_DIRECTORY32 { //SIZE:0x18h
DWORD StartAddressOfRawData;
DWORD EndAddressOfRawData;
DWORD AddressOfIndex; // PDWORD
DWORD AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *
DWORD SizeOfZeroFill;
DWORD Characteristics;
} IMAGE_TLS_DIRECTORY32;
typedef IMAGE_TLS_DIRECTORY32 * PIMAGE_TLS_DIRECTORY32;
AddressOfcallBacks是一个指向指针数组的指针,指向的指针数组是TLS注册的回调函数地址。回调函数以数组形式连续分布,并以一个全为0的DWORD值来表示结束。
一个TLS可以有多个回调函数,这些回调函数都会被调用。
因此00401000
处就是TLS注册的回调函数,也可以看到,本程序只注册了一个回调函数。
触发机制
当创建/终止线程时会自动调用TLS的回调函数。
EP是在系统创建了该程序的主线程之后进入的,所以TLS回调函数先于EP运行,这也正是很多反调试技术用TLS的原因。
TLS callback函数的定义
typedef VOID
(NTAPI *PIMAGE_TLS_CALLBACK) (
PVOID DllHandle, //模块句柄,即加载地址
DWORD Reason,
PVOID Reserved
);
其中reason有以下几种:(winNT.h)
#define DLL_PROCESS_ATTACH 1 进程启动
#