日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

SEH(结构化异常处理)

發(fā)布時(shí)間:2025/3/21 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SEH(结构化异常处理) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 內(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ù),查找的順序:

  • 先查全局鏈表:VEH
  • 再查句柄鏈表:SEH

  • 它是與線程有關(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é):

  • fs:[0]指向的是SEH鏈表的第一個(gè)成員
  • SEH的異常處理函數(shù)必須在當(dāng)前線程的堆棧中
  • 只有在VEH中的處理函數(shù)不存在或者不處理才會(huì)到SEH鏈表中查找
  • 程序代碼

    #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

  • 把Trap_frame(當(dāng)前線程3環(huán)進(jìn)入0環(huán)時(shí),那些寄存區(qū)環(huán)境,也就是eip運(yùn)行地方那些值)備份到context里(為返回3環(huán)做準(zhǔn)備)(也就是把3環(huán)代碼eip保存,不能破壞原來的執(zhí)行流程
  • 第二步:判斷先前模式,0是內(nèi)核調(diào)用,1是用戶調(diào)用,用戶層異常呢,緊接著就是跳轉(zhuǎn)
  • 把KeUserExceptionDispatcher里面的值覆蓋到Eip
  • 回到三環(huán)的KiUserExceptionDispatcher會(huì)調(diào)用RtlDispatchException函數(shù)來查找并調(diào)用異常處理函數(shù),查找的順序:先查全局鏈表:VEH; 再查句柄鏈表:SEH
  • 找到解決之后呢,調(diào)用ZwContine再次進(jìn)入0環(huán),
    主要作用就是恢復(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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。