异常派发研究KiDispatchException

当系统Debug模式下:
KdDebuggerEnabled1
KdPitchDebugger
0
KiDebugRoutine==KdpTrap

此模式下R3触发的异常相关若没有异常处理接管,电脑直接卡死

当系统正常模式下:
KdDebuggerEnabled0
KdPitchDebugger
1
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 ExceptionFrame,
IN PKTRAP_FRAME TrapFrame,
IN KPROCES

### Windows 异常处理机制详解 Windows 系统的异常处理机制是一种结构化异常处理(Structured Exception Handling, SEH),它为应用程序提供了一种统一的方式来捕获和处理运行时错误。这种机制不仅能够处理由程序逻辑引发的软件异常,还能够捕获硬件级别的错误,例如内存访问违例、除零错误等。 #### 1. 异常处理的基本流程 当发生异常时,CPU 会查询中断向量表以定位对应的异常处理函数。这一过程通常会调用操作系统内核中的特定函数来分发异常[^2]。具体步骤如下: - **异常触发**:当 CPU 遇到无法处理的指令或状态时,会产生一个硬件异常。 - **中断向量查询**:CPU 查询中断向量表,找到与该异常对应的处理函数地址。 - **内核级分发**:系统调用内核函数(如 `_KiTrapXX`)进行初步处理,并进一步调用 `KiDispatchException` 分发异常[^2]。 - **用户级回调**:如果异常未被内核完全处理,则通过回调机制传递给用户模式下的异常处理器[^4]。 #### 2. 结构化异常处理(SEH) SEH 是 Windows 提供的一种异常处理机制,允许开发者在程序中定义异常处理器。其核心思想是通过链式结构维护一系列异常处理器,确保异常能够被逐层捕获和处理。 - **异常处理器注册**:每个线程都有一个指向当前异常处理器的指针(存储在 FS:[0] 中)。当新的异常处理器被创建时,它会被插入到链表的头部[^1]。 - **回调函数**:当异常发生时,系统会依次调用链表中的异常处理器,直到某个处理器成功处理了异常。回调函数的原型如下: ```c EXCEPTION_DISPOSITION __cdecl _except_handler( struct _EXCEPTION_RECORD *ExceptionRecord, void * EstablisherFrame, struct _CONTEXT *ContextRecord, void * DispatcherContext ); ``` 这个函数负责决定是否继续处理异常,或者将异常传递给下一个处理器[^3]。 #### 3. C++ 异常处理与 SEH 的结合 C++ 异常处理机制可以与 Windows 的 SEH 结合使用。通过调用 `SetUnhandledExceptionFilter` API,开发者可以注册一个全局异常过滤器,从而捕获未处理的异常。此外,C++ 的 `catch(...)` 块也可以捕获操作系统产生的异常,例如“内存访问违例”等。 #### 4. 异常处理的优点 - **简化实现**:通过利用操作系统的异常处理机制,C++ 编译器可以减少对异常处理的支持代码量。 - **全面覆盖**:SEH 不仅能够捕获软件异常,还能处理硬件级别的错误。 - **灵活性**:开发者可以通过自定义异常处理器实现特定的错误恢复逻辑[^5]。 #### 5. 注意事项 尽管 SEH 和 C++ 异常处理功能强大,但在实际开发中需要注意以下几点: - 确保异常处理器的逻辑正确,避免无限递归或死循环。 - 在多线程环境中,需特别注意异常处理器链的管理,防止线程间冲突。 - 对于性能敏感的应用程序,应尽量减少异常的发生频率,因为异常处理的开销较高。 ```c // 示例:简单的 SEH 使用 #include <windows.h> #include <stdio.h> LONG WINAPI MyExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo) { printf("An exception occurred: %X\n", ExceptionInfo->ExceptionRecord->ExceptionCode); return EXCEPTION_EXECUTE_HANDLER; } void main() { __try { // 触发异常 int* ptr = NULL; *ptr = 10; // 访问空指针 } __except (MyExceptionHandler(GetExceptionInformation())) { printf("Exception handled.\n"); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值