我看到了一个名为The Ultimate Anti-Reversing Reference 的文档,它描述了各种反调试技术。在点4.Thread Local Storage有提到
每当创建或销毁线程时都会调用线程本地存储回调(除非进程调用 kernel32 DisableThreadLibraryCalls() 或 ntdll LdrDisableThreadCalloutsForDll() 函数)。这包括当调试器附加到进程时由 Windows 创建的线程。调试器线程是特殊的,因为它的入口点不指向图像内部。相反,它指向 kernel32.dll 内部。因此,一个简单的调试器检测方法是使用线程本地存储回调来查询每个创建的线程的起始地址。可以使用此 32 位代码进行检查,以检查 32 位或 64 位版本的 Windows 上的 32 位 Windows 环境:
push eax
mov eax, esp
push 0
push 4
push eax
;ThreadQuerySetWin32StartAddress
push 9
push -2 ;GetCurrentThread()
call NtQueryInformationThread
pop eax
cmp eax, offset l1
jnb being_debugged
...
我写了 C++ 代码如下
bool fooBar()
{
uintptr_t dwStartAddress;
TFNNtQueryInformationThread ntQueryInformationThread = (TFNNtQueryInformationThread)GetProcAddress(
GetModuleHandle(TEXT("ntdll.dll")), "NtQueryInformationThread");
if (ntQueryInformationThread != 0) {
NTSTATUS status = ntQueryInformationThread(
(HANDLE)-2,
(_THREADINFOCLASS)9,
&dwStartAddress,
sizeof(dwStartAddress),
nullptr);
cout << hex << "dwStartAddress: 0x" << dwStartAddress << dec << endl;
}
我在 TLS 回调中运行它
EXTERN_C
#ifdef _M_X64
#pragma const_seg (".CRT$XLB")
const
#else
#pragma data_seg (".CRT$XLB")
#endif
PIMAGE_TLS_CALLBACK p_thread_callback = fooBar;
#pragma data_seg ()
#pragma const_seg ()
dwStartAddress 的值指向 .exe 模块,而不是文本中所述的 kernel32.dll。无论我是只运行 exe 还是在调试器中运行,或者将调试器附加到进程中(虽然我对附加不是很有经验,所以也许我在这里做错了什么)。
我做错了什么,还是文本错误/不再有效?