Windows的SEH機理簡要介紹

來源:互聯網
上載者:User

1.異常分類

一般來說,我們把Exception分為2類,一類是CPU產生的異常,我們稱之為CPU異常(或者硬體異常)。另一類為是通過調用RaiseException API產生的軟體異常,我們稱之為軟體異常。

Windows使用同一的方式(KiDispatchException)來描述和分發這兩類異常。但是,在處理各自異常時,會略有區別。

 

一般來說,異常處理過程可以分為2個階段,第1階段:異常登記過程;第2階段:異常分發過程。下面分別簡要介紹。

 

2.異常登記

1) CPU異常(硬體異常)登記:

在windows kernel中,存在一張中斷描述符表(IDT, Interupt Descriptor Table). IDT是一張位於核心態實體記憶體中的線性表,其有256個表項。IDT中的每個表項叫做門描述符(Gate Descriptor)。門描述符的基本作用就是將CPU異常對應的中斷號與其對應的異常處理函數KiTrapXX關聯起來。

例如,0號中斷(即除0錯誤)對應的處理常式為nt!KiTrap00

同時,我們可以通過以下debug comnand來列出IDT表中的各個表項。

lkd>!idt -a

 

對於CPU異常,通過中斷向量找到其中斷處理常式 KiTrapXX後,該KiTrapXX會調用CommDispatchException函數,其會擷取異常發生時候的適當參數,用來初始化EXCEPTION_RECORD結構體之後,開始調用KiDispatchException進行異常分發。

(簡述如下:中斷向量 - 〉KiTrapXX - > CommonDispatchException - >KiDispatchException)

EXCEPTION_RECORD的結構如下:
0:000> dt ntdll!_EXCEPTION_RECORD
   +0x000 ExceptionCode    : Int4B
   +0x004 ExceptionFlags   : Uint4B
   +0x008 ExceptionRecord  : Ptr32 _EXCEPTION_RECORD
   +0x00c ExceptionAddress : Ptr32 Void
   +0x010 NumberParameters : Uint4B
   +0x014 ExceptionInformation : [15] Uint4B

 

2) 軟體異常登記

軟體異常是通過直接或者間接調用核心服務NtRaiseException而產生的。而使用者態中可以通過RaiseException API,或者Try-catch等進階語言來調用這個核心服務,而通過RaiseException來登記軟體異常的過程可以簡單表述如下:

RaiseException在初始化一個EXCEPTION_RECORD結構體之後,開始調用NTDLL中的RtlRaiseException; RtlRaiseException在初始化CONTEXT結構體之後,開始調用核心中NtRaiseException, NtRaiseException再調用另外一個核心功能KiRaiseException。接下來KiRaiseException會調用KiDispatchException開始異常的分發。

如下所示:

CONTEXT是一個用來儲存使用者態-核心態切換現場的資料結構,主要是切換狀態時候的各個寄存器的狀態,其結構如下:
struct _CONTEXT
   +0x000 ContextFlags     : Uint4B
  ...

  ...   

   +0x09c Edi              : Uint4B
   +0x0a0 Esi              : Uint4B
   +0x0a4 Ebx              : Uint4B
   +0x0a8 Edx              : Uint4B
   +0x0ac Ecx              : Uint4B
   +0x0b0 Eax              : Uint4B
   +0x0b4 Ebp              : Uint4B
   +0x0b8 Eip              : Uint4B
   +0x0c4 Esp              : Uint4B
   ...

   ...

 

3. 異常派發過程(Dispatch Exception)

當產生CPU異常或者軟體異常之後,最後都會調用到系統服務KiDispatchException進行異常的派發和處理。 對於CPU異常和軟體異常,其處理過程略有不同。下面分別簡要介紹

1)CPU異常派發過程:

 對於第一輪的異常,其會嘗試先讓核心調試器來處理該異常(KiDebugRoutine)。如果KiDebugRoutine返回為True,也就是核心調試器處理了該異常,那麼便停止異常分發。否則,會調用kernel mode下的RtlDispatchException (NTOSKRNL)來試圖尋找已經註冊的結構化異常處理器。

 

如果沒有相應的異常處理器,系統會嘗試進行第二次分發。如果這次KeDebugRoutine仍然返回FAlSE,表明這是一個無人處理的異常,從而調用KeBugCheckEx引發藍屏。

 其過程如下所示:

2) 軟體異常派發過程:

 當軟體異常被派發到user-mode之後,如何處理這個exception呢?實際上,在TEB中有一個非常重要的結構體,叫做_NT_TIB。在_NT_TIB中有一個_EXCEPTION_REGISTRATION_RECORD類型的欄位叫做exceptionlist, 他的值就是指向異常處理器(_exception_handler)的首地址。EXCEPTION_REGISTRATION_RECORD是一個單向鏈表。

 

那麼這個EXCEPTION_REGISTRATION_RECORD的首地址值從何而來呢?他是儲存在FS:[0]寄存器中的。也就是說,當異常發生時,取得FS:[0]中的值,即為EXCEPTION_REGISTRATION_RECORD的首地址。我們從windbg中可以得到驗證,如下:

 

代碼

0:000> !teb
TEB at 7ffdf000
    ExceptionList:        0012fd04
    StackBase:            00130000
    StackLimit:           0012e000
    SubSystemTib:         00000000
    FiberData:            00001e00
    ArbitraryUserPointer: 00000000
    Self:                 7ffdf000
    EnvironmentPointer:   00000000
    ClientId:             0000312c . 00001a50
    RpcHandle:            00000000
    Tls Storage:          00000000
    PEB Address:          7ffdb000
    LastErrorValue:       0
    LastStatusValue:      c0000135
    Count Owned Locks:    0
    HardErrorMode:        0
0:000> r fs
fs=0000003b
0:000> dd fs:[0] L4
003b:00000000  0012fd04 00130000 0012e000 00000000

 

 

在得到該異常處理鏈表之後,便開始遍曆該鏈表。在遍曆鏈表的過程中,當前節點的Exception_hanlder會判斷是否能否handle當前的異常。如不能,則返回枚舉類型_EXCEPTION_DISPOSITION的一個值 (ExceptionContinueSearch),以便讓其繼續向後遍曆該鏈表,直到找到該exception_handler,並最終返回ExceptionContinueExecution,以便停止向下遍曆的過程。其過程如所示:

 

但是,如果遍曆到最後都沒有找到handle當前exception的exception handler,那麼便會觸發unhandled exception並最終調用ntdll!RtlUnhandledExceptionFilter,對於案頭型應用程式,其就會崩潰; 而對於服務端程式,為了更好的使用者體驗,這時候比如asp.net 的runtime 就會捕捉到該exception,在用戶端可能就看到service unavailable,或者伺服器端錯誤等等。

 

代碼

_TEB (thread environment blcok即線程環境塊)定義如下:
=============
typedef struct _TEB{
   +0x000 NtTib            : _NT_TIB
   +0x01c EnvironmentPointer : Ptr32 Void
   +0x020 ClientId         : _CLIENT_ID
   +0x028 ActiveRpcHandle  : Ptr32 Void
   +0x02c ThreadLocalStoragePointer : Ptr32 Void
   +0x030 ProcessEnvironmentBlock : Ptr32 _PEB
   +0x034 LastErrorValue   : Uint4B
   ...   ...    }TEB   
_NT_TIB的結構定義如下:
===========
typedef struct _NT_TIB{
   +0x000 ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x004 StackBase        : Ptr32 Void
   +0x008 StackLimit       : Ptr32 Void
   ...   ...   +0x018 Self             : Ptr32 _NT_TIB
}NT_TIB
而ntdll!_EXCEPTION_REGISTRATION_RECORD的定義如下:
===========typedef struct _EXCEPTION_REGISTRATION_RECORD{
   +0x000 Next             : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : Ptr32     _EXCEPTION_DISPOSITION 
}EXCEPTION_REGISTRATION_RECORD ntdll!_EXCEPTION_DISPOSITION的定義如下:============
  typedef enum _EXCEPTION_DISPOSITION{  ExceptionContinueExecution = 0
   ExceptionContinueSearch = 1
   ExceptionNestedException = 2
   ExceptionCollidedUnwind = 3
}EXCEPTION_DISPOSITION

 

 附件1:
NTDLL模組中與exception處理相關的常見幾個系統服務和相關函數

 

代碼

 ntdll!RtlpUnhandledExceptionFilter 
 ntdll!RtlpDphRaiseException 
 ntdll!RtlpHeapExceptionFilter
 ntdll!RtlpDphUnexpectedExceptionFilter 
 ntdll!RtlUnhandledExceptionFilter2 
 ntdll!RtlSetUnhandledExceptionFilter 
 ntdll!RtlDispatchException 
 ntdll!RtlRaiseException 
 ntdll!RtlpExecuteHandlerForException

 ntdll!KiRaiseUserExceptionDispatcher 
 ntdll!KiUserCallbackExceptionHandler 
 ntdll!KiUserExceptionDispatcher 
 ntdll!KiUserApcExceptionHandler

  參考文檔:

=======

A Crash Course on the Depths of Win32 Structured Exception Handling

http://www.microsoft.com/msj/0197/exception/exception.aspx

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.