Windows下C++内核崩溃需用SEH捕获:一、用__try/__except捕获硬件异常;二、SetUnhandledExceptionFilter设全局处理器;三、AddVectoredExceptionHandler注册高优先级VEH;四、DllMain中启用SEH兼容性支持。

如果您在Windows平台开发C++应用程序时遇到内核级崩溃错误(如访问违规、页故障等),标准C++异常机制无法捕获这些操作系统底层异常。SEH(Structured Exception Handling)是Windows提供的原生异常处理机制,可捕获包括STATUS_ACCESS_VIOLATION、STATUS_STACK_OVERFLOW在内的硬件异常。以下是利用SEH捕获并处理此类异常的具体方法:
一、使用__try / __except语句块封装潜在崩溃代码
__try / __except是SEH最直接的语法形式,允许在函数内部对可能触发硬件异常的代码段进行隔离捕获。该机制在编译器生成的异常帧中注册当前作用域的异常处理回调,并在异常发生时由系统调度执行对应的__except过滤表达式。
1、在需要保护的代码区域外围添加__try关键字,并在其后紧跟一对大括号包裹待监控代码。
2、在__try块后立即编写__except(表达式)块,表达式必须返回EXCEPTION_EXECUTE_HANDLER、EXCEPTION_CONTINUE_SEARCH或EXCEPTION_CONTINUE_EXECUTION之一。
3、在__except块内调用GetExceptionCode()获取当前异常类型,判断是否为STATUS_ACCESS_VIOLATION(0xC0000005)或STATUS_IN_PAGE_ERROR(0xC0000006)等内核崩溃相关代码。
4、若需记录上下文,调用GetExceptionInformation()获取PEXCEPTION_POINTERS结构指针,从中提取ContextRecord和ExceptionRecord字段。
二、设置全局向量异常处理函数SetUnhandledExceptionFilter
当未被__try/__except捕获的异常向上传播至进程顶层时,系统将调用全局未处理异常过滤器。通过SetUnhandledExceptionFilter注册自定义处理函数,可在程序崩溃前完成堆栈捕获、内存快照与日志写入,避免直接终止。
1、声明符合LPTOP_LEVEL_EXCEPTION_FILTER签名的回调函数,参数为PEXCEPTION_POINTERS类型指针。
2、在main()或WinMain()入口早期调用SetUnhandledExceptionFilter并传入该函数地址。
3、在回调函数内检查ExceptionInfo->ExceptionRecord->ExceptionCode是否属于内核崩溃类异常,例如EXCEPTION_ACCESS_VIOLATION或EXCEPTION_ILLEGAL_INSTRUCTION。
4、使用MiniDumpWriteDump API将当前进程上下文写入.dmp文件,确保包含模块列表、线程上下文及可读内存页。
三、结合Vectored Exception Handling注册高优先级异常处理器
Vectored Exception Handlers(VEH)优先级高于SEH链和全局过滤器,且不受特定函数栈帧限制,适用于跨模块统一拦截内核崩溃异常。其注册后对整个进程有效,且按注册顺序逆序调用。
1、实现符合PVECTORED_EXCEPTION_HANDLER签名的函数,接收PEXCEPTION_POINTERS参数并返回LONG类型响应值。
2、调用AddVectoredExceptionHandler(TRUE, 处理器函数地址),其中TRUE表示插入到处理链头部以获得最高优先级。
3、在处理器内部比对ExceptionInfo->ExceptionRecord->ExceptionCode与STATUS_GUARD_PAGE_VIOLATION(0x80000001)或STATUS_NO_MEMORY(0xC0000017)等关键内核错误码。
4、若决定处理该异常,返回EXCEPTION_EXECUTE_HANDLER;若需交由后续处理器处理,则返回EXCEPTION_CONTINUE_SEARCH。
四、在DLL入口点DllMain中动态启用SEH兼容性支持
当C++ DLL被注入或延迟加载时,若目标进程禁用了映像SEH表(如通过/NXCOMPAT:NO或/SAFESEH:NO链接),可能导致__try块无法生效。需在DllMain中验证并强制启用运行时SEH支持路径。
1、在DllMain函数中检测dwReason是否为DLL_PROCESS_ATTACH。
2、调用IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE)确认系统支持快速失败机制。
3、使用SetProcessValidCallTargets或手动修改PEB结构中的NtGlobalFlag位FLG_ENABLE_HANDLE_TYPE_CHECKING以增强异常分发可靠性。
4、若检测到当前模块未启用SafeSEH,通过LoadLibrary加载ntdll.dll并调用RtlAddFunctionTable注册本地SEH表项。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











