Saturday, October 30, 2010

A Quick Look At TLS Callbacks

TLS callbacks have been used by many malware programmers to hide code from reverse engineers eyes. As most debuggers (in their default settings) don't really see them because TLS callbacks are called by the PE loader (in ntdll.dll) even before debuggers e.g. ollydbg, break on PE files Entry points.

And this is why they have mainly been used as an anti-debug method. I will give a simple example, which is a simple executable file executing its code within a TLS callback. In this example i built pxm.exe using minimum header files and standard libraries. And here is the source code

This file was tested on both XP SP2 and Vista. So what should reverse engineers do to catch these callbacks??
The first solution is to use IDA pro, where You will see TLS callback functions shown in the "Names" window if the PE file does really have TLS calback functions.
Then we can easily add a breakpoint.
The second solution is to use ollydbg v2, which can be configured to make its first pause on TLS callbacks.

1) If the same module has more than one TLS callback (consider the source code in the figure below), Olly will break on the first TLS callback only and discard any other TLS callback.
2) If the module has no TLS callbacks but implicitly linked with a DLL that has a TLS callback, Olly will not break at all. To try this yourself, here is a simple project (just try to debug pxm.exe with olly).
Here are reports about the PE files included in this project.
pxm.exe report
pxmd.dll report
When you run pxm.exe under olly, you will notice that TLS callback of pxmd.dll will run before that of pxm.exe and that olly will not break on pxmd.dll TLS callback.
So how to overcome these 2 flaws in olly???
To overcome these 2 flaws, i had to create an ollydbg plugin. This plugin simply intercepts any new module loaded into a process address space, searchs it for TLS callbacks, and sets a one-shot breakpoint on every callback found.
plugin here
This plugin, TLSCatch, was tested on windows XP SP2, Vista, and 7.

N.B i am still working on this plugin to make it catch dynamically added TLS callbacks.

Version 0.3 of TLSCatch can be found here and its source code from here.


  1. Hello. Just read your blog post and I got a solution for your "dynamic" quest. Before reading your stuff, I normally intercepted ANY TLS Callback using this simple algo (hook) - breaking at ntdll.LdrInitializeThunk + x - where X is an offset that varies based on OS. In XP SP3, this offset is 0x21 I think.

    $+21 > FF55 08 CALL DWORD PTR SS:[EBP+8]


    - hook LdrInitializeThunk+0x21
    - check main application's EP passing through CALL DWORD PTR [EBP+8];
    - catch loaded libs' EPs through CALL;

    Should be straight forward.

    I'll check your work later on. At the moment am caught with some surgery. Crapz..

    SunBeam @

  2. Thnx SunBeam for your reply,
    I used to catch Tlscallbacks with this method you suggested.
    But i want you to put the following points in mind,

    push dword ptr[ebp+14];lpreserved
    push dword ptr[ebp+10];reason
    push dword ptr[ebp+c];hModule
    call dword ptr[ebp+8];calls Dlls Entry points(implicitly or explicitly linked) and Tlscallbacks(dynamic or static).
    N.B Dll entry points and Tlscallbacks have the same prototype.
    int __stdcall DLLEP_OR_TLSCB(void* hModule,int Reason,int reserved);

    The question is how to filter Tlscallbacks calls?

    consider this conditional breakpoint on
    call dword ptr[ebp+8] :_

    ,olly will break with tlscallbacks and Entry points for explicitly linked Dlls.
    (This is not 100% accurate).

    consider this hypothetical breakpoint:_

    ,this is what i am trying to implement now but it can't be considered as a silver bullet.

  3. Thanks for this wonderful documentation!
    Saved my day :)

  4. Hi if you run the TLS programm in olly with Windows7 as OS,i can only see the call by ntdll.dll where the address ranges are from 7****** and not able to find tls callback address
    i found the address in CFF and IDA as 0X400010.but why there is a difference in olly.can anyone help here