TLS回调函数反调试技术
TLS回调函数反调试技术
0x00 什么是TLS 回调函数
TLS是各线程的独立的数据存储空间,使用TLS技术可在线程内部独立使用或修改进程的全局数据或静态数据,就像对待自身的局部变量一样,多用于线程间同步。
TLS (Thread Local Storage 线程局部存储 )回调函数每当创建/终止进程的线程时会自动调用执行的函数。
void NTAPI TLS_CALLBACK(PVOID DllHandle, DWORD Reason, PVOID Reserved)//回调函数的声明,和DllMain类似
0x01 如何反调试
由于在创建主线程的时候会自动调用TLS回调函数,并且调用的时机早于OEP的执行,所以可以在程序入口点之前在TLS回调函数内部完成对调试器的检测。
反调试Demo代码如下;
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
typedef NTSTATUS(NTAPI* pfnNtQueryInformationProcess)(
_In_ HANDLE ProcessHandle,
_In_ UINT ProcessInformationClass,
_Out_ PVOID ProcessInformation,
_In_ ULONG ProcessInformationLength,
_Out_opt_ PULONG ReturnLength
);
const UINT ProcessDebugPort = 7;
typedef NTSTATUS(NTAPI* pfnNtSetInformationThread)(
_In_ HANDLE ThreadHandle,
_In_ ULONG ThreadInformationClass,
_In_ PVOID ThreadInformation,
_In_ ULONG ThreadInformationLength
);
const ULONG ThreadHideFromDebugger = 0x11;
//告知连接器使用TLS
#pragma comment(linker, "/INCLUDE:__tls_used")
DWORD isDebuggerPresent = 0;
void NTAPI TLS_CALLBACK1(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
if (Reason == DLL_PROCESS_ATTACH) //和DLL类似
{
MessageBox(NULL, _T("TLS_CALLBACK 1 函数执行"), _T("提示"), MB_OK);
//利用NtQueryInformationProcess执行反调试
HMODULE hNtDll = LoadLibrary(_T("ntdll.dll"));
pfnNtQueryInformationProcess NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(hNtDll, "NtQueryInformationProcess");
NTSTATUS status = NtQueryInformationProcess(GetCurrentProcess(), ProcessDebugPort, &isDebuggerPresent, sizeof(DWORD), NULL);
if (status == 0x00000000 && isDebuggerPresent != 0)
{
MessageBox(NULL, _T("Debug!!!"), _T("提示"), MB_OK);
exit(-1);
}
}
}
void NTAPI TLS_CALLBACK2(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
if (Reason == DLL_PROCESS_ATTACH)
{
MessageBox(NULL, _T("TLS_CALLBACK 2 函数执行"), _T("提示"), MB_OK);
//利用NtSetInformationThread执行反调试
HMODULE hNtDll = LoadLibrary(_T("ntdll.dll"));
pfnNtSetInformationThread NtSetInformationThread = (pfnNtSetInformationThread)GetProcAddress(hNtDll, "NtSetInformationThread");
NTSTATUS status = NtSetInformationThread(GetCurrentThread(),ThreadHideFromDebugger, NULL, 0);//停止发送关于调试事件的通知
}
}
int main(void)
{
MessageBox(NULL, _T("Main函数执行"), _T("提示"), MB_OK);
return 0;
}
#pragma data_seg(".CRT$XLX")
//存储回调函数地址
PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { TLS_CALLBACK1, TLS_CALLBACK2, NULL };
#pragma data_seg()
0x02 如何反反调试
我们发现直接拖入OD中去,程序自动跑了起来,运行结束就终止了毫无调试的空间,此时就要使用OD上的一个非常好用的插件了 StrongOD 并勾选上 Break on Tls
重新加载程序就会断在TLS回调函数1上了
在根据IDA和OD动静配合解掉反调试