当系统Debug模式下:
KdDebuggerEnabled1
KdPitchDebugger0
KiDebugRoutine==KdpTrap
此模式下R3触发的异常相关若没有异常处理接管,电脑直接卡死
当系统正常模式下:
KdDebuggerEnabled0
KdPitchDebugger1
KiDebugRoutine==KdpStub
此模式下R3触发异常若没有异常处理接管,则程序崩溃
KdDebuggerNotPresent:启动Debug并且连接调试器0,否则1
KdEnteredDebugger:中断到调试器标志,中断前会设1 恢复后会设0
KiDispatchException的一些研究
内核异常:
1.如果是第一次处理异常并且存在内核调试器,处理成功则返回
2.不存在内核调试器,或者内核调试器不能处理异常,内核就会调用RtlDispatchException函数,依次调用注册的异常处理函数(SEH)
3.如果仍然没处理成功尝试第二次向内核调试器发往异常消息
4.仍然失败,则蓝屏
用户异常:
1.如果是第一次处理异常,如果调试端口为空并且存在内核调试器,就会将异常交给内核调试器处理
2.若调试端口不为空,则发送一个消息至调试端口
3.如果调试器处理了异常,则返回,继续执行
4.否则,把异常信息填充都用户栈中,并且设置好用户模式的Eip为KeUserExceptionDispatcher,并且准备该函数锁需参数,然后KiDipatchException返回
5.当从内核模式的异常处理例程返回后,ntdll.dll的KiUserException-Dpspatcher函数获得控制,它会试图将该异常分发给一个基于调用帧的异常处理器。如果存在一个基于调用帧的异常处理器处理了该异常,则程序继续执行.
6.如果该异常仍然未被处理,则通过NtRaiseException函数再次进入内核中处理该函数。这一次KiDispatchException函数被调用时,FirstChance的参数为FALSE。
7.如果是第二次处理进程,并且当前进程有一个调试端口,则发送一个消息至调试端口,然后等待应答.如果进程的调试器处理了该异常,则返回,并继续执行。
8.否则,如果当前进程有一个异常端口,则发送一个消息至异常端口,然后等待应答。
9.如果处理成功则返回,并继续执行。如果处理失败,则进程终止
typedef struct _EXCEPTION_RECORD {
DWORD ExceptionCode;//异常产生的原因
DWORD ExceptionFlags;//异常标志
struct _EXCEPTION_RECORD *ExceptionRecord;//相关联的异常记录
PVOID ExceptionAddress;//用来记录异常地址,错误类异常与陷阱类异常会有区别
DWORD NumberParameters; // 附加参数个数,即ExceptionInformation数组的有效个数。
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD, *PEXCEPTION_RECORD;
VOID KiDispatchException (
IN PEXCEPTION_RECORD ExceptionRecord, // 指向异常信息结构体
IN PKEXCEPTION_FRAME ExceptionFrame, // 指向异常帧,0
IN PKTRAP_FRAME TrapFrame, // 指向陷阱帧,寄存器环境
IN KPROCESSOR_MODE PreviousMode, // 异常产生的位置 R0/R3
IN BOOLEAN FirstChance // 是否是第一次分发异常 第一次==TRUE
)
VOID
KiDispatchException(
IN PEXCEPTION_RECORD ExceptionRecord,
IN PKEXCEPTION_FRAME Exc