TLS回调函数

TLS是Thread-local storage的缩写,它是线程自己私有的数据存储区。TLS回调函数则是一种的特殊函数,它在进程创建、进程退出、线程创建、线程退出时被操作系统调用,听起来有点像DllMain函数。TLS回调函数在进程创建时被调用,会早于进程的Main入口函数,很多软件会利用这一特性进行反调试检查。

实现TLS回调函数代码也很简单,不过有几个值得注意的小细节,见如下代码:

#pragma comment(linker, "/INCLUDE:__tls_used")
#pragma comment(linker, "/INCLUDE:_p_thread_callback_base")

void NTAPI OnTLSCallback(PVOID module, DWORD reason, PVOID reserved) {
  switch (reason)
  {
  case DLL_PROCESS_ATTACH:
    std::cout << "DLL_PROCESS_ATTACH\n";
    break;
  case DLL_THREAD_ATTACH:
    std::cout << "DLL_THREAD_ATTACH\n";
    break;
  case DLL_THREAD_DETACH:
    std::cout << "DLL_THREAD_DETACH\n";
    break;
  case DLL_PROCESS_DETACH:
    std::cout << "DLL_PROCESS_DETACH\n";
    break;
  }
}

extern "C" {
#pragma data_seg(".CRT$XLB")
  PIMAGE_TLS_CALLBACK p_thread_callback_base = OnTLSCallback;
  // Reset the default section.
#pragma data_seg()
}

#pragma comment(linker, "/INCLUDE:__tls_used")这句的作用时在PE文件里创建一个.tls的目录,如果不存在的话。

#pragma comment(linker, "/INCLUDE:_p_thread_callback_base")的作用则是强制编译器生成对_p_thread_callback_base的引用,以防止在release模式下编译器whole program optimization优化导致找不到TLS回调函数。这点值得注意,有些人实现了一些TLS回调函数,发现在debug模式下可以正常工作,到了release模式就失效了。

#pragma data_seg(".CRT$XLB")这部分代码创建一个tls段。".CRT$XLB"的含义是:

如果要定义多个TLS_CallBack函数,可以把下面这句写成:PIMAGE_TLS_CALLBACK p_thread_callback_base [] = {tls_callback_A, tls_callback_B, tls_callback_C,0};

我们用到了extern "C",这是想在c++代码里也可以方便的使用。

参考: