Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html
内核层异常的收集与处理
前面我们分析过,存在两种异常,CPU异常与用户模拟异常,其异常触发时收集的线路是不同的,但是其最终走经过KiDispatchException函数。
当走到KiDispatchException,CPU异常与用户模拟异常唯一的区别是CPU异常最高位置1(nt!KiRaiseException异常派发时的上一行代码),其余记录的都是一样的。
而KiDispatchException的处理是按照其先前模式来处理的,也就是内核异常与用户异常两种,而不是按照CPU异常与用户模拟异常来进行处理。
1.内核层异常的派发(Nt!KiDispatchException函数分析)
这部分我们先看内核异常的处理流程,至于用户模式,其因为要返回三环执行,稍微复杂,等其分析完成之后再来一起进行汇总处理。
如下图,我们截取一部分,其核心的执行流程为:
① 如果存在内核调试器则调用内核调试器;
② 如果不存在或者不成功,调用RtlDispatchException调用内核的SEH异常来进行处理;
③ 如果RtlDispatchException不成功,则再次尝试判断内核调试器;
④ 如果上面某一步成功,则直接返回正常退出;
⑤ 否则调用KeBugCheckEx触发蓝屏。
2.内核层异常的处理(Nt!RtlDispatchException函数分析)
该函数是处理内核异常的核心函数,如果没有内核调试器,则就使用这个函数来进行分析,其操作如下所示:
其中,我们在分析前必须要有几个重要的数据结构:
1)异常的标志位 flag
#define EXCEPTION_NONCONTINUABLE 0x1 // Noncontinuable exception
#define EXCEPTION_UNWINDING 0x2 // Unwind is in progress
#define EXCEPTION_EXIT_UNWIND 0x4 // Exit unwind is in progress
#define EXCEPTION_STACK_INVALID 0x8 // Stack out of limits or unaligned
#define EXCEPTION_NESTED_CALL 0x10 // Nested exception handler call
#define EXCEPTION_TARGET_UNWIND 0x20 // Target unwind in progress
#define EXCEPTION_COLLIDED_UNWIND 0x40 // Collided exception handler call
2)异常结果的返回值
enum _EXCEPTION_DISPOSITION {
ExceptionContinueExecution = 0, // 异常处理成功
ExceptionContinueSearch = 1, // 异常没有处理,继续寻找
ExceptionNestedException = 2, // 二次异常,存在嵌套异常
ExceptionCollidedUnwind = 3 // 发生嵌套的展开
};
注意:如果是SEH扩展的异常,我们使用这个,因为其使用SEH拓展结构,需要进行异常展开的操作,这些对程序员是不可见的。
平时我们再手动写SEH异常,不需要操心异常的展开等额外操作,所以使用下面的结构:
#define EXCEPTION_EXECUTE_HANDLER 1 // 异常被识别,_except模块中处理该异常
#define EXCEPTION_CONTINUE_SEARCH 0 // 异常未被识别,继续调用下一个Handler来处理异常
#define EXCEPTION_CONTINUE_EXECUTION (-1) // 异常已被忽略或修复,不继续往下寻找
该函数的核心操作如下:
① 通过KPCR获取异常链;
② 取出一个异常处理结点,ExceptionRegistrationRecord(next,handler);
③ 通过全局变量判断是否需要异常记录;
④ 执行对应的handler函数,获取返回结果;
⑤ 如果返回为 ExceptionContinueExecution并且eflags的EXCEPTION_NONCONTINUABLE位为0,则返回成功;
⑥ 否则继续找下一个,处理失败,或者引发二次异常。
3.总结
这里我们只是简单分析了一下内核层的SEH异常的大体流程,其中我们会发现二次异常的嵌套以及展开UnWind等操作,这里可能会让你感到头晕,
没关系,我们在分析用户异常时会详细解释其编译器对于SEH异常的拓展,之后我们会讲解局部展开与全局展开等骚操作,之后你再看这里就能很好理解了。