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;
}
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyY4UTZ0IDNlJ2M1cTL2UjN50iZ4ADNtkTZ0MTLlJGZjFmZlJWPklWL49jZpdmL5hXaw9CXt92YuEGduFWblpnLn1Wavw1LcpDc0RHaiojIsJye.gif)
轉載于:https://www.cnblogs.com/fanzi2009/archive/2009/03/19/1416363.html