SEH(结构化异常处理)
文章目錄
- 內容回顧:
- 總結:
- 程序代碼
- 實現截圖
- 具體流程
內容回顧:
當用戶異常產生后,內核函數KiDispatchException并不是像處理內核異常那樣在0環直接處理,而是修正3環EIP為KiUSerExceptionDispatcher函數后就結束了。
這樣,當線程再次回到3環時,將會從KiUserExceptionDispatcher函數開始執行。
KiUserExceptionDispatcher會調用RtlDispatchException函數來查找并調用異常處理函數,查找的順序:
它是與線程有關的,存儲在當前線程的堆棧中。
3環的FS寄存器指向TEB
下圖中兩個call,第一個是VEH,第二個是SEH
然后進入后查看第一批代碼:
首先取出fs+8,和fs+4位置的參數
當前堆棧的界面和起始位置,利用這兩個值,進行如下代碼檢測:
看看堆棧是否屬于當前線程(也就是說異常處理函數必須位于當前線程堆棧)
繼續看,fs指向Teb,fs:0指向SEH:
真正開始調用異常處理的函數如下(也就是說所寫異常處理函數必須符合調用約定,不能隨便寫):
由內核發起調用的函數都一樣,都是必須符合調用約定,寫成規范形式。
總結:
程序代碼
#include<Windows.h> #include <iostream> //0環異常處理時講過這個結構體 /* typedef struct _EXCEPTION_REGISTRATION_RECORD {struct _EXCEPTION_REGISTRATION_RECORD* next;PEXCEPTION_ROUTINE Handler; }; */ struct MyException {struct MyException* prev;DWORD handle; };EXCEPTION_DISPOSITION _cdecl MyException_handler(struct _EXCEPTION_RECORD* ExceptionRecord,//ExceptionRecord存儲異常信息,什么類型,異常產生位置void* EstablishFrame,//MyException結構體地址(指向堆棧中的結構體)struct _CONTEXT* ContextRecord,//Context結構體,存儲異常發生時的各種寄存器值,堆棧位置等void* DispatcherContext ) {::MessageBoxA(NULL, "SEH異常處理函數執行了", "SEH異常", MB_OK);if (ExceptionRecord->ExceptionCode == 0xC0000094) {ContextRecord->Eip = ContextRecord->Eip + 2;// ContextRecord->Ecx=1;return ExceptionContinueExecution;}return ExceptionContinueSearch; }int main() {DWORD temp;//插入異常處理函數,必須在當前線程的堆棧中;MyException myException;//(只能在堆棧中創建,不能定義為全局變量)__asm {mov eax,fs:[0]mov temp,eaxlea ecx,myExceptionmov fs:[0],ecx}myException.prev = (MyException*)temp;myException.handle = (DWORD)&MyException_handler;//創造異常__asm{xor edx,edxxor ecx,ecxmov eax,0x10idiv ecx //EDX:EAX除以ECX}//摘掉異常處理函數__asm{mov eax,tempmov fs:[0],eax}printf("函數正常執行了"); }實現截圖
具體流程
idiv ecx //EDX:EAX除以ECX產生異常:
CPU指令檢測到異常(例:除0)------>查IDT表,執行中斷處理函數--------->CommonDispatchException
然后異常分發:KiDispatchException
主要作用就是恢復_TRAP_FRAME(也就是第一步中的EIP恢復原來執行流程)然后通過_KiServiceExit返回到3環。
在跳轉CommonDispatchException之前,還傳了兩個參數
if (ExceptionRecord->ExceptionCode == 0xC0000094) {ContextRecord->Eip = ContextRecord->Eip + 2;// ContextRecord->Ecx=1;return ExceptionContinueExecution;}記住,這里的返回并非直接回到下面這行代碼:
printf("函數正常執行了");總結
以上是生活随笔為你收集整理的SEH(结构化异常处理)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 异常分发(用户异常)
- 下一篇: 编译器扩展SEH(1)