标题: "!gflag +soe"的意义 创建: 2018-02-08 13:47 链接: https://scz.617.cn/windows/201802081347.txt 以x64/Win10 16299.15.amd64fre.rs3_release.170928-1534为例。 设计实验,复制mspaint_0x33.exe,将$exentry首字节改成0x33。假设已经设置用户 态JIT调试器,假设已经挂上kd。 执行mspaint_0x33.exe,用户态流程到达$exentry时触发 STATUS_ACCESS_VIOLATION(0xC0000005)异常,内核态流程到达nt!KdpReport+0x125: -------------------------------------------------------------------------- KdpReport () { ... switch ( ExceptionCode ) { ... case STATUS_BREAKPOINT: goto EnterDebugger; ... } /* end of switch */ ... if ( NtGlobalFlag & FLG_STOP_ON_EXCEPTION ) { if () { /* * nt!KdpReport+0x125 */ goto EnterDebugger; } } ... } /* end of KdpReport */ -------------------------------------------------------------------------- 如果在kd中已经"!gflag +soe",最终会跳至EnterDebugger,陷入kd: Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. ... 0033:00007ff6`f4cdff10 3383ec28e8d7 xor eax,dword ptr [rbx-2817D714h] ds:002b:ffffffff`d7e828ec=???????? 在kd里g之后,用户态JIT调试器弹出。如果没有"!gflag +soe",流程不会到 "nt!KdpReport+0x125",不会陷入kd,用户态JIT调试器直接弹出。 (a2c.1724): Access violation - code c0000005 (!!! second chance !!!) mspaint_0x33!wWinMainCRTStartup: 00007ff6`f4cdff10 3383ec28e8d7 xor eax,dword ptr [rbx-2817D714h] ds:ffffffff`d7e828ec=???????? "sxe av"或"sxe 0xC0000005"是缺省设置,但用户态JIT调试器拿到的仍然是 SecondChance。 -------------------------------------------------------------------------- Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug] "Auto"="1" -------------------------------------------------------------------------- 上面是Auto等于1时的情况。如果Auto等于0,离开内核态后,会弹出对话框让你选择 终止、调试,点调试才会弹出用户态JIT调试器。 第一个坑,假设Auto等于0,g离开内核态之前,必须先"!gflag -soe",否则不停地 陷入kd,直至"!gflag -soe"。 第二个坑,如果用cdb启动mspaint_0x33,无论是否"!gflag +soe",都不会陷入kd, 微软就是这样设计的,不是BUG。 -------------------------------------------------------------------------- KiDispatchException () { ... if ( ( PsGetCurrentProcess()->DebugPort == NULL ) && ... ) { if ( KdTrap( TrapFrame, Unused, ExceptionRecord, &Context, PreviousMode, FALSE ) != FALSE ) { goto Handled1; } } if ( DbgkForwardException( ExceptionRecord, TRUE, FALSE ) == TRUE ) { goto Handled2; } ... } -------------------------------------------------------------------------- 用cdb启动mspaint_0x33时,DebugPort不为空,流程最终不会路过对 FLG_STOP_ON_EXCEPTION的检查,此时与"!gflag +soe"完全无关。 设计实验,复制mspaint_int3.exe,将$exentry首字节改成0xCC,即int3。 执行mspaint_int3.exe,你会发现,即使没有"!gflag +soe",也会陷入kd: Break instruction exception - code 80000003 (first chance) ... 0033:00007ff6`1befff10 cc int 3 nt!KdpReport对来自用户态的断点异常(0x80000003)优先处理,不受"!gflag +soe" 影响,没有用户态调试器(cdb)的情况下,必将陷入内核态调试器(kd)。还有几个这 样被优先处理的异常,逆一下nt!KdpReport就看到了。 对于来自用户态的异常,只有有限的几个死活会被nt!KdpReport处理,其他绝大多数 缺省都不被nt!KdpReport处理。"!gflag +soe"的意义是,改变绝大多数来自用户态 的异常不被nt!KdpReport处理的缺省设定。 别看nt!KdpReport对SecondChance死活都处理,那个SecondChance不是给用户态异常 准备的。实际上"用户态异常+SecondChance"的流程不可能到达nt!KdpReport,此时 会去nt!KeUserExceptionDispatcher,也就是ntdll!KiUserExceptionDispatch,后 者负责呼叫用户态JIT调试器(假设已设置)。 (12a8.64c): Break instruction exception - code 80000003 (!!! second chance !!!) mspaint_int3!wWinMainCRTStartup: 00007ff6`1befff10 cc int 3 对于mspaint_int3.exe,如果在kd里g,你会发现用户态JIT调试器没有弹出,进程直 接结束。为了让JIT弹出,必须在kd里gn或gN,表示kd没有处理0x80000003号异常。 kd> sx ... av - Access violation - break - not handled ... bpe - Break instruction exception - break bpec - Break instruction exception continue - handled ... sse - Single step exception - break ssec - Single step exception continue - handled ... wob - WOW64 breakpoint - break - handled wos - WOW64 single step exception - break - handled ... av的"handling status"缺省是"not handled",bpec的"handling status"缺省是 "handled",所以有前面mspaint_0x33、mspaint_int3的区别。 -------------------------------------------------------------------------- 将bpec的"handling status"调成"not handled" sxd -h bpe sxn -h bpe sxi -h bpe sxd bpec sxn bpec sxi bpec 将bpec的"handling status"调成"handled" sxe -h bpe sxe bpec --------------------------------------------------------------------------