软件调试学习笔记(四)—— 异常的处理流程
軟件調試學習筆記(四)—— 異常的處理流程
- 要點回顧
- 異常的處理流程
- 實驗1:理解調試器與異常的關系
- 未處理異常:最后一道防線
- 實驗2:理解UnhandledExceptionFilter執行流程
- 實驗3:利用UnhandledExceptionFilter實現反調試
要點回顧
調試事件有多重類型、例如DLL加載、進程創建、線程創建等等。
其中最關鍵的調試事件是”異常“。
在調試過程中,不論是軟件斷點、硬件斷點還是INT 3斷點,都是通過異常來實現的。
異常的處理流程
流程圖:
實驗1:理解調試器與異常的關系
1)編譯并運行以下代碼:
#include <stdio.h> #include <windows.h>int main () {int x = 100;int y = 0;int z;_try{z = x / y; //除0異常printf("無法執行的代碼 \n");}_except(1){printf("SEH異常處理代碼 \n");}return 0; }執行結果:
2)設置調試器選項
3)使用調試器運行程序
程序停在40104E處,由于調試器沒有除0異常處理代碼,因此無法繼續向下執行。
4)手動模擬異常處理,將[ebp-0x20]的值改為1,繼續運行
程序成功向下運行。
思考:會不會存在某種異常沒人處理的情況
答案:不存在,因為有UnhandledExceptionFilter(未處理異常)
未處理異常:最后一道防線
描述:在前面異常相關章節已經學習,任何一個線程,在啟動時都會先布置最后一道防線。
__try {} __except(UnhandledExceptionFilter(GetExceptionInformation()) {//終止線程//終止進程 }UnhandledExceptionFilter執行流程:
1)通過NtQueryInformationProcess查詢當前進程是否正在被調試,如果是,返回EXCEPTION_CONTINUE_SEARCH,此時會進入第二輪分發。
2)如果沒有被調試:
實驗2:理解UnhandledExceptionFilter執行流程
1)編譯以下代碼
#include <stdio.h> #include <windows.h>int main () {int x = 100;int y = 0;int z;_try{z = x / y; //除0異常printf("無法執行的代碼 \n");}_except(0){printf("SEH異常處理代碼 \n");}getchar();return 0; }2)雙擊運行程序
結論:
1)由于當前進程并未處于調試狀態,因此不會調用UnhandledExceptionFilter。
2)由于當前程序并未使用SetUnhandledExceptionFilter注冊處理函數,因此會讓用戶選擇是否啟動調試器。
通過UnhandledExceptionFilter的這個性質,可以借此實現反調試。
實驗3:利用UnhandledExceptionFilter實現反調試
1)編譯并運行以下代碼:
#include <stdio.h> #include <windows.h>DWORD g_Test = 0;LONG NTAPI TopLevelExcepFilter(PEXCEPTION_POINTERS pExcepInfo) {printf("頂級異常處理器修復異常 \n");g_Test = 1;return EXCEPTION_CONTINUE_EXECUTION; }int main () {int r = 0;int x = 100;SetUnhandledExceptionFilter(&TopLevelExcepFilter);r = x / g_Test; //除0異常printf("正常邏輯開始執行 \n");for(int i=0; i<10; i++){Sleep(1000);printf("%d \n", i);}getchar();return 0; }編譯器運行結果:
雙擊運行結果:
由于調試器不會觸發SetUnhandledExceptionFilter設置的頂層異常,因此程序處于被調試狀態時無法回歸到正常邏輯;且調試器在處理異常時,若處理結果與程序所需不符,程序也將無法得以正常執行。
總結
以上是生活随笔為你收集整理的软件调试学习笔记(四)—— 异常的处理流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 软件调试学习笔记(三)—— 调试事件的处
- 下一篇: 软件调试学习笔记(五)—— 软件断点内存