官术网_书友最值得收藏!

3.10.1 結構化異常處理

SEH通常在編譯器級別通過try...catch語句實現,如例3.16所示。

例3.16 try...catch語句


1  try {
2    // 
在這里做一些事
3  }
4  catch(...){
5    // 
在這里處理異常
6  }
7  __finally {
8    // 
在這里處理清理
9  }

try塊中引發的任何異常都將被匹配的catch塊處理。如果catch塊無法處理該異常,那么它將被傳回之前的范圍塊。__finally關鍵字是微軟對C/C++語言的擴展,用于表示一個代碼塊,該代碼塊被調用來清理由try塊說明的任何東西。不管try塊如何退出,該關鍵字都被調用。

對結構化異常處理而言,Windows為每線程的異常處理程序提供了特殊支持。編譯器產生的代碼將一個指向EXCEPTION_REGISTRATION結構的指針的地址,寫入fs段寄存器所引用的地址。這個結構在Visual C++運行庫源文件的EXSUPP.INC中使用匯編語言struc定義,它包含2個數據元素,如例3.17所示。

例3.17 EXCEPTION_REGISTRATION struc的定義


1 _EXCEPTION_REGISTRATION struc
2 prev dd ?
3 handler dd ?
4 _EXCEPTION_REGISTRATION ends

在這個結構中,prev是一個指向異常處理程序鏈中前一個EXCEPTION_HANDLER結構的指針,handler則是一個指向實際異常處理程序函數的指針。

Windows針對異常處理程序施加了幾條強制性的措施,以確保異常處理程序鏈和系統的完整性:

1.EXCEPTION_REGISTRATION結構必須在棧上分配。

2.prev EXCEPTION_REGISTRATION結構必須處于棧中較高的地址。

3.EXCEPTION_REGISTRATION結構必須按雙字邊界對齊。

4.如果可執行映像頭部列出了SAFE SEH處理程序地址 [1],那么處理器地址必須被列為SAFE SEH處理程序。反之,任何結構化異常處理程序都可以被調用。

編譯器在函數開頭(function prolog)初始化棧幀。例3.18展示了Visual C++產生的典型的函數開頭。這段代碼建立了如表3.1所示的棧幀結構。編譯器在棧中為局部變量保存空間。因為異常處理程序地址緊跟在局部變量之后,因此,如果一個棧變量發生緩沖區溢出,那么異常處理程序地址就可以被覆寫為任意值。

例3.18 棧幀初始化


1 push ebp
2 mov ebp, esp
3 and esp, 0FFFFFFF8h
4 push 0FFFFFFFFh
5 push ptr [Exception_Handler]
6 mov eax, dword ptr fs:[00000000h]
7 push eax
8 mov dword ptr fs:[0], esp

表3.1 具有異常處理程序的棧幀

除了覆寫單獨的函數指針外,還可以替換線程環境塊(Thread Environment Block,TEB)中的指針,已注冊的異常處理程序的列表就是由該指針所引用的。攻擊者需要仿造一個列表入口作為攻擊代碼的一部分,然后利用任意內存寫技術修改第一個異常處理程序域。盡管最新版本的Windows已經加入了列表入口有效性校驗功能,然而Litchfield示范了在很多情況下都可以成功地進行利用攻擊[Litchfield 2003a]。

[1] Microsoft Visual Studio.NET編譯器支持創建帶有SAFE SEH的代碼,但這種檢查只在WindowsXP SP2中強制執行。
主站蜘蛛池模板: 河北省| 丰原市| 九龙城区| 汾阳市| 凉山| 巴中市| 济阳县| 绥棱县| 乐山市| 合川市| 彭泽县| 大港区| 永寿县| 西乡县| 原阳县| 离岛区| 桐城市| 泸定县| 塔河县| 茶陵县| 英吉沙县| 济源市| 盘山县| 霍州市| 新宁县| 高淳县| 纳雍县| 盖州市| 五大连池市| 应用必备| 昆山市| 宿迁市| 朝阳市| 收藏| 海门市| 阳高县| 嘉定区| 杨浦区| 谷城县| 鹿邑县| 清镇市|