Windows异常学习笔记(五)—— 未处理异常
Windows異常學(xué)習(xí)筆記(五)—— 未處理異常
- 要點(diǎn)回顧
- 最后一道防線
- 實(shí)驗(yàn)一:理解最后一道防線
- 實(shí)驗(yàn)二:新線程的最后一道防線
- 總結(jié)
- UnhandledExceptionFilter
- 實(shí)驗(yàn)三:理解UnhandledExceptionFilter
- 未處理異常
要點(diǎn)回顧
windows異常處理流程:
CPU檢測(cè)到異常 ↓ 查IDT表執(zhí)行中斷處理函數(shù) ↓ CommonDispatchException //存儲(chǔ)異常相關(guān)信息 ↓ KiDispatchException //異常分發(fā)處理函數(shù),查找由哪一個(gè)處理程序處理這個(gè)異常//判斷0環(huán)異常還是3環(huán)異常//若為3環(huán),修正EIP,指向KiUserExceptionDispatcher(ntdll.dll) ↓ KiUserExceptionDispatcher //通過RtlDispatchException查找異常處理函數(shù)位置,VEH/SEH ↓ RtlDispatchException //先查找VEH,若找不到,查找SEH(從FS:[0]開始遍歷) ↓ VEH ↓ SEH思考:會(huì)不會(huì)存在一種情況,SEH中也沒有程序能處理當(dāng)前異常
答案:一般來說,不存在
最后一道防線
描述:當(dāng)我們程序剛開始執(zhí)行時(shí),編譯器已經(jīng)替我們注冊(cè)了一個(gè)異常處理程序,因此叫做最后一道防線
實(shí)驗(yàn)一:理解最后一道防線
1)編譯并運(yùn)行以下代碼(在return處設(shè)置斷點(diǎn))
#include <stdio.h> #include <windows.h>int main() {int x = 1;return 0; }2)查看堆棧調(diào)用情況
可以發(fā)現(xiàn),程序并不是從main函數(shù)開始運(yùn)行的,而是從kernel32.dll的某個(gè)位置開始運(yùn)行的
3)查看kernel32中的代碼
4)查看7181704b位置調(diào)用的函數(shù)的具體代碼
↓
7C8024D6 push 7C839AC0h 7C8024DB mov eax,fs:[00000000] //讀取了FS:[0] 7C8024E1 push eax 7C8024E2 mov eax,dword ptr [esp+10h] 7C8024E6 mov dword ptr [esp+10h],ebp 7C8024EA lea ebp,[esp+10h] 7C8024EE sub esp,eax 7C8024F0 push ebx 7C8024F1 push esi 7C8024F2 push edi 7C8024F3 mov eax,dword ptr [ebp-8] 7C8024F6 mov dword ptr [ebp-18h],esp 7C8024F9 push eax 7C8024FA mov eax,dword ptr [ebp-4] 7C8024FD mov dword ptr [ebp-4],0FFFFFFFFh 7C802504 mov dword ptr [ebp-8],eax 7C802507 lea eax,[ebp-10h] 7C80250A mov fs:[00000000],eax //修改了FS:[0] 7C802510 ret5)使用IDA進(jìn)行查看(BaseProcessStart)
6)總結(jié):當(dāng)我們程序剛開始執(zhí)行時(shí),編譯器已經(jīng)替我們注冊(cè)了一個(gè)異常處理程序,因此在主線程中,找不到SEH的情況基本是不會(huì)發(fā)生的
思考:如果新起一個(gè)線程,會(huì)出現(xiàn)找不到SEH的情況嗎?
答案:不會(huì),參考實(shí)驗(yàn)二
實(shí)驗(yàn)二:新線程的最后一道防線
1)編譯并運(yùn)行以下代碼(在新線程中設(shè)置斷點(diǎn))
#include <stdio.h> #include <windows.h>DWORD WINAPI ThreadProc(LPVOID lpParam) {int x = 1;return 0; }int main() {CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);getchar();return 0; }2)當(dāng)中斷在新線程中時(shí),查看新線程堆棧調(diào)用情況
可以發(fā)現(xiàn),線程也不是從我們提供的線程函數(shù)開始運(yùn)行的,仍然是從kernel32.dll的某個(gè)位置開始運(yùn)行的
3)查看kernel32中的代碼
在地址7C80B6E3處也調(diào)用了地址7C8024D6的代碼(__SEH_prolog),注冊(cè)了異常處理函數(shù)
總結(jié)
UnhandledExceptionFilter
描述:
執(zhí)行流程:
1)查詢是否通過SetUnhandledExceptionFilter注冊(cè)處理函數(shù) 如果有就調(diào)用
2)如果沒有通過SetUnhandledExceptionFilter注冊(cè)處理函數(shù),彈出窗口,讓用戶選擇終止程序還是啟動(dòng)即時(shí)調(diào)試器
3)如果用戶沒有啟用即時(shí)調(diào)試器,那么該函數(shù)返回EXCEPTION_EXECUTE_HANDLER,此時(shí)會(huì)執(zhí)行except中的代碼
實(shí)驗(yàn)三:理解UnhandledExceptionFilter
1)編譯并運(yùn)行以下代碼
#include <stdio.h> #include <windows.h>long __stdcall callback(_EXCEPTION_POINTERS *excp) {excp->ContextRecord->Ecx = 1;return EXCEPTION_CONTINUE_EXECUTION; }int main() {SetUnhandledExceptionFilter(callback);__asm{xor edx, edxxor ecx, ecxmov eax, 0x10idiv ecx}printf("程序正常執(zhí)行\(zhòng)n");getchar();return 0; }2)執(zhí)行結(jié)果
3)雙擊exe執(zhí)行,執(zhí)行結(jié)果
4)總結(jié)
思考:遇到這種情況如何進(jìn)行調(diào)試
答案:HOOK NtQueryInformationProcess
未處理異常
執(zhí)行流程:
KiUserExceptionDispatcher ↓ RtlDispatchException //查找并執(zhí)行異常處理函數(shù)//如果返回真,調(diào)用ZwContinue再次進(jìn)入0環(huán)//但線程再次返回3環(huán)時(shí),會(huì)從修正后的位置開始執(zhí)行//如果返回假,調(diào)用ZwRaiseException進(jìn)行第二輪異常分發(fā)//(參見KiUserExceptionDispatcher代碼)總結(jié)
以上是生活随笔為你收集整理的Windows异常学习笔记(五)—— 未处理异常的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows异常学习笔记(四)—— 编
- 下一篇: Windows内存管理学习笔记(一)——