windows異常

異常處理


image.png

異常和中斷是由CPU觸發(fā)的.
操作系統(tǒng)怎么接收到異常的?
IDT表, 操作系統(tǒng)在啟動(dòng)時(shí),就會(huì)將中斷處理的地址存入到IDT中.
當(dāng)產(chǎn)生中斷的時(shí)候,CPU(硬件)就會(huì)調(diào)用IDT中的函數(shù)(軟件).
Windows的異常處理機(jī)制, 都是由Windows操作系統(tǒng)提供.

  1. SEH
  2. VEH

SEH的原理

  1. SEH的異常處理函數(shù)是怎么被調(diào)用?
    產(chǎn)生異常后 , 操作系統(tǒng)使用fs段寄存器找到TEB, 通過(guò)TEB.ExceptionList 找到SEH鏈表的頭節(jié)點(diǎn), 通過(guò)節(jié)點(diǎn)中記錄的異常處理函數(shù)的地址調(diào)用該函數(shù).

  2. 異常過(guò)濾函數(shù)是怎么被調(diào)用的?
    由編譯器提供的異常處理函數(shù)(except_handler4)內(nèi)部所調(diào)用的,
    except_handler4這個(gè)函數(shù)被充當(dāng)為注冊(cè)SEH節(jié)點(diǎn)時(shí)的異常處理函數(shù).
    系統(tǒng)調(diào)用的是except_handler4函數(shù),except_handler4 調(diào)用我們?cè)趀xcept塊的異常過(guò)濾表達(dá)式中給出的異常過(guò)濾函數(shù).

  3. except語(yǔ)句塊怎么被執(zhí)行的?
    也是由except_handler4函數(shù)調(diào)用的.

  4. seh是怎么找到上一層的異常處理塊的.
    通過(guò)節(jié)點(diǎn)的Next找到下一個(gè)節(jié)點(diǎn), 然后找到節(jié)點(diǎn)的異常出來(lái)函數(shù).

=====================

  1. 異常是在哪里產(chǎn)生的?
    1.1 CPU外部硬件息拜。
    1.2 CPU內(nèi)部中斷(中斷指令)
  1. SEH異常處理函數(shù)是被誰(shuí)調(diào)用的?異常過(guò)濾函數(shù)呢丢氢?
    異常處理函數(shù) :保存在SEH節(jié)點(diǎn)中的蘸炸,被操作系統(tǒng)調(diào)用玫镐。是系統(tǒng)的原生SEH異常處理桨踪。
    異常過(guò)濾函數(shù) : 保存在編譯器所提供異常機(jī)制的某個(gè)結(jié)構(gòu)中(《軟件調(diào)試》),最終被exceptHandler4所調(diào)用栖博。是對(duì)編譯器在原生SEH異常處理機(jī)制的封裝阁苞。

  2. SEH節(jié)點(diǎn)保存在內(nèi)存中的什么位置?
    保存在棧中, 一般和函數(shù)是相關(guān)腰埂, 一般在進(jìn)入到函數(shù)的時(shí)候飒焦,SEH的節(jié)點(diǎn)被安裝在棧中,在離開(kāi)函數(shù)之后就會(huì)刪除節(jié)點(diǎn)。

  1. 從哪可以找到SEH的頭節(jié)點(diǎn)?
    TEB.TIB.ExceptionList,也就是FS:[0]
  1. 異常是怎么從CPU轉(zhuǎn)發(fā)到操作系統(tǒng)中
    1.1 CPU的處理:
    1.1.1 當(dāng)發(fā)生異常的時(shí)候牺荠,CPU根據(jù)異常號(hào)調(diào)用IDT表中對(duì)應(yīng)的異常處理程序翁巍。
    1.2 操作系統(tǒng)的處理:
    1.2.1 將各種異常處理函數(shù)填充到IDT
    1.2.2 等待IDT的異常處理函數(shù)被調(diào)用
    1.2.2.1 KiTrap03 (IDT中3號(hào)處理函數(shù)),相當(dāng)于異常的源頭休雌。
    base\ntos\ke\i386\trap.asm
    1.2.2.2 函數(shù)的功能:開(kāi)辟椩詈空間保存了產(chǎn)生異常時(shí)的線程上下文。通過(guò)寄存器傳參杈曲,調(diào)用CommonDispatchException函數(shù)驰凛。
    主要傳遞了:通過(guò)寄存器傳遞的有:異常地址,異常代碼担扑,異常附加參數(shù)恰响。通過(guò)棧傳遞有:線程的上下文。
    1.2.3 CommonDispatchException
    1.2.3.1 函數(shù)的功能:
    1.2.3.1.1 開(kāi)辟一個(gè)椨肯祝空間將異常記錄信息保存到棧中胚宦。
    1.2.3.1.2 獲取異常發(fā)生的模式(用戶層/內(nèi)核層)
    1.2.3.1.3 KiDispatchException
    參數(shù)1: 異常記錄結(jié)構(gòu)體的地址
    參數(shù)2: NULL
    參數(shù)3:異常記錄幀
    參數(shù)4: 異常發(fā)生的模式
    參數(shù)5:是否是第一次處理異常(通過(guò)KiTrapXX系列函數(shù)處理的異常都是第一次)
    1.2.4 KiDispatchException
    base\ntos\ke\i386\exceptn.c
    1.2.4.1 功能:
    1.2.4.1.1 內(nèi)核模式的處理:
    1.2.4.1.1.1 將異常交給內(nèi)核調(diào)試器處理
    1.2.4.1.1.2 內(nèi)核調(diào)試器處理不了才交給異常處理機(jī)制處理
    1.2.4.1.1.3 異常處理機(jī)制也處理不了,則進(jìn)入到第二次異常分發(fā):
    再將異常交給調(diào)試器處理
    1.2.4.1.1.4 還處理不了燕垃,就KeBugCheckEx
    1.2.4.2 用戶模式異常的處理
    1.2.4.2.1 通過(guò)發(fā)送消息枢劝,將調(diào)試記錄發(fā)送到用戶層的調(diào)試器,并等待調(diào)試器的處理結(jié)果利术。
    1.2.4.2.2 如果調(diào)試器處理不了呈野, 則輪到異常處理機(jī)制處理。
    1.2.4.2.2.1 將內(nèi)核棧的數(shù)據(jù)拷貝到用戶棧印叁,并將esp指向拷貝后數(shù)據(jù)的首地址
    1.2.4.2.2.2 將eip設(shè)置到ntdll!KiUserExceptionDispatcher函數(shù)中被冒。這樣當(dāng)執(zhí)行流從內(nèi)核回到用戶層的時(shí)候, esp指向了EXCEPTION_POINTERS的變量的地址轮蜕, eip指向了用戶層的異常分發(fā)函數(shù)的地址昨悼。

1.2.5 用戶層的異常分發(fā)(用戶層的SHE,VEH的調(diào)用過(guò)程):
1.2.5.1 遍歷VEH跃洛,并調(diào)用異常處理函數(shù)
1.2.5.2 遍歷SEH率触,并調(diào)用異常處理函數(shù)

  1. 用戶異常處理程序怎么接收到的異常
  2. 分析操作系統(tǒng)處理異常的源碼
    3.1 系統(tǒng)異常處理的步驟
    3.2 系統(tǒng)對(duì)調(diào)試機(jī)制的支持
    3.2.1 反調(diào)試
  3. 反調(diào)試和反反調(diào)試

=====================

// 01_try_finally.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。
//

#include "stdafx.h"
#include <windows.h>



int _tmain(int argc, _TCHAR* argv[])
{
    __try{
        printf("try塊\n");
        //return 0;
        *(int*)0 = 0;
        __leave; // 以正常方式離開(kāi)try的關(guān)鍵字
    }
    __finally{
        printf("finally塊\n");
    }
    printf("main\n");
    return 0;
}

====================

// 02_try_except.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)汇竭。
//

#include "stdafx.h"
#include <windows.h>

int* g_pNum = NULL;


void fun()
{
    __try{
        *(int*)0 = 0;
    }
    __except (EXCEPTION_CONTINUE_SEARCH){

    }
}

// 異常過(guò)濾函數(shù), 用于處理程序中出現(xiàn)的異常.
int seh(EXCEPTION_POINTERS* pExce)
{
    
    printf("在%08X處產(chǎn)生了%08X異常\n",
        pExce->ExceptionRecord->ExceptionAddress,
        pExce->ExceptionRecord->ExceptionCode);
    printf("EAX:%08X ECX:%08X\n",
        pExce->ContextRecord->Eax,
        pExce->ContextRecord->Ecx);

    pExce->ContextRecord->Eax = (DWORD)new int;
    return EXCEPTION_CONTINUE_EXECUTION;
}


int _tmain(int argc, _TCHAR* argv[])
{
    //執(zhí)行處理程序(except塊)
    EXCEPTION_EXECUTE_HANDLER;

    //繼續(xù)搜索
    // 將異常傳遞到上一層的try和except,將異常交給它執(zhí)行
    EXCEPTION_CONTINUE_SEARCH;
    
    //繼續(xù)執(zhí)行
    // 繼續(xù)執(zhí)行產(chǎn)生異常的那條指令
    EXCEPTION_CONTINUE_EXECUTION;

    __try{
        fun();
        //*(int*)0 = 0;
        *g_pNum = 10;
        printf("try塊\n");
    }
    __except ( seh(GetExceptionInformation())){
        printf("finally塊\n");
    }


    printf("main()\n");
    __try{
        *(int*)0 = 0;
        printf("try塊\n");
    }
    __except (EXCEPTION_CONTINUE_EXECUTION){
        printf("finally塊\n");
    }

    return 0;
}

=============================

// 03_veh.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)葱蝗。
//

#include "stdafx.h"
#include <windows.h>


LONG WINAPI veh(EXCEPTION_POINTERS* pExce)
{
    printf("veh\n");
    // 繼續(xù)執(zhí)行, 說(shuō)明異常已被處理,產(chǎn)生異常的指令將會(huì)
    // 被繼續(xù)執(zhí)行
    EXCEPTION_CONTINUE_EXECUTION;
    // 讓下一個(gè)veh節(jié)點(diǎn)處理異常.
    return EXCEPTION_CONTINUE_SEARCH;
}

LONG WINAPI seh(EXCEPTION_POINTERS* pExce){
    printf("seh\n");
    // 讓下一個(gè)veh節(jié)點(diǎn)處理異常.
    return EXCEPTION_CONTINUE_SEARCH;
}

int _tmain(int argc, _TCHAR* argv[])
{
    //1. 將異常處理函數(shù)注冊(cè)到系統(tǒng)
    AddVectoredExceptionHandler(TRUE, veh);
    __try{

        *(int*)0 = 0;
    }
    __except (seh(GetExceptionInformation())){

    }

    return 0;
}

============================

// 04_異常 處理的優(yōu)先級(jí).cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。
//

#include "stdafx.h"
#include <windows.h>

LONG WINAPI vch(EXCEPTION_POINTERS* pExcept){
    printf("vch\n");
    return EXCEPTION_CONTINUE_SEARCH;
}


LONG WINAPI veh(EXCEPTION_POINTERS* pExcept){
    printf("veh\n");
    return EXCEPTION_CONTINUE_SEARCH;
}

LONG WINAPI seh(EXCEPTION_POINTERS* pExcept){
    printf("seh\n");
    return EXCEPTION_CONTINUE_SEARCH;
}


LONG WINAPI ueh(EXCEPTION_POINTERS* pExcept){
    printf("ueh\n");
    return EXCEPTION_CONTINUE_SEARCH;
}

int _tmain(int argc, _TCHAR* argv[])
{
    AddVectoredContinueHandler(TRUE, vch);//vch
    AddVectoredExceptionHandler(TRUE, veh);//veh
    // 在64位系統(tǒng)下, 當(dāng)程序被調(diào)試時(shí),UEH不會(huì)被調(diào)用
    // 不被調(diào)試才會(huì)被調(diào)用.
    // 在32位系統(tǒng)下,被調(diào)試時(shí)也會(huì)被調(diào)用.
    SetUnhandledExceptionFilter(ueh);
    __try{
        *(int*)0 = 0;
    }
    __except (seh(GetExceptionInformation())){

    }
    return 0;
}

======================

// 05_手工安裝SEH節(jié)點(diǎn).cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)细燎。
//

#include "stdafx.h"
#include <windows.h>

EXCEPTION_DISPOSITION NTAPI seh(struct _EXCEPTION_RECORD *ExceptionRecord,PVOID EstablisherFrame,struct _CONTEXT *ContextRecord,PVOID DispatcherContext)
{
    printf("seh\n");
    // 繼續(xù)執(zhí)行
    return ExceptionContinueExecution;
}

int _tmain(int argc, _TCHAR* argv[])
{
//  EXCEPTION_REGISTRATION_RECORD node;
    /*
      * 產(chǎn)生異常后 , 操作系統(tǒng)使用fs段寄存器找到TEB, 
      * 通過(guò)TEB.ExceptionList 找到SEH鏈表的頭節(jié)點(diǎn), 
      * 通過(guò)節(jié)點(diǎn)中記錄的異常處理函數(shù)的地址調(diào)用該函數(shù).
    */
//  node.Handler = seh;
//  node.Next = NULL;

    _asm
    {
        push seh; // 將SEH異常處理函數(shù)的地址入棧
        push fs:[0];//將SEH頭節(jié)點(diǎn)的地址入棧
        ;// esp + 0 -- > [fs:0]; node.Next;
        ;// esp + 4 -- > [seh]; node.handler;
        mov fs:[0], esp;// fs:[0] = &node;
    }


    *(int*)0 = 0;


    // 平衡椓铰空間
    // 還原FS:[0]原始的頭節(jié)點(diǎn)
    _asm{
        pop fs : [0]; // 將棧頂?shù)臄?shù)據(jù)(原異常頭節(jié)點(diǎn)的地址)恢復(fù)到FS:[0],然后再平衡4個(gè)字節(jié)的棧
        add esp, 4; // 平衡剩下的4字節(jié)的棧.
    }
    return 0;
}

=========================

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市玻驻,隨后出現(xiàn)的幾起案子悼凑,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件户辫,死亡現(xiàn)場(chǎng)離奇詭異渐夸,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)渔欢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門墓塌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人膘茎,你說(shuō)我怎么就攤上這事桃纯。” “怎么了披坏?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵态坦,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我棒拂,道長(zhǎng)伞梯,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任帚屉,我火速辦了婚禮谜诫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘攻旦。我一直安慰自己喻旷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布牢屋。 她就那樣靜靜地躺著且预,像睡著了一般。 火紅的嫁衣襯著肌膚如雪烙无。 梳的紋絲不亂的頭發(fā)上锋谐,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音截酷,去河邊找鬼涮拗。 笑死,一個(gè)胖子當(dāng)著我的面吹牛迂苛,可吹牛的內(nèi)容都是我干的三热。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼三幻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼就漾!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起赌髓,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后锁蠕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體夷野,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年荣倾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了悯搔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡舌仍,死狀恐怖妒貌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情铸豁,我是刑警寧澤灌曙,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站节芥,受9級(jí)特大地震影響在刺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜头镊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一蚣驼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧相艇,春花似錦颖杏、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至靡馁,卻和暖如春欲鹏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背臭墨。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工赔嚎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胧弛。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓尤误,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親结缚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子损晤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容