TLS_Callback(Thread-local storage,线程本地存储)是WindowsAPI下的一个回调函数,它会在程序进程开始,结束以及线程开始,结束的时候调用。
TLS_Callback在逆向中有一个特点: 先于main函数执行/在main结束后执行。因此也经常被用作反调试,或者是藏匿变量修改,以防止动态和静态分析。
参考此处
#include <stdio.h>
#include <Windows.h>
#ifdef _WIN64
#pragma comment (linker, "/INCLUDE:_tls_used")
#pragma comment (linker, "/INCLUDE:thread_callback_base")
#else
#pragma comment (linker, "/INCLUDE:__tls_used")
#pragma comment (linker, "/INCLUDE:_thread_callback_base")
#endif
void generate_str(char* ptr, DWORD reason)
{
switch (reason) {
case DLL_PROCESS_ATTACH:
strcat_s(ptr ,200, "DLL_PROCESS_ATTACH\n");
break;
case DLL_PROCESS_DETACH:
strcat_s(ptr, 200, "DLL_PROCESS_DETACH\n");
break;
case DLL_THREAD_ATTACH:
strcat_s(ptr, 200, "DLL_THREAD_ATTACH\n");
break;
case DLL_THREAD_DETACH:
strcat_s(ptr, 200, "DLL_THREAD_DETACH\n");
break;
}
}
// TLS回调
void NTAPI tls_callback_1(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
char ptr[256]{ 0 };
strcpy_s(ptr, " TLS Callback1: ");
generate_str(ptr, Reason);
WriteConsoleA(hStdout, ptr, strlen(ptr), NULL, NULL);
}
// TLS回调
void NTAPI tls_callback_2(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
char ptr[256]{ 0 };
strcpy_s(ptr, " TLS Callback2: ");
generate_str(ptr, Reason);
WriteConsoleA(hStdout, ptr, strlen(ptr), NULL, NULL);
}
#ifdef _WIN64
#pragma const_seg(".CRT$XLF")
EXTERN_C const
#else
#pragma data_seg(".CRT$XLF")
EXTERN_C
#endif
PIMAGE_TLS_CALLBACK thread_callback_base[] = { tls_callback_1, tls_callback_2, 0 };
#ifdef _WIN64
#pragma const_seg()
#else
#pragma data_seg()
#endif //_WIN64
#define OK_PRINT_FLAG(s) ("\033[1;40;32m[+]\033[0m "##s)
#define ERR_PRINT_FLAG(s) ("\033[1;40;31m[-]\033[0m "##s)
// 线程回调
DWORD WINAPI thread_func(
_In_ LPVOID lpParameter
)
{
printf(OK_PRINT_FLAG("Enter thread func...\n"));
Sleep(5000);
printf(OK_PRINT_FLAG("Leave thread func...\n"));
return 0;
}
int main(void)
{
printf(OK_PRINT_FLAG("Enter main...\n"));
HANDLE hThread = CreateThread(NULL, 0, thread_func, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
printf(OK_PRINT_FLAG("Leave main...\n"));
return 0;
}
执行效果:
其中,tls_callback的第二个参数Reason可以有四个值分别是DLL_PROCESS_ATTACH、DLL_THREAD_ATTACH、DLL_THREAD_DETACH、DLL_PROCESS_DETACH
分别对应1,2,3,0
因此几次调用TLS回调函数的顺序也是1-2-3-0即DLL_PROCESS_ATTACH->DLL_THREAD_ATTACH->DLL_THREAD_DETACH->DLL_PROCESS_DETACH
在ida中反编译可以看到:
因此可以在进程启动时,对程序进行反调试,例如
在CTF逆向中,也可以利用DLL_PROCESS_DETACH后于main函数结束执行,在main函数结束后继续调用某些函数。
通过配合CreateThread,对程序中某些变量重复修改也可以打出一套组合拳。
本文作者:Xunflash
本文链接:http://xunflash.top/index.php/archives/TLS_Callback.html
最后修改时间:2023-03-08 16:01:11
本站未注明转载的文章均为原创,并采用 CC BY-NC-SA 4.0 授权协议,转载请注明来源,谢谢!