Windows異常分發函數---KiUserExceptionDispatcher


簡介

KiUserExceptionDispatcher 是SEH分發器的用戶模式的負責函數。當一個異常發生的時候,該異常將生成一個異常事件,內核檢查該異常是否是由於執行用戶模式代碼導致的。如果是這樣的話,內核修改棧上的trap frame,因此當內核從中斷或者異常返回的時候,線程將從KiUserExceptionDispatcher 函數執行而不是導致異常的指令。內核將另外安排幾個參數(一個 PCONTEXT 和一個 PEXCEPTION_RECORD),它們描述了異常發生時機器的狀態,而且在線程返回到用戶模式之前被傳遞給KiUserExceptionDispatcher 函數。
一旦內核模式棧展開,而且指令轉移到用戶模式的KiUserExceptionDispatcher 函數,該函數通過調用一個本地的函數RtlDispatchException來處理異常,RtlDispatchException是用戶模式異常處理邏輯中的核心函數。如果異常被成功分發的話(也就是SHE 鏈表中有一個函數宣稱可以處理該異常), RtlDispatchException調用RtlRestoreContext 函數實現最終的用戶模式上下文的設置,該函數只是加載給定的上下文中的寄存器到到處理器的體系結構執行狀態中。 否則,通過調用 NtRaiseException 函數,異常重新被提交到內核模式,這是最后一次機會了。在內核停止該進程之前,這給了用戶模式調試器(如果有的話)一個處理該異常的最后機會。 (內核內部在安排KiUserExceptionDispatcher執行之前給了用戶模式調試器和內核模式調試器第一次處理該異常的機會)

原型和偽碼

改函數位於模塊ntdll.dll,聲明如下:

VOID KiUserExceptionDispatcher(__in PEXCEPTION_RECORD ExceptionRecord,__in PCONTEXT ContextRecord)

下面是匯編代碼:

.text:7C958550 ; __stdcall KiUserExceptionDispatcher(x, x)
.text:7C958550                 public _KiUserExceptionDispatcher@8
.text:7C958550 _KiUserExceptionDispatcher@8 proc near  ; DATA XREF: .text:off_7C94C618o
.text:7C958550
.text:7C958550 var_C           = dword ptr -0Ch
.text:7C958550 var_8           = dword ptr -8
.text:7C958550 var_4           = dword ptr -4
.text:7C958550 arg_0           = dword ptr  4
.text:7C958550
.text:7C958550                 mov     ecx, [esp+arg_0] ; CONTEXT
.text:7C958554                 mov     ebx, [esp+0]     ; EXCEPTION_RECORD
.text:7C958557                 push    ecx
.text:7C958558                 push    ebx
.text:7C958559                 call    _RtlDispatchException@8 ; RtlDispatchException(x,x)
.text:7C95855E                 or      al, al
.text:7C958560                 jz      short loc_7C95856E       ;如果返回FALSE
.text:7C958562                 pop     ebx  ; ebx = EXCEPTION_RECORD
.text:7C958563                 pop     ecx  ; ecx = CONTEXT
.text:7C958564                 push    0
.text:7C958566                 push    ecx  ; ecx = CONTEXT
.text:7C958567                 call    _ZwContinue@8   ;已經處理好了,按照CONTEXT 中設置的值繼續執行就好了,此函數不返回
.text:7C95856C                 jmp     short loc_7C958579
.text:7C95856E ; ---------------------------------------------------------------------------
.text:7C95856E
.text:7C95856E loc_7C95856E:                           ; 沒有找到處理函數,提交一個異常->FirstChance = FALSE
.text:7C95856E                 pop     ebx  ; ebx = EXCEPTION_RECORD
.text:7C95856F                 pop     ecx  ; ecx = CONTEXT
.text:7C958570                 push    0
.text:7C958572                 push    ecx
.text:7C958573                 push    ebx
.text:7C958574                 call    _ZwRaiseException@12 ; ZwRaiseException(x,x,x)
.text:7C958574 _KiUserExceptionDispatcher@8 endp ; sp-analysis failed
.text:7C958574
.text:7C958579 ; ---------------------------------------------------------------------------
.text:7C958579                 retn    8


.text:0000000078EA124A                 public KiUserExceptionDispatcher
.text:0000000078EA124A KiUserExceptionDispatcher proc near     ; DATA XREF: .rdata:0000000078F54BB0o
.text:0000000078EA124A                                         ; .rdata:off_78F56298o
.text:0000000078EA124A                 cld
.text:0000000078EA124B                 mov     rax, cs:Wow64PrepareForException
.text:0000000078EA1252                 test    rax, rax
.text:0000000078EA1255                 jz      short loc_78EA1266
.text:0000000078EA1257                 mov     rcx, rsp
.text:0000000078EA125A                 add     rcx, 4F0h    ; rcx 為第一個參數ExceptionRecord 0x4F0 為其CONTEXT 的大小
.text:0000000078EA1261                 mov     rdx, rsp     ; rdx 為第二個參數,指向CONTEXT 結構
.text:0000000078EA1264                 call    rax ; Wow64PrepareForException
.text:0000000078EA1266
.text:0000000078EA1266 loc_78EA1266:                          
.text:0000000078EA1266                 mov     rcx, rsp
.text:0000000078EA1269                 add     rcx, 4F0h        ;ExceptionRecord
.text:0000000078EA1270                 mov     rdx, rsp         ;ContextRecord
.text:0000000078EA1273                 call    RtlDispatchException ;分發該異常RtlDispatchException(ExceptionRecord,ContextRecord);
.text:0000000078EA1278                 test    al, al
.text:0000000078EA127A                 jz      short loc_78EA1288
.text:0000000078EA127C                 mov     rcx, rsp        ; ContextRecord
.text:0000000078EA127F                 xor     edx, edx        ; ExceptionRecord-->0
.text:0000000078EA1281                 call    RtlRestoreContext
.text:0000000078EA1286                 jmp     short loc_78EA129D
.text:0000000078EA1288 ; ---------------------------------------------------------------------------
.text:0000000078EA1288
.text:0000000078EA1288 loc_78EA1288:                          
.text:0000000078EA1288                 mov     rcx, rsp
.text:0000000078EA128B                 add     rcx, 4F0h
.text:0000000078EA1292                 mov     rdx, rsp
.text:0000000078EA1295                 xor     r8b, r8b
.text:0000000078EA1298                 call    ZwRaiseException ;ZwRaiseException(ExceptionRecord,ContextRecord,FALSE);
.text:0000000078EA129D
.text:0000000078EA129D loc_78EA129D:
.text:0000000078EA129D                 mov     ecx, eax
.text:0000000078EA129F                 call    RtlRaiseStatus   ; RtlRaiseStatus(上面的函數的返回值);
.text:0000000078EA12A4                 nop
.text:0000000078EA12A5                 jmp     short $+2
.text:0000000078EA12A7 ; ---------------------------------------------------------------------------
.text:0000000078EA12A7
.text:0000000078EA12A7 loc_78EA12A7:
.text:0000000078EA12A7                 nop
.text:0000000078EA12A7 KiUserExceptionDispatcher endp ; sp-analysis failed

下面是c++偽碼:

VOID
KiUserExceptionDispatcher(__in PEXCEPTION_RECORD ExceptionRecord,__in PCONTEXT ContextRecord)
{
   NTSTATUS Status;

   //
   // (A custom calling convention is used that does not pass the parameter
   // values in a C-compatible fashion.)
   //

#if defined(_WIN64)

   //
   // 如果Wow64.dll 注冊它的幫助函數來處理異常事件,調用這個函數

   if (Wow64PrepareForException)
      Wow64PrepareForException(
         ExceptionRecord,
         ContextRecord
         );

#endif

   if (RtlDispatchException(
         ExceptionRecord,
         ContextRecord))
   {
#if defined(_WIN64)
      RtlRestoreContext( ContextRecord );
#else
      NtContinue(
         ContextRecord,
         FALSE
         );
#endif

      Status = (NTSTATUS)ContextRecord->Rax;

      RtlRaiseStatus( Status );

      //
      // No return from RtlRaiseStatus.
      //

   }

   Status = NtRaiseException(
      ContextRecord,
      ExceptionRecord,
      FALSE
      );

   RtlRaiseStatus( Status );

   //
   // No return from RtlRaiseStatus.
   //
}

參數

  • PCONTEXT ContextRecord
    這個結構包含有關最近發生的異常的詳細信息,這些信息獨立於C P U,具體參考《Windows異常相關數據結構
  • PEXCEPTION_RECORD ExceptionRecord
    包含處理器特定的寄存器數據。系統使用上下文結構執行各種內部操作,具體參考《Windows異常相關數據結構

這兩個參數對我們進行異常調試和dmp分析很有用,可以得到異常信息和還原調用棧


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM