天天看點

關于SEH的一些總結

1.以前的一個誤解

在ring3時候,fs段指向的是TEB。

以前一直有個誤解,fs:[0]和fs:[1]記錄着EXCEPTION_REGISTRATION

其實不然,而是fs:[0]記錄着EXCEPTION_REGISTRATION的指針。

2.資料結構,它可以形成一個連結清單,這個連結清單的首位址記錄在fs:[0],其中handle是異常處理函數。

_EXCEPTION_REGISTRATION struc

     prev    dd      ?

     handler dd      ?

 _EXCEPTION_REGISTRATION ends

3.異常處理函數會執行兩遍。

第一次用來系統通過上述連結清單,找到确切這個異常的處理函數。

第二次是unwind,用來做一些回收相關的操作。例如,C++的destructor,執行_finally塊。

執行完後,系統将恢複到當初出現錯誤的狀态,删除沒用的EXCEPTION_REGISTRATION鍊。

4._try _except嵌套塊隻使用一個EXCEPTION_REGISTRATION,而沒有使用多個

5.vc的編譯器将EXCEPTION_REGISTRATION資料結構擴充,使得可以支援_try _excetp

 ;struct _EXCEPTION_REGISTRATION{

 ;     struct _EXCEPTION_REGISTRATION *prev;

 ;     void (*handler)(PEXCEPTION_RECORD,

 ;                     PEXCEPTION_REGISTRATION,

 ;                     PCONTEXT,

 ;                     PEXCEPTION_RECORD);

 ;     struct scopetable_entry *scopetable;

 ;     int trylevel;

 ;     int _ebp;

 ;     PEXCEPTION_POINTERS xpointers;

 ;};

6.

有_try塊的函數的堆棧情況

 EBP-00 _ebp

 EBP-04 trylevel

 EBP-08 scopetable pointer

 EBP-0C handler function address

 EBP-10 previous EXCEPTION_REGISTRATION

 EBP-14 GetExceptionPointers

 EBP-18 Standard ESP in frame

這裡解釋一下Standard ESP in frame的作用。

儲存舊的EBP後,然後把ESP=>EBP,這樣就可以用EBP通路堆棧中的局部變量。

函數一般用ADD ESP ,(負數)來開辟堆棧中的局部變量。

這時候如果再push 或者pop則是在stack的上方。這個時候的ESP需要被記住,如果出現異常的時候需要恢複這個值。它被記在EBP-18的位置。

例如:

#include <stdio.h>

#include <windows.h>

int main(int argc, char *argv[])

{

    _try

    {

        *((PUCHAR)NULL)=0;

    }_except(1)//這裡需要恢複esp的數值

    {

    }

    return 0;

}

關于SEH的一些總結

轉載于:https://www.cnblogs.com/fanzi2009/archive/2009/03/19/1416363.html