首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

Win32 結構化異常處理 (SEH) 深度探秘 (下):展開機制、未處理異常與核心調度流程

     編輯:關於C++

展開機制:RtlUnwind 核心邏輯

當異常處理程序不在鏈表頭部時,系統需移除其前的所有幀,此過程稱「展開」。Visual C++ 透過 __global_unwind2 封裝 RtlUnwind (實際轉發至 NTDLL.dll) 完成。核心步驟:

  1. 從 FS:[4]、FS:[8] 取得堆疊邊界,驗證幀合法性。
  2. 建立 EXCEPTION_RECORD,ExceptionCode = STATUS_UNWIND,Flags = EXCEPTION_UNWINDING。
  3. 呼叫 RtlCaptureContext 捕獲當前上下文 (寄存器狀態)。
  4. 遍歷 EXCEPTION_REGISTRATION 鏈表,對每個幀呼叫 RtlpExecuteHandlerForUnwind 執行清理 (如呼叫解構函數),並透過 RtlpUnlinkHandler 移除幀。
  5. 若遇目標幀 (pRegistrationFrame),呼叫 NtContinue 恢復執行;若遍歷完仍未找到,拋出 STATUS_INVALID_UNWIND_TARGET。

安全檢查包含:堆疊範圍、DWORD 對齊、幀順序。任何違規觸發 EXCEPTION_NONCONTINUABLE 終止進程。

未處理異常:UnhandledExceptionFilter 全流程

當鏈表無人處理異常,BaseProcessStart 的 __except 區塊呼叫 UnhandledExceptionFilter。關鍵邏輯:

  • 讀寫資源區:EXCEPTION_ACCESS_VIOLATION 若因寫入 .rsrc 區,自動修改頁面屬性允許寫入並重試。
  • 偵測除錯器:NtQueryInformationProcess 檢查 ProcessDebugPort,若被除錯返回 EXCEPTION_CONTINUE_SEARCH 喚醒除錯器。
  • 用戶過濾器:若有 SetUnhandledExceptionFilter 設定回呼,優先執行。
  • 錯誤對話框或 JIT 除錯:預設呼叫 NtRaiseHardError 顯示「應用程式錯誤」對話框。若註冊表 AeDebug\Auto=1,直接啟動 JIT 除錯器 (CreateProcess + 事件同步)。

點選「確定」→ 返回 EXCEPTION_EXECUTE_HANDLER → ExitProcess 終止進程;點選「取消」→ 附加除錯器 → 返回 EXCEPTION_CONTINUE_SEARCH。

進入地獄:KiUserExceptionDispatcher 起始點

用戶模式異常入口為 NTDLL!KiUserExceptionDispatcher (跳過核心模式 IDT 處理)。偽代碼核心:

if (RtlDispatchException(pExcptRec, pContext)) 
    NtContinue(pContext, 0); 
else 
    NtRaiseException(pExcptRec, pContext, 0);

RtlDispatchException 遍歷鏈表,嚴格驗證堆疊完整性,呼叫 RtlpExecuteHandlerForException (首次調度) 或 RtlpExecuteHandlerForUnwind (展開)。兩者皆為 ExecuteHandler 前端,差異在 EDX 傳遞不同處理常式指標。ExecuteHandler 以 SEH 保護自身呼叫用戶回呼,若回呼中再發生異常,返回 DISPOSITION_NESTED_EXCEPTION 或 DISPOSITION_COLLIDED_UNWIND 觸發嚴重錯誤處理。

調用關係圖譜

KiUserExceptionDispatcher()
  RtlDispatchException()
    RtlpExecuteHandlerForException()
      ExecuteHandler() → __except_handler3()
        scopetable filter-expression()
        __global_unwind2()
          RtlUnwind()
            RtlpExecuteHandlerForUnwind()
              scopetable __except block()

附錄:Prolog/Epilog 與堆疊幀規範

x64 環境下,Prolog 負責保存非易失性寄存器、配置固定堆疊、建立幀指標;Epilog 則逆向恢復。展開代碼透過掃描 Epilog 模式 (add RSP, const 或 lea RSP, const[FPReg] + pop 序列 + ret/jmp) 實現可靠展開。__chkstk 輔助函數處理大於 4KB 的堆疊配置探測。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved