又是没整理的一个知识点,做PPT真是强制帮我整理知识点了。
TLS
Introduction Of TLS
TLS ( Thread Local Storage,线程局部存储 ) 回调函数(Callback Function),常用于反调试。
TLS 是各线程的独立数据存储空间,使用 TLS 技术可在线程内部独立使用或修改进程的全局数据或静态数据,就像对待自己的局部变量一样(编程中这种功能非常有用)。
IMAGE_DATA_DIRECTORY[9]
这 IMAGE_DATA_DIRECTORY 保存着 TLS TABLE
IMAGE_TLS_DIRECTORY
分别有 32位 版本和 64位 版本
而该结构体比较重要的是成员是 AddressOfCallbacks ,该值指向含有 TLS 回调函数的地址的数组,这意味着同一个程序可以注册多个 TLS 回调函数(数组以 NULL 结束)。
可以发现注册了两个 TLS 函数,进程启动运行时,系统会逐一调用存储该数组中的函数
IMAGE_TLS_CALLBACK
从技术层面来讲,所谓 TLS 回调函数是指,每当创建/终止进程的线程时会自动调用执行的函数,有意思的是创建进程的主线程时也会自动调用回调函数,且其调用先于 EP 代码。
TLS 回调函数定义如下
可以发现与 DllMain() 函数定义相似
可以发现这两个定义的顺序与含义都是一样的
- 其中 DllHandle 为模块句柄(即加载地址)
- 参数 Reason 表示调用 TLS 回调函数的原因
其中原因有四种
TLSTest.exe
Resource code:
1 |
|
该源码中注册两个 TLS 回调函数
TLS_CALLBACK1 与 TLS_CALLBACK2
- 该回调函数的功能为打印 DllHandle 与 Reason 这两个参数
main 函数功能为创建用户线程 ThreadProc 后中止
效果如下
DLL_PROCESS_ATTACH
进程的主线程调用 main() 函数前,已经注册的 TLS 回调函数(TLS_CALLBACK1、TLS_CALLBACK2)会被先执行,此时 Reason 的值为 1 (DLL_PROCESS_ATTACH)
DLL_THREAD_ATTACH
所有 TLS 回调函数完成调用后,main 函数开始调用执行,创建用户线程(ThreadProc)前,TLS 回调函数会被再次调用,此时 Reason = 2 (DLL_THREAD_ATTACH)
DLL_THREAD_DETACH
TLS 回调函数全部执行完,ThreadProc() 线程函数开始执行,该用户起的线程函数结束后再度调用 TLS 函数,其 Reason = 3(DLL_THREAD_DETACH)
DLL_PROCESS_DETACH
ThreadProc 函数执行完毕后,一直等待线程终止的 main 函数也就是主线程终止,这时候再度调用 TLS 回调函数(DLL_PROCESS_DETACH)
两个 TLS 函数分别调用执行了 4 次,总共为 8 次
源代码中并未使用 printf 函数,因为开启特定编译选项(/MT)编译源程序时,先于主线程调用执行的 TLS 回调函数可能会引用 Run-Time Error(运行时错误),所以用了 WriteConsole API 以防万一
About this Post
This post is written by P.Z, licensed under CC BY-NC 4.0.