技术开发 频道

轻视WinXPe异常系统健壮性将命悬一线

2.Windows XPe异常处理流程

  Windows XPe有两种运行模式:内核模式和用户模式,并且允许一个运行于用户模式的应用程序随时切换为内核模式或切换回来。因此,Windows XPe的异常处理也和桌面Windows 相似,有两种不同的处理流程。

  (1)内核模式异常处理流程

  内核是 Windows XPe的内部核心,它负责调度和同步线程、处理异常和中断、加载应用程序和治理虚拟内存。系统内核包括内存管理、进程管理以及异常处理。当中断到来时,内核根据IRQ来调用相应的中断服务例程(ISR)。先判断KiDebugRoutine是否为空,不为空就将Context、陷阱帧、异常记录、异常帧、发生异常的模式等压入栈并将控制交给KiDebugRoutine。若KiDebugRoutine为空或者KiDebugRoutine未处理异常,则将Context结构和异常记录ExceptionRecord压栈,并调用内核模式的RtlDispatchException在内核堆栈中查找基于帧的异常处理例程。

  RtlDispatchException调用RtlpGetRegistrationHead获取当前线程异常处理链表指针,并调用RtlpGetStackLimits获取当前线程堆栈底和顶。然后开始由异常处理链表指针遍历链表查找异常处理例程,这里和用户态有一点不同是既没有顶层异常处理例程(TOP LEVEL SEH),也没有默认异常处理例程。然后对每个当前异常处理链表指针检查判断堆栈是否有效及堆栈是否是DPC堆栈。

  处理后RtlDispatchException再判断异常处理例程的返回值,若为ExceptionContinueExecution,则返回TRUE到上一层,否则调用RtlRaiseException进入到KiDispatchException的第二次机会处理异常;若为ExceptionContinueSearch则继续查找异常处理例程;若为ExceptionNestedException嵌套异常,则保留当前异常处理链表指针为内层异常处理链表并继续查找异常处理例程。简单说就是,当异常发生于内核模式,会给予内核调试器第一次机会和第二次机会处理异常。

  (2)用户模式下陷阱帧异常处理流程

  在进行用户态异常的分派前,KiDispatchException先判断异常是否来自用户模式,是的话将Context.ContextFlags 上CONEXT_FLOATING_POINT,这意味着对来自用户模式的异常总是尝试分派浮点状态,这样可以允许异常处理程序或调试器检查和修改协处理器的状态。然后从陷阱帧中取出寄存器值填入Context结构,并判断是否是断点异常(int 0x3和int 0x2d),如果是的话先将Context.Eip减一使它指向int 0x3指令,然后根据不同模式而采取不同处理过程。当异常被处理后就将设置好陷阱帧并返回到陷阱处理程序,在Iret返回发生异常的地方继续执行。

  例如,当用户模式下发生异常后,CPU记录当前各寄存器状态并在内核堆栈中建立陷阱帧TrapFrame,然后将控制交给对应异常的陷阱处理程序。当陷阱处理程序能处理异常时,比如缺页时通过调页程序MmAccessFault,将页换入物理内存后通过iret返回发生异常的地方。但大多数情况下是无法处理异常的,则此时先是调用CommonDispatchException在内核堆栈中建立异常记录ExceptionRecord和异常帧ExceptionFrame。然后,调用KiDispatchException进行异常的分派,这个函数是Windows XPe下异常处理的核心函数,负责异常的分派处理。
 

0
相关文章