-
-
[转帖]TLS回调函数,Anti-od原理分析
-
发表于: 2010-9-22 12:29 6369
-
本文转载链接:
线程本地存储器可以将数据与执行的特定线程联系起来,一个进程中的每个线程在访问同一个线程局部存储时,访问到的都是独立的绑定于该线程的数据块。动态绑定(运行时)线程特定数据是通过 TLS API(TlsAlloc、TlsGetValue、TlsSetValue 和 TlsFree)的方式支持的。除了现有的 API 实现,Win32 和 Visual C++ 编译器现在还支持静态绑定(加载时间)基于线程的数据。当使用_declspec(thread)声明的TLS变量时,编译器把它们放入一个叫.tls的区块里。当应用程序加载到内存时,系统寻找可执行文件中的.tls区块,并动态的分配一个足够大的内存块,以便存放TLS变量。系统也将一个指向已分配内存的指针放到TLS数组里,这个数组由FS:[2CH]指向。
数据目录表中第9索引的IMAGE_DIRECTORY_ENTRY_TLS条目的VirtualAddress指向TLS数据,如果非零,这里是一个IMAGE_TLS_DIRECTORY结构,如下:
IMAGE_TLS_DIRECTORY32 STRUC
StartAddressOfRawData DWORD ? ; 内存起始地址,用于初始化新线程的TLS
EndAddressOfRawData DWORD ? ; 内存终止地址
AddressOfIndex DWORD ? ; 运行库使用该索引来定位线程局部数据
AddressOfCallBacks DWORD ? ; PIMAGE_TLS_CALLBACK函数指针数组的地址
SizeOfZeroFill DWORD ? ; 用0填充TLS变量区域的大小
Characteristics DWORD ? ; 保留,目前为0
IMAGE_TLS_DIRECTORY32 ENDS
AddressOfCallBacks 是线程建立和退出时的回调函数,包括主线程和其它线程。当一个线程创建或销毁时,在列表中的每一个函数被调用。一般程序没有回调函数,这个列表是空的。TLS数据初始化和TLS回调函数调用都在入口点之前执行,也就是说TLS是程序最开始运行的地方。程序退出时,TLS回调函数再被执行一次。回调函数:
TLS_CALLBACK proto Dllhandle : LPVOID, Reason : DWORD, Reserved : LPVOID
参数如下:
Dllhandle : 为模块的句柄
Reason可取以下值:
DLL_PROCESS_ATTACH 1 : 启动一个新进程被加载
DLL_THREAD_ATTACH 2 : 启动一个新线程被加载
DLL_THREAD_DETACH 3 : 终止一个新线程被加载
DLL_PROCESS_DETACH 0 : 终止一个新进程被加载
Reserverd:用于保留,设置为0
IMAGE_TLS_DIRECTORY结构中的地址是虚拟地址,而不是RVA。这样,如果可执行文件不是从基地址装入,则这些地址会通过基址重定位修正。而且IMAGE_TLS_DIRECTORY本身不在.TLS区块中,而在.rdata里。
TLS回调可以使用诸如pedump之类的PE文件分析工具来识别。如果可执行文件中存在TLS条目,数据条目将会显示出来。
Data directory
EXPORT rva:00000000 size:00000000
IMPORT rva:00061000 size:000000E0
:::
TLS rva:000610E0 size:00000018
:::
IAT rva:00000000 size:00000000
DELAY_IMPORT rva:00000000 size:00000000
COM_DESCRPTR rva:00000000 size:00000000
unused rva:00000000 size:00000000
接着显示TLS条目的实际内容。AddressOfCallBacks成员指向一个以null结尾的回调函数数组。
TLS directory:
StartAddressOfRawData: 00000000
EndAddressOfRawData: 00000000
AddressOfIndex: 004610F8
AddressOfCallBacks: 004610FC
SizeOfZeroFill: 00000000
Characteristics: 00000000
在这个例子中,RVA 0x4610fc指向回调函数指针(0x490f43和0x44654e):
默认情况下OllyDbg载入这个例子将会暂停在入口点。由于TLS回调函数是在实际的入口点执行之前被调用的,OllyDbg应该配置一下使其在TLS回调被调用之前中断在实际的loader。
可以通过选择选项->调试选项->事件->第一次中断于->系统断点来设置中断于ntdll.dll内的实际loader代码。这样设置以后,OllyDbg将会中断在位于执行TLS回调的ntdll!LdrpRunInitializeRoutines()之前的ntdll!_LdrpInitializeProcess(),这时就可以在回调例程中下断并跟踪了。如,在内存映像的.text代码段上设置内存访问断点,可以断在TLS回调函数。
实例代码看下一篇:
参考自《加密与解密》及看雪论坛
使用Thread Local Storage (TLS)回调函数可以实现在实际的入口点之前执行反调试的代码,这也是OD载入程序就退出的原因所在。
赞赏
- [求助]谁有exetools论坛的帐号,帮我下载这个工具isDcc31src 10148
- [求助]如何把两个可执行文件合并在一起 8347
- [求助]如何修改和保存setup.inx文件 6800
- 求助:这个是.NET程序吗?有壳吗? 12467
- [转帖]TLS回调函数,Anti-od实例 6893