02 内核异常的处理流程

1、用户层异常与内核异常
异常可以发生在用户空间也可以发生在内核空间。
无论是CPU异常还是模拟异常,是用户层异常还是内核层异常,都要通过KiDispatchException函数进行分发。理解这个函数是弄懂异常的关键。

2、VOID KiDispatchException (
IN PEXCEPTION_RECORD ExceptionRecord,
IN PKEXCEPTION_FRAME ExceptionFrame,
IN PKTRAP_FRAME TrapFrame,
IN KPROCESSOR_MODE PreviousMode,
IN BOOLEAN FirstChance
)
<1>_KeContextFromKframes将Trap_frames备份到context为返回3环做准备
<2>判断先前模式 , 0是内核调用,1是用户调用
<3>是否是第一次机会
<4>是否有内核调试器
<5>如果没有或者内核调试器不处理
<6>调用RtlDispatchException
<7>如果返回FALSE 也就是0
<8>再次判断是否有内核调试器,有就调用,没有直接蓝屏
代码片段

    call    _KeContextFromKframes@12 ; 将Trap_frames备份到context为返回3环做准备
.text:004259F0                 mov     eax, [esi]
.text:004259F2                 cmp     eax, 80000003h
.text:004259F7                 jz      short loc_425A67
.text:004259F9                 cmp     eax, 10000004h
.text:004259FE                 jnz     short loc_425A6D
.text:00425A00                 mov     dword ptr [esi], 0C0000005h
.text:00425A06                 cmp     byte ptr [ebp+arg_C], 1
.text:00425A0A                 jnz     short loc_425A6D
.text:00425A0C                 lea     eax, [ebp+Context]
.text:00425A12                 push    eax
.text:00425A13                 push    esi
.text:00425A14                 call    _KiCheckForAtlThunk@8 ; KiCheckForAtlThunk(x,x)
.text:00425A19                 test    al, al
.text:00425A1B                 jnz     loc_425B2D
.text:00425A21                 cmp     byte ptr ds:0FFDF0280h, 1
.text:00425A28                 jnz     short loc_425A6D
.text:00425A2A                 cmp     dword ptr [esi+14h], 8
.text:00425A2E                 jnz     short loc_425A6D
.text:00425A30                 test    _KeNumberProcessors+0Fh, 40h
.text:00425A37                 jnz     short loc_425A60
.text:00425A39                 mov     eax, large fs:124h
.text:00425A3F                 mov     eax, [eax+44h]
.text:00425A42                 test    byte ptr [eax+6Bh], 2
.text:00425A46                 jnz     short loc_425A60
.text:00425A48                 test    _KeNumberProcessors+0Fh, 80h
.text:00425A4F                 jnz     short loc_425A6D
.text:00425A51                 mov     eax, large fs:124h
.text:00425A57                 mov     eax, [eax+44h]
.text:00425A5A                 test    byte ptr [eax+6Bh], 1
.text:00425A5E                 jnz     short loc_425A6D
.text:00425A60
.text:00425A60 loc_425A60:                             ; CODE XREF: KiDispatchException(x,x,x,x,x)+C9↑j
.text:00425A60                                         ; KiDispatchException(x,x,x,x,x)+D8↑j
.text:00425A60                 xor     edi, edi
.text:00425A62                 mov     [esi+14h], edi
.text:00425A65                 jmp     short loc_425A6F
.text:00425A67 ; ---------------------------------------------------------------------------
.text:00425A67
.text:00425A67 loc_425A67:                             ; CODE XREF: KiDispatchException(x,x,x,x,x)+89↑j
.text:00425A67                 dec     [ebp+Context._Eip]
.text:00425A6D
.text:00425A6D loc_425A6D:                             ; CODE XREF: KiDispatchException(x,x,x,x,x)+90↑j
.text:00425A6D                                         ; KiDispatchException(x,x,x,x,x)+9C↑j ...
.text:00425A6D                 xor     edi, edi
.text:00425A6F
.text:00425A6F loc_425A6F:                             ; CODE XREF: KiDispatchException(x,x,x,x,x)+F7↑j
.text:00425A6F                 cmp     byte ptr [ebp+arg_C], 0 ; 判断先前模式 , 0是内核调用,1是用户调用
.text:00425A73                 jnz     short loc_425ADA ; 用户态调用跳转
.text:00425A75                 cmp     [ebp+arg_10], 1 ; 是否第一次调用
.text:00425A79                 jnz     short loc_425AB0
.text:00425A7B                 mov     eax, _KiDebugRoutine ; 是否有内核调试器
.text:00425A80                 cmp     eax, edi
.text:00425A82                 jz      short loc_425A9F ; 如果没有内核调试器
.text:00425A84                 push    edi
.text:00425A85                 push    edi
.text:00425A86                 lea     ecx, [ebp+Context]
.text:00425A8C                 push    ecx
.text:00425A8D                 push    esi
.text:00425A8E                 push    [ebp+var_2F0]
.text:00425A94                 push    ebx
.text:00425A95                 call    eax ; _KiDebugRoutine ; 有内核调试器,会调用这个内核调试器
.text:00425A95                                         ; 如果调用返回成功,说明内核调试器处理了,将context恢复到trap_frame
.text:00425A95                                         ; 如果内核调试器没有处理,就让3环的程序处理
.text:00425A97                 test    al, al
.text:00425A99                 jnz     loc_425B2D      ; 如果有内核调试器处理,直接跳转到要处理处
.text:00425A9F
.text:00425A9F loc_425A9F:                             ; CODE XREF: KiDispatchException(x,x,x,x,x)+114↑j
.text:00425A9F                 lea     eax, [ebp+Context] ; 如果没有内核调试器,或者内核调试器没有处理
.text:00425AA5                 push    eax             ; Context
.text:00425AA6                 push    esi             ; ExceptionRecord
.text:00425AA7                 call    _RtlDispatchException@8 ; 这个函数负责调用处理函数

3、RtlDispatchException(PEXCEPTION_RECORD ExceptionRecord, PCONTEXT Context)函数执行流程
typedef struct _EXCEPTION_REGISTRATION_RECORD{
struct _EXCEPTION_REGISTRATION_RECORD *Next;
PEXCEPTION_ROUTINE Handler;
}EXCEPTION_REGISTRATION_RECORD;
RtlDispatchException的作用就是:
遍历异常链表,调用异常处理函数,如果异常被正常处理了,该函数返回1。如果当前异常处理函数不能处理该异常,那么调用下一个异常处理函数,一次类推,如果到最后也没有能处理这个异常,则返回0

4、RtlDispatchException函数式执行流程
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/lifeshave/article/details/87529214
02
今日推荐