Malware authors employ numerous and creative techniques to protect their executables from reverse-engineering. The arsenal includes an anti-debugging technique called TLS callback. The approach is not new, yet it is not widely understood by malware analysts, so I'd like to describe in this note. (Thanks to Christian Wojner from CERt.at for his insights regarding this topic!)

What is TLS?

According to Microsoft, Thread Local Storage (TLS) is a mechanism that allows Microsoft Windows to define data objects that are not automatic (stack) variables, yet are "local to each individual thread that runs the code. Thus, each thread can maintain a different value for a variable declared by using TLS." This information is stored in the PE header. (Windows uses the PE header to store meta information about the executable to load and run the progrem.)

A programmer can define TLS callback functions, which were designed mainly to initialize and clear TLS data objects. From the malware author's perspective, the beauty of TLS callbacks is that Windows executes these functions before execuding code at the traditional start of the program.

How Can TLS Callbacks Confuse Debuggers and Analysts?

Analysts often examine the a malicious program's code by starting with the instructions located at the Entry Point of the executable. The Entry Point is a field in the PE header that stores the address of the "first" instruction in the program that Windows is supposed to execute; debuggers typically take us to that instruction after loading the executable. TLS callback functions allow malware authors to execute malicious code before the debugger has a chance to pause at the traditional Entry Point. This allows malware to infect the system or disable the debugger before the analyst has a chance to look at the sample's code.

Consider the TLS callback technique employed by the Nadnadzzz bot about a year ago. If you load the bot's executable into OllyDbg, you expect to have the debugger pause at its entry point. Instead, OllyDbg seems to immediately say that the process terminated. What happened? You just infected yourself!

The problem is that before OllyDbg had a chance to pause at the traditional Entry Point instruction, it executed a TLS callback function.

How to Bypass the TLS Callback Defense

To bypass the TLS callback defense to debug the program starting from its "true" beginning of the TLS callback function:

Configure the debugger to pause on the system entry point, instead of the traditional program entry point.

Identify the address of the TLS callback function, instead of the traditional program Entry Point.

Set the breakpoint on the TLS callback function, then run the program if you wish.

If using OllyDbg, you can tell it to pause before TLS callback by going to Debugging options > Events. By default, it's set to pause at "WinMain (if location is known)." Instead, set it to pause at "System breakpoint." This will allow you to control the program before TLS callback functions execute.

Now you will have a chance to set the breakpoint on the TLS callback function. You need to find it first, though. Ilfak Guilfanov describes a convenient way to do that with IDA Pro in his blog posting. To locate the TLS callback function, load the malicious executable into IDA Pro, then press Ctrl+E to view the executable's entry points. The address of the TLS callback function should be among them.

Now you know where to start debugging or otherwise analyzing the program's code. You can do this in IDA Pro. If you prefer OllyDbg, you can return to OllyDbg, and load the malicious program; OllyDbg will now pause at the "system entry point" in ntdll.dll. Press Ctrl+G and enter the address of the TLS callback function, which you located via IDA Pro; set a breakpoint there and continue the analysis.

For additional information about TLS callbacks used by malware for anti-debugging, see the links mentioned earlier, as well as:

Sylvain Sarmejeanne reminded us that GRUM malware used TLS callback to execute its unpacking code, as outlined in this Websense blog posting. Sylvain also shared with us a link to his personal blog posting (in French), which explains how one could use TLS callbacks to create a UPX-packed file that runs differently depending on whether was statically uncompressed ("upx -d") or whether it dynamically uncompresses itself in memory. (Here's a link to the Google auto-translate of Sylvain's posting.)

If you have other tips and examples of TLS callbacks used by malware, please let us know.