Log in

View Full Version : # dynamic TLS callbacks instead of SEH


nezumi-lab
January 11th, 2009, 19:29
static TLS are not static at all! actually, they’re dynamic. statically declared TLS could be changed in run-time without using any API. it’s possible to register/unregistered new TLS callbacks on the fly even after the file has been loaded.

it was a long story - I tried to found where OS keeps TLS info, but was unable to do it. suddenly something hit me - maybe OS does not keep TLS info at all? maybe OS reads PE file directly? quick investigation confirmed this suggestion. as a matter of fact: OS re-reads PE-header and .tls every time it need the data.

on any following even DLL_PROCESS_ATTACH, DLL_THREAD_ATTACH, DLL_THREAD_DETACH, DLL_PROCESS_DETACH Windows NT reads Data Directories -> TLS Directory. if VirtualAddress isn’t zero, OS reads Address of Callbacks Array and executes the first callback in the list. after it, OS reads the next element of Address of Callbacks Array.

what does it mean? it means: a) we can add/remove new TLS callbacks from another TLS callback or the program; b) if TLS Directory does not fit our needs it’s possible to create the new one on the fly;

guess, we have a program with statically declared TLS callbacks or without TLS at all. the program changes TLS array or creates it from the scratch. how interesting and how useful for malware!

shell-codes and malware sometimes make errors leading to exceptions. not good! thus, malware uses SEH to intercept expectations and suppress them. it was easy. “was” because SafeSEH mechanism has been infixed. too bad for hackers! well, what’s about TLS? if TLS data or TLS callback array belongs to writable memory - no problem to change it on the fly. as it was mentioned before, any exception generated by TLS is suppressed by OS. so, we got what we want.

moreover. guess, a hacker attacking an application, does something wrong and the application crashes. OS terminates it, Dr. Wantons saves the log for future analysis. quite common scenario, isn’t? well, dynamic TLS callbacks is absolute differing thing. TLS callback is called after the critical error, but _before_ process will be finished. in other words, malicious code inside TLS callbacks will be called _after_ Dr. Watson have finished loggin!!!

another thing. add new TLS callback (or create TLS Dir from the scratch), raise an exception (kind of XOR EAX, EAX/MOV EAX, [EAX]) and… pass control to TLS. of course, critical message will appear, but… not every reverser will find out where control is passed after pressing “OK” key.

no matter how TLS info is changed, it might be a local process or something else. yes, it’s possible to add new callback to another process, using WriteProcessMemory.

to demonstrate this I wrote a simple test program adding TLS callback on the fly. download ("http://nezumi-lab.org/ffh/TLS-dyn.zip") it and run. if you speaker makes “buzz” before and after Message Box it means the program works fine. otherwise: either you have no speaker, either something wrong.

source code is very simple. see it bellow:

BOOL WINAPI TLS_callback_01(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
BOOL WINAPI TLS_callback_02(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);

// TLS callback_01 is declared statically
// TLS callback_02 is not declared yet (will be added dynamically)
DWORD ptr[] = { (DWORD) TLS_callback_01, 0, 0 };
DWORD *xl[] = { (DWORD*) 0xEFBEADDE, ptr, ptr, (DWORD*) xl, ptr, 0, 0};

// this callback is declared statically
BOOL WINAPI TLS_callback_01(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
// add new call-back
if (fdwReason == 1) ptr[1] = (DWORD) TLS_callback_02;
return 0×666;
}

// this callback is not declared statically, will be added dynamically
BOOL WINAPI TLS_callback_02(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
// make sound
Beep(96, 6000); return 0×999;
}

// main function, just to be
nezumi() { MessageBox(0, “press ok to hear buzz”, “[x]“, 0); }



http://nezumi-lab.org/blog/?p=59

Ricardo Narvaja
January 12th, 2009, 04:39
Sorry for my bad english

the pointer of tls is in the header, if different of zero, go and look the address pointed by this and execute the code in this address, and you can change out of the header this pointer, and redirect the execution.
But if the tls pointer in the header is zero, the header is not writable, and we cannot change this pointer, and 99% of the programs have this pointer with value zero in the header, in this cases, tls will be not executed at all, and we cannot change this value of zero in the header, only this is valid for programs users of tls with value different of zero, not for all, i think, correct me if i'm wrong.

ricnar