原理
SetUnhandledExceptionFilter 可以注册一个异常处理函数,当一个异常产生且我们的 try - catch(或 try - expect)没有处理处理这个异常时,异常会转交给 SetUnhandledExceptionFilter ,这是我们的应用程序处理异常的最后机会。
我们可以自己触发一个异常,然后不在 try-catch 中处理它,如果存在调试器则调试器就会接管这个异常,那么这个异常就不会走到我们的 SetUnhandledExceptionFilter 注册的异常处理函数(调试器默认情况下是接管的,当然调试器也可以选择不接管这个异常,所以这属于一种比较低级的反调试手段 🙃)
函数介绍
/*
允许应用程序替代进程的每个线程的顶级异常处理程序
返回值:用该函数建立的上一个异常过滤器的地址
*/
LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(
LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter // 一个指向顶级异常过滤器函数的指针,这个函数的返回值必须是 EXCEPTION_EXECUTE_HANDLER 或 EXCEPTION_CONTINUE_EXECUTION 或 EXCEPTION_CONTINUE_SEARCH
);
/*
在调用线程中引发异常
*/
VOID RaiseException(
DWORD dwExceptionCode, // 异常代码,参考:https://docs.microsoft.com/en-us/windows/win32/debug/getexceptioncode
DWORD dwExceptionFlags, // 异常标志,0表示连续异常,EXCEPTION_NONCONTINUABLE 表示非连续异常
DWORD nNumberOfArguments, // lpArguments 的参数数量
const ULONG_PTR *lpArguments // 参数数组
);
代码示例
// Test_Console_1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <Windows.h>
using namespace std;
// 如果有调试器,则不会执行这个函数
BOOL bIsBeinDbg = TRUE;
LONG WINAPI UnhandledExcepFilter(PEXCEPTION_POINTERS pExcepPointers){
bIsBeinDbg = FALSE;
return EXCEPTION_CONTINUE_EXECUTION;
}
int main()
{
// 注册异常处理函数
LPTOP_LEVEL_EXCEPTION_FILTER Top = SetUnhandledExceptionFilter(UnhandledExcepFilter);
// 主动抛出一个异常
RaiseException(EXCEPTION_FLT_DIVIDE_BY_ZERO, 0, 0, NULL);
if (bIsBeinDbg == TRUE) {
cout << "发现调试器!" << endl;
}
else {
cout << "没有调试器!" << endl;
}
main_end:
getchar();
return 0;
}
效果图
vs调试:
正常打开: