PEB->BeingDebugged修改为0时调试器无法捕获特定异常如何解决
这是Windows内核异常分发机制的固有设计:EXCEPTION_INVALID_HANDLE属于非严重可恢复异常,内核在向调试器发送首次机会异常通知前,会额外校验目标进程PEB->BeingDebugged字段值:若该字段为0,内核会判定进程无调试器附着,直接将异常递交给目标进程的SEH处理链,不会再向调试器分发事件。而EXCEPTION_BREAKPOINT等严重异常不受该校验规则限制,因此修改PEB->BeingDebugged后仍可正常捕获。
方案1:用户态HOOK异常分发入口
在目标进程内HOOKKiUserExceptionDispatcher或者NtRaiseException函数,异常触发时临时将PEB->BeingDebugged改回1,等异常分发完成后再恢复为0即可。
核心逻辑参考:PPEB peb = NtCurrentPeb(); UCHAR orig_flag = peb->BeingDebugged; // 临时恢复调试标志让内核正常派发异常到调试器 peb->BeingDebugged = 1; OriginalKiUserExceptionDispatcher(ExceptionRecord, ContextRecord); // 恢复反调试标志 peb->BeingDebugged = orig_flag;该方案无需修改调试器核心逻辑,兼容性好,适合用户态调试工具使用。
方案2:主动监控
NtClose调用
在调试器中通过设置执行断点HOOK目标进程的NtClose系统调用,每次调用前校验传入的句柄是否合法:如果检测到无效句柄,直接主动生成异常事件上报,跳过内核的异常分发校验逻辑。
句柄合法性可通过NtQueryInformationHandle函数实现无接触校验,不会触发额外异常。方案3:内核态捕获异常
若允许使用驱动,可在内核层通过注册异常回调的方式捕获所有进程异常,完全绕过用户态PEB字段的校验逻辑,该方案不受任何用户态反调试操作影响,兼容性最高。
如果仅需要兼容Windows 10 1809及以上版本,你可以在修改PEB->BeingDebugged的同时,保留内核态EPROCESS.DebugPort的正常状态,通过NtQueryInformationProcess传入ProcessDebugObjectHandle参数即可获取真实调试状态,不需要依赖PEB字段。
内容的提问来源于stack exchange,提问作者absvsb

