- C和C++安全編碼(原書第2版)
- (美)Robert C.Seacord
- 888字
- 2020-10-30 17:56:50
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]。
- Mastering JavaScript Functional Programming
- Android Jetpack開發:原理解析與應用實戰
- WebAssembly實戰
- 編寫整潔的Python代碼(第2版)
- FreeSWITCH 1.6 Cookbook
- Android開發案例教程與項目實戰(在線實驗+在線自測)
- RabbitMQ Cookbook
- Machine Learning in Java
- Android開發三劍客:UML、模式與測試
- 打開Go語言之門:入門、實戰與進階
- GameMaker Essentials
- SQL Server 2008 R2數據庫技術及應用(第3版)
- Photoshop CC移動UI設計案例教程(全彩慕課版·第2版)
- 從零開始學Selenium自動化測試:基于Python:視頻教學版
- Java EE實用教程