VEH无法捕获内核模式、硬件中断或已被SEH链/调试器拦截的非法内存访问;其仅对用户态未被处理的异常有效,且恢复执行需谨慎修改上下文并确保逻辑自洽。

VEH(Vectored Exception Handling)不能捕获所有非法内存访问,尤其是那些发生在内核模式、硬件中断或已由 SEH 链提前处理的异常;它只对用户态未被其他异常处理器拦截的异常有效。
VEH 注册后为什么 Access violation 依然崩溃?
常见原因是异常在到达 VEH 前已被系统 SEH 链(如 CRT 的 _set_se_translator 或 MFC 的异常过滤器)吞掉并转为 C++ 异常,或被调试器截获。VEH 是“向量式”的,优先级高于 SEH,但低于内核异常分发逻辑,且不覆盖已安装的顶层 SEH 处理器。
- 确保调用
AddVectoredExceptionHandler返回非 NULL 句柄,否则注册失败 - 传入的回调函数必须声明为
LONG WINAPI VecHandler(PEXCEPTION_POINTERS),签名错误会导致栈破坏 - 若程序启用了
/SAFESEH或运行在 CFG(Control Flow Guard)启用环境下,部分异常可能被提前终止,VEH 不会触发 - 调试状态下(如 VS 附加调试),IDE 默认会拦截
EXCEPTION_ACCESS_VIOLATION,需在「调试 → 异常设置」中取消勾选对应异常类型
AddVectoredExceptionHandler 的 bFirst 参数影响什么?
该参数控制 VEH 回调在向量链中的插入位置:设为 TRUE 插入链首(最先执行),FALSE 插入链尾(最后执行)。但注意:VEH 链本身不参与 SEH 层级嵌套,它独立于线程的 EXCEPTION_REGISTRATION_RECORD 链。
在 Windows 上执行终端命令,或对比 Windows 与 Linux 的 Shell 语法时使用。建议先检测当前 Shell 是 PowerShell 还是 cmd.exe,再给出相应命令……
- 多数场景应设为
TRUE,避免其他第三方库(如某些反作弊或监控 SDK)先于你处理并返回EXCEPTION_EXECUTE_HANDLER - 若返回
EXCEPTION_CONTINUE_SEARCH,系统继续查找下一个 VEH;返回EXCEPTION_EXECUTE_HANDLER则终止搜索,并跳转到异常发生点的上下文(此时可安全读写ExceptionInfo->ContextRecord) - 不要在回调中抛出 C++ 异常——VEH 运行在异步信号上下文中,栈帧可能不完整,
throw极易导致二次崩溃
如何安全地从 EXCEPTION_ACCESS_VIOLATION 中恢复执行?
恢复的前提是:确认非法访问是可控的(如模拟页缺失、访问对齐检查、或自定义内存池越界),且能通过修改 ContextRecord 调整指令指针或寄存器状态绕过故障点。
立即学习“C++免费学习笔记(深入)”;
- 仅当
ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION且ExceptionInfo->ExceptionRecord->NumberParameters >= 2时,才可读取ExceptionInfo->ExceptionRecord->ExceptionInformation[1](出错地址) - 修改
ExceptionInfo->ContextRecord->Rip(x64)或Eip(x86)可跳过出错指令,但必须确保跳转后逻辑自洽(例如跳过一条mov rax, [rbx+0x10]前,已保证rbx有效) - 直接修复访问地址(如映射新页、填充哨兵值)需配合
VirtualProtect和VirtualAlloc,且注意CONTEXT结构在不同 CPU 架构下字段名不同(x64 用Rbp/Rsp,x86 用Ebp/Esp) - 恢复执行不等于“忽略错误”——未解决根本问题(如野指针)会导致后续相同地址再次触发,建议记录
ExceptionInformation[1]和调用栈(用RtlCaptureStackBackTrace)用于诊断
VEH 恢复执行最危险的盲区是:它无法区分“读/写/执行”类型的具体违例(ExceptionInformation[0] 表示访问类型,但文档未完全公开语义),且对硬件单步、断点等异常无权干预。真要稳定兜底,得结合页面保护(PAGE_GUARD)、影子栈和运行时内存标记,而不是只靠一次 VEH 回调。

















