TLS即线程局部存储的结构定义如下
typedef struct _IMAGE_TLS_DIRECTORY32 {
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;
其中主要关心的就是第4个参数,这个参数指向一个数组,数组中每个元素都是一个函数指针,并以一个NULL为结尾
函数原型为
typedef VOID (NTAPI *PIMAGE_TLS_CALLBACK)(PVOID DllHandle, DWORD Reason, PVOID Reserved);
第一个参数顾名思义即为Dll句柄即模块句柄
第二个参数即表示调用该函数的时机,分别对应以下几个值:
DLL_PROCESS_DETACH 0 进程将要被终止,包括第一个线程
DLL_PROCESS_ATTACH 1 启动了一个新进程,包括第一个线程
DLL_THREAD_ATTACH 2 创建了一个新线程。创建所有线程时都会发送这个通知,除第一个线程外
DLL_THREAD_DETACH 3 线程将要被终止。终止所有线程时都会发送这个通知,除第一个线程外
第三个预留,为0
在程序加载进入OEP前,会按函数指针数组中地址顺序依次调用其函数(当然退出时也会),这可以利用到加壳脱壳等安全方面中
在程序中定义如上结构后,一般只初始化函数指针数组为有意义的值,其他值可都用初始化为0的值初始化
在定义完成生成程序后还要手动修改TLS数据目录使其指向你定义的TLS结构
下面分别贴上WIN32汇编和C的应用代码
/
;------------------------
; 静态TLS演示
; 戚利
; 2010.2.28
;------------------------
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.data
szText db 'HelloWorldPE',0,0,0,0
; 构造IMAGE_TLS_DIRECTORY
TLS_DIR dd offset Tls1
dd offset Tls2
dd offset Tls3
dd offset TlsCallBack
dd 0
dd 0
Tls1 dd 0
Tls2 dd 0
Tls3 dd 0
TlsCallBack dd offset TLS
dd 0
dd 0
.data?
TLSCalled db ? ;重进标志
.code
start:
invoke ExitProcess,NULL
RET
; 以下代码将会在.code之前执行一次
TLS:
; 变量TLSCalled是一个防重进标志。正常情况下该部分代码
; 会被执行两次,但使用了该标识后,该代码只在开始运行前
; 执行一次
cmp byte ptr [TLSCalled],1
je @exit
mov byte ptr [TLSCalled],1
invoke MessageBox,NULL,addr szText,NULL,MB_OK
@exit:
RET
end start
/
#include <windows.h>
void _Tls( );
typedef struct
{
DWORD start;
DWORD end;
DWORD index;
DWORD call;
DWORD a;
DWORD b;
}TLS_DIR;
DWORD tls1=0;
DWORD tls2=0;
DWORD tls3=0;
DWORD t[2]={ _Tls, 0 };
//DWORD x=0;
TLS_DIR tls = {
&tls1,
&tls2,
&tls3,
t,
0,
0
};
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
MessageBox (NULL, TEXT ("Hello"), TEXT ("HelloMsg"), 0) ;
return 0 ;
}
void _Tls( )
{
TCHAR s[20];
TCHAR a[]=L"%d %d %d";
wsprintf(s,a,tls1,tls2,tls3);
MessageBox(0,s,0,0);
wsprintf(s,L"%X,%X,%X",&tls1,&tls2,&tls3);
MessageBox(0,s,0,0);
//_asm ret
}