新聞中心

        EEPW首頁(yè) > Windows內(nèi)核調(diào)試器原理淺析(三)

        Windows內(nèi)核調(diào)試器原理淺析(三)

        ——
        作者: 時(shí)間:2007-04-18 來(lái)源: 收藏
        系統(tǒng)與交互的方法除了int 0x3外,還有DbgPrint、DbgPrompt、加載和卸載symbols,它們共同通過(guò)調(diào)用DebugService獲得服務(wù)。

        NTSTATUS DebugService(
                ULONG   ServiceClass,
                PVOID   Arg1,
                PVOID   Arg2
            )
        {
            NTSTATUS    Status;

            __asm {
                mov     eax, ServiceClass
                mov     ecx, Arg1
                mov     edx, Arg2
                int     0x2d
                int     0x3   
                mov     Status, eax
            }
            return Status;
        }

        ServiceClass可以是BEAKPOINT_PRINT(0x1)、BREAKPOINT_PROMPT(0x2)、BREAKPOINT_LOAD_SYMBOLS(0x3)、BREAKPOINT_UNLOAD_SYMBOLS(0x4)。為什么后面要跟個(gè)int 0x3,M$的說(shuō)法是為了和int 0x3共享代碼(我沒(méi)弄明白啥意思-_-),因?yàn)閕nt 0x2d的陷阱處理程序是做些處理后跳到int 0x3的陷阱處理程序中繼續(xù)處理。但事實(shí)上對(duì)這個(gè)int 0x3指令并沒(méi)有任何處理,僅僅是把Eip加1跳過(guò)它。所以這個(gè)int 0x3可以換成任何字節(jié)。
            
            int 0x2d和int 0x3生成的異常記錄結(jié)(EXCEPTION_RECORD)ExceptionRecord.ExceptionCode都是STATUS_BREAKPOINT(0x80000003),不同是int 0x2d產(chǎn)生的異常的ExceptionRecord.NumberParameters>0且ExceptionRecord.ExceptionInformation對(duì)應(yīng)相應(yīng)的ServiceClass比如BREAKPOINT_PRINT等。事實(shí)上,在內(nèi)核被掛接后,處理DbgPrint等發(fā)送字符給內(nèi)核不再是通過(guò)int 0x2d陷阱服務(wù),而是直接發(fā)包。用M$的話(huà)說(shuō),這樣更安全,因?yàn)椴挥谜{(diào)用KdEnterDebugger和KdExitDebugger。

            最后說(shuō)一下被調(diào)試系統(tǒng)和內(nèi)核調(diào)試器之間的通信。被調(diào)試系統(tǒng)和內(nèi)核調(diào)試器之間通過(guò)串口發(fā)數(shù)據(jù)包進(jìn)行通信,Com1的IO端口地址為0x3f8,Com2的IO端口地址為0x2f8。在被調(diào)試系統(tǒng)準(zhǔn)備要向內(nèi)核調(diào)試器發(fā)包之前先會(huì)調(diào)用KdEnterDebugger暫停其它處理器的運(yùn)行并獲取Com端口自旋鎖(當(dāng)然,這都是對(duì)多處理器而言的),并設(shè)置端口標(biāo)志為保存狀態(tài)。發(fā)包結(jié)束后調(diào)用KdExitDebugger恢復(fù)。每個(gè)包就象網(wǎng)絡(luò)上的數(shù)據(jù)包一樣,包含包頭和具體內(nèi)容。包頭的格式如下:

                typedef struct _KD_PACKET {
                    ULONG PacketLeader;
                   USHORT PacketType;
                    USHORT ByteCount;
                    ULONG PacketId;
                    ULONG Checksum;
                } KD_PACKET, *PKD_PACKET;
            
            PacketLeader是四個(gè)相同字節(jié)的標(biāo)識(shí)符標(biāo)識(shí)發(fā)來(lái)的包,一般的包是0x30303030,控制包是0x69696969,中斷被調(diào)試系統(tǒng)的包是0x62626262。每次讀一個(gè)字節(jié),連續(xù)讀4次來(lái)識(shí)別出包。中斷系統(tǒng)的包很特殊,包里數(shù)據(jù)只有0x62626262。包標(biāo)識(shí)符后是包的大小、類(lèi)型、包ID、檢測(cè)碼等,包頭后面就是跟具體的數(shù)據(jù)。這點(diǎn)和網(wǎng)絡(luò)上傳輸?shù)陌芟嗨啤_€有一些相似的地方比如每發(fā)一個(gè)包給調(diào)試器都會(huì)收到一個(gè)ACK答復(fù)包,以確定調(diào)試器是否收到。若收到的是一個(gè)RESEND包或者很長(zhǎng)時(shí)間沒(méi)收到回應(yīng),則會(huì)再發(fā)一次。對(duì)于向調(diào)試器發(fā)送輸出字符串、報(bào)告SYMBOL情況等的包都是一接收到ACK包就立刻返回,系統(tǒng)恢復(fù)執(zhí)行,系統(tǒng)的表現(xiàn)就是會(huì)卡那么短短一下。只有報(bào)告狀態(tài)的包才會(huì)等待內(nèi)核調(diào)試器的每個(gè)控制包并完成對(duì)應(yīng)功能,直到發(fā)來(lái)的包包含繼續(xù)執(zhí)行的命令為止。無(wú)論發(fā)包還是收包,都會(huì)在包的末尾加一個(gè)0xaa,表示結(jié)束。
            現(xiàn)在我們用幾個(gè)例子來(lái)看看調(diào)試流程。

            記得我以前問(wèn)過(guò)jiurl為什么WinDBG的單步那么慢(相對(duì)softICE),他居然說(shuō)沒(méi)覺(jué)得慢?*$&$^$^(&(&(我ft。。。現(xiàn)在可以理解為什么WinDBG的單步和從操作系統(tǒng)正常執(zhí)行中斷下來(lái)為什么那么慢了。單步慢是因?yàn)槊繂尾揭淮纬吮匾奶幚硗猓€得從串行收發(fā)包,怎么能不慢。中斷系統(tǒng)慢是因?yàn)橹挥械鹊綍r(shí)鐘中斷發(fā)生執(zhí)行到KeUpdateSystemTime后被調(diào)試系統(tǒng)才會(huì)接受來(lái)自WinDBG的中斷包。現(xiàn)在我們研究一下為什么在KiDispatchException里不能下斷點(diǎn)卻可以用單步跟蹤KiDispatchException的原因。如果在KiDispatchException中某處下了斷點(diǎn),執(zhí)行到斷點(diǎn)時(shí)系統(tǒng)發(fā)生異常又重新回到KiDispatchException處,再執(zhí)行到int 0x3,如此往復(fù)造成了死循環(huán),無(wú)法不能恢復(fù)原來(lái)被斷點(diǎn)int 0x3所修改的代碼。但對(duì)于int 0x1,因?yàn)樗囊鹗且驗(yàn)镋FLAG寄存中TF位被置位,并且每次都自動(dòng)被復(fù)位,所以系統(tǒng)可以被繼續(xù)執(zhí)行而不會(huì)死循環(huán)。現(xiàn)在我們知道了內(nèi)部機(jī)制,我們就可以調(diào)用KdXXX函數(shù)實(shí)現(xiàn)一個(gè)類(lèi)似WinDBG之類(lèi)的內(nèi)核調(diào)試器,甚至可以替換KiDebugRoutine(KdpTrap)為自己的函數(shù)來(lái)自己實(shí)現(xiàn)一個(gè)功能更強(qiáng)大的調(diào)試器,呵呵。


        評(píng)論


        相關(guān)推薦

        技術(shù)專(zhuān)區(qū)

        關(guān)閉
        主站蜘蛛池模板: 界首市| 西平县| 通河县| 嘉鱼县| 宁德市| 南川市| 抚州市| 洪湖市| 从江县| 界首市| 阿拉善左旗| 南投市| 辰溪县| 霍邱县| 北川| 泗水县| 凉城县| 武汉市| 客服| 长治县| 麻城市| 龙陵县| 怀安县| 翼城县| 鄂伦春自治旗| 大同市| 麻城市| 双峰县| 江陵县| 普安县| 合山市| 沙坪坝区| 渝中区| 崇信县| 莫力| 江川县| 汕头市| 公主岭市| 娄烦县| 尼玛县| 日照市|