反调试——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);
}

这样调用了该函数之后就直接崩溃了。