View and vote on the article here: Manually create a Thread Local Storage (TLS) Callback
Manually create a Thread Local Storage (TLS) Callback| Category | | | Summary | | A security-oriented article on creating Thread Local Storage (TLS) callbacks. Basic Portable Executable (PE) format knowledge is assumed. |
| | Body | Thread Local Storage as defined here can also be used in software protection schemes or malware. The advantage (or danger) of a program with a TLS callback is that if it is loaded inside software that is supposed to stop the execution at the entry point of the program (like a ring3 debugger, a tracer...etc.), the code in the TLS will still be executed.
This can be used by a malware writer to infect someone who might be trying to analyse the program or by a software developer who would like to implement copy or code protection before the program can be loaded into a debugger, to disable the software or send an illegal activity report.
Even though OllyDbg has all the features we need for the task, StudPE is better for locating and visualising portable executable (PE) information easily.
The PE format and TLS table
A PE format file is composed of 4 headers:
-DOS Header
-COFF Header
-Optional Header
-Data Directories
The pointer to the TLS table is located inside the last header (as shown below).

Notice the two DWORDs. The first one is the address of the TLS table and the other one is the size of the table. Each value in a PE file is in little endian notation and needs to be converted to hexadecimal.
In the example above, the pointer's value is actually: 00003053 and the size of the table is: 00000028
The structure of the TLS table
Using the address above, we can now locate the table itself inside the executable by adding the ImageBase to this value.
In most cases, the ImageBase is 00400000 (which you can check in the PE editor), thus by going to the address 00403053 we will be looking right at the information we need.

In OllyDbg, focus on the dump window and press CTRL+G (stands for Goto) and enter 00403053.
This table is made of 12 DWORDs:
-DataBlockStartVa
-DataBlockEndVa
-IndexVariableVa
-CallBackTableVa
-SizeOfZeroFill
-Characteristics
-Empty DWORD
-Empty DWORD
-Empty DWORD
-TlsCallBack
-Empty DWORD
-Empty DWORD
The first 3 DWORDs point to other DWORDs initialised to 00. They can point anywhere, as long as the value pointed to is 00.
The CallBackTableVa is a pointer to the TlsCallBack DWORD which is the address of the function to execute in the program.
Empty DWORDs are initialised to 00.
Sample Program
I use Dev-Cpp (mingw) on Windows, but you should be able to follow this code easily with any compiler.
#include <windows.h>
int MyFunction();
int tlsdone = 0;
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
ExitProcess(0);
return 0;
}
int MyFunction ()
{
if(tlsdone == 0)
{
MessageBox( NULL,
"hello",
"hello",
MB_OK | MB_ICONINFORMATION);
tlsdone = 1;
}
return 0;
}
You can see that MyFunction() is not called and will never be executed.
By referencing this function in the TLS table, it will be executed before any other function and before the main entry point of the program is reached.
However, a TLS Calback is always executed twice, once before the main entry point and once after the program exits, hence the need for a "tlsdone" variable.
Modifications
The first thing to do is find some empty space to write our custom TlsTable. There is usually enough free space after the last string definition. In our example, the string "hello" is located at 00403000
By pressing CTRL+G in the dump window you will find yourself at the same location as the screenshot below where you can seee some empty bytes at the bottom. We can start our modifications here at 004030D3.

The first information we need is the address of the beginning of the function we want to execute. In my example it is found at 004012A2. This address must go in the TlsCallBack section of the TLS table. This section is the 10th DWORD and starts at 004030D3 + 9 DWORDs = 004030F7
Before inserting this value in the binary, we need to transform it into little endian notation which gives A2124000. To insert this value, select 4 bytes (from 004030F7 to 004030FA) and press space to edit the selected bytes.
Now that this value is hardcoded, we can reference it in CallBackTableVa (4th DWORD of the table)
Insert F7304000 at address 004030DF
We now have to make the 3 first DWORDs point to some other empty values. In the screenshot below I created the following pointers:
-DataBlockStartVa points to SizeOfZeroFill
-DataBlockEndVa points to Characteristics
-IndexVariableVa points to the Empty DWORD below Characteristics

To save your changes to a file, first select all your modifications in the dump window, right-click on the selection and select "Save modifications". Then right-click again on the selection and select "Save to file".
Now that our table is ready, we need to modify the Data Directory header in studPE and feed the TLS CallBack section with 004030D3 minus the imagebase and converted to little endian: D3300000
We also need to specify a size which will be 30000000
Since our custom TLS table will be written to when the program is run, we need to make the .RDATA section 'writable' by setting its flag to C0000040
Running the program will now execute MyFunction(), and loading the program inside the debugger will also execute MyFunction() even if the the program hasn't been launched. |
|
There are no replies to this post yet.
|