DLLs & TLS Callbacks, (Fri, Dec 19th)
文章探讨了利用DLL中的TLS(线程本地存储)回调机制,在程序启动前执行代码的方法。通过编写带有 TLS 回调函数的 DLL 并使用 rundll32 加载,作者展示了 TLS 回调在 DllMain 之前触发的过程。这提醒我们在进行静态分析时应检查 TLS 回调,并在动态分析中确保调试器正确配置以捕捉这些回调函数的执行。 2025-12-19 10:55:26 Author: isc.sans.edu(查看原文) 阅读量:5 收藏

Xavier's diary entry "Abusing DLLs EntryPoint for the Fun" inspired me to do some tests with TLS Callbacks and DLLs.

TLS stands for Thread Local Storage. TLS Callbacks are an execution mechanism in Windows PE files that lets code run automatically when a process or thread starts, before the program’s normal entry point is reached. I've done tests in the past with EXEs and TLS Callbacks, but never with DLLs.

In Windows, TLS is used to give each thread its own copy of certain variables. To support this, the PE format has a TLS directory (IMAGE_TLS_DIRECTORY) that describes:

  • Where TLS data is stored
  • How large it is
  • A list of callback functions

My pecheck.py tool lists TLS callbacks:

I used the following code for a DLL with a TLS callback:

#include <windows.h>

// Declare TLS callback section
#pragma section(".CRT$XLB", read)

// TLS callback function
void NTAPI MyTlsCallback(PVOID hModule, DWORD dwReason, PVOID pReserved)
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        MessageBoxA(NULL, "TLS Callback fired", "TLS", MB_OK);
    }
}

// Force linker to include TLS directory symbol
#ifdef _WIN64
#pragma comment(linker, "/INCLUDE:_tls_used")
#pragma comment(linker, "/INCLUDE:tls_callback_func")
#else
#pragma comment(linker, "/INCLUDE:__tls_used")
#pragma comment(linker, "/INCLUDE:_tls_callback_func")
#endif

// Place pointer in TLS callback section (extern "C" prevents mangling)
extern "C" __declspec(allocate(".CRT$XLB"))
PIMAGE_TLS_CALLBACK tls_callback_func = MyTlsCallback;

// Standard DllMain
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    if (ul_reason_for_call == DLL_PROCESS_ATTACH)
        MessageBoxA(NULL, "DllMain fired", "DllMain", MB_OK);
    return TRUE;
}

And compiled it with Visual Studio C++:

cl /nologo /EHsc /LD tls_dll.cpp user32.lib

I used rundll32 to load the DLL.

The callback function got executed:

before the DllMain function:

This is something to take into account when performing static analysis: next to looking at DllMain and exported functions, look also at TLS callbacks (if any).

And it's also important when performing dynamic analysis: when using a debugger, make sure to check how it is configured:

This debugger is configured to break on TLS callbacks: thus these callbacks will not execute unbeknownst to you.

Didier Stevens
Senior handler
blog.DidierStevens.com


文章来源: https://isc.sans.edu/diary/rss/32580
如有侵权请联系:admin#unsafe.sh