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