内核层异常的收集与处理

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异常的拓展,之后我们会讲解局部展开与全局展开等骚操作,之后你再看这里就能很好理解了。

 

posted @ 2020-04-25 09:16  OneTrainee  阅读(582)  评论(0编辑  收藏  举报