反调试——3——反调试手段
反调试的方法有非常非常多,这里介绍一些比较常见的。
通过CloseHandle()
通过CloseHandle来试图关闭一个不存在的句柄,如果程序处于调试状态就会引发异常,否则没有任何反应。
这种机制在User下看起来就是调用一个CloseHandle,但是其实它的内部逻辑在内核层次下是实现了的。 这个大家可以试一下,反正我试出来是可行的。
void testCloseHandle()
{
CloseHandle((HANDLE)0x1234);
}
所以我们就可以采用处理异常的办法来处理:
void testCloseHandle()
{
__try
{
CloseHandle((HANDLE)0x1234);
}
__except(1)
{
cout << "CloseHandle验证失败,程序正在被调试" << endl;
return;
}
cout << "CloseHandle验证成功" << endl;
}
设置线程信息分离调试器
关键函数:ZwSetInformationThread()
NTSYSAPI NTSTATUS ZwSetInformationThread(
HANDLE ThreadHandle,
THREADINFOCLASS ThreadInformationClass,
PVOID ThreadInformation,
ULONG ThreadInformationLength
);//有点类似NtQueryInformation
同样的THREADINFOCLASS这个也是一个枚举类型,和上一章非常相识:
https://geoffchappell.com/studies/windows/km/ntoskrnl/api/ps/psquery/class.htm这个网站里面有这个枚举变量的值的详细介绍。
这里我们只需要用到0x11 也就是十进制的17这个值:0x11:ThreadHideFromDebugger,这个枚举量的意思就是将线程和调试器隔离。
同样它也是ntdll.dll里面的函数:
void testZwSetInformationThread()
{
HMODULE hModule = LoadLibraryA("Ntdll.dll");
_ZwSetInformationThread ZwSetInformationThread = (_ZwSetInformationThread)GetProcAddress(hModule, "ZwSetInformationThread");
ZwSetInformationThread(GetCurrentThread(),(THREAD_INFORMATION_CLASS)0x11, NULL, NULL);
}