• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 319, comments - 22, trackbacks - 0, articles - 11
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
            導讀:


            版權(quán)聲明:轉(zhuǎn)載時請以超鏈接形式標明文章原始出處和作者信息及本聲明
            http://chenshine.blogbus.com/logs/4414354.html


            剛 進入計算機相關(guān)專業(yè)領(lǐng)域時,大家最先用過的調(diào)試器大多會是Turbo C。它雖然古老但用過的人卻很多,然而嚴格的講,Turbo C是一個集成開發(fā)環(huán)境,雖然擁有獨立的編譯器,鏈接器,卻沒有獨立的調(diào)試器,這和Visual Studio一樣。如果你做過DOS,早期Windows下的匯編,也許你會對Debug,CodeView等調(diào)試工具熟悉,但這些工具太老 了,Debug甚至不能調(diào)試32位程序,介紹它們與這篇文章的主旨不符,如果你對它們感興趣,可以去查閱相關(guān)資料。本文主要是介紹與調(diào)試技術(shù)相關(guān)的理論知 識以及常用調(diào)試器的使用,Windows設(shè)備驅(qū)動程序與內(nèi)核的調(diào)試等。具體的講解方法是理論結(jié)合實踐,并且是站在給新手看的角度,循序漸進的,用一個一個 調(diào)試會話向你展示每個重要命令的使用。



            目錄

            1。調(diào)試器
            2。調(diào)試信息
            3。用戶模式程序的調(diào)試
            4。驅(qū)動程序與內(nèi)核的調(diào)試

            1 調(diào)試器

            1。1 概覽

            調(diào) 試器,與編譯器,鏈接器一樣,都屬于基礎(chǔ)軟件,它們在制作上都有很大的難度,但盡管如此,現(xiàn)實中還是有不少專業(yè)級的調(diào)試器,微軟官方的就有 cdb,ntsd,WinDbg,kd等,還有SoftIce,OllyDbg等來自于其它公司的優(yōu)秀調(diào)試器。本文不可能對這幾個調(diào)試器一一介紹,一個是 限于篇幅,另一個是上面列舉的這幾個調(diào)試器無論是哪一個都需要你花很長的時間去完全掌握(在市面上有很多書籍甚至專門講解某一個調(diào)試器的使用,比如 SoftIce)。雖然本文不會講解SoftIce的詳細使用,但我還是要對它進行簡短的介紹,因為它太有名了,甚至比Windows出生的早。

            1。2 SoftIce

            SoftIce 是NuMega公司生產(chǎn)的調(diào)試器,產(chǎn)于80年代后期,直到今天為止,這個軟件已經(jīng)變革過好幾次了,因為處理器的體系結(jié)構(gòu)在更新,操作系統(tǒng)也在更新,所以調(diào) 試器也必須相應的更新。它之所以有名,那是與歷史有關(guān)的,在Intel推出386 Cpu的時候,NuMega立即讓SoftIce支持了386 Cpu的新特性,同時吸引了大量黑客的使用,使它在黑客界產(chǎn)生了一定的地位(功能強大的調(diào)試器可以對軟件的保護機制進行破解,如突破序列號之類的)。在 Windows推出時,所有的調(diào)試器都不適用這種新的系統(tǒng)軟件體系結(jié)構(gòu)了,唯一能用的就是微軟自己生產(chǎn)的調(diào)試器,卻很拙劣,這時NuMega又對 SoftIce進行了變革,不僅讓它可以在新的系統(tǒng)上很好的工作,甚至還可以調(diào)試Windows的內(nèi)核,這是當時是不敢想象的。也正是因為它很好的性能, 卓越的功能,它成為了黑客們的寵兒,并且培養(yǎng)了幾代的黑客。讀完本文后,你自己應該有能力去探索它,或許你也可以在這幾款調(diào)試器里找到適合自己的。

            1。3 微軟的調(diào)試工具

            本 文主要介紹的是微軟官方的調(diào)試器,并且MS微軟也最積極,調(diào)試工具包一直在更新中。在微軟的調(diào)試器里,大家可能最為熟悉Visual Studio Debugger,就是你在Visual C++里使用的那個,它并不是一個單獨可運行的程序,而是內(nèi)嵌在Visual Studio中的,它的功能相對于上面幾個調(diào)試器來說要弱很多,這里并不會對它進行介紹,如果你想全方面的了解它的話,你可以去參考MSDN,那里專門有 幾章講解它,是一份很好的文檔化的資源(而且還是中文的)。其它的微軟調(diào)試工具cdb,ntsd,WinDbg,kd都在微軟的一個安裝包里,被稱作Debugging Tools for Windows(10 多M的大小,請通過這個鏈接下載并安裝,一會兒就要用到)。這些調(diào)試器在下文中會分別介紹,這里先做一個簡單的區(qū)別,cdb與ntsd幾乎是一樣的程序, 唯一的不同是cdb是一個CUI程序,即Console程序,而ntsd是GUI程序,但ntsd并沒有產(chǎn)生窗口,而是又分配了一個Console窗口, 這個Console窗口就相當于是cdb。它與真正的cdb執(zhí)行完全一樣的功能(官方如是說,然而實際上還有一些個不同)。在命令行中啟動它們時下面兩句 命令有一樣的效果(C:/Progs/Debug是調(diào)試工具包的安裝位置):

            C:/Progs/Debug/>start cdb
            C:/Progs/Debug/>ntsd

            cdb 與ntsd是用來調(diào)試用戶模式應用程序的。kd調(diào)試器也是一個命令行程序,不過正如其名kernel debugger所描述的一樣,它是內(nèi)核調(diào)試器的,是驅(qū)動程序開發(fā)者,系統(tǒng)Hacker的最愛。WinDbg是一個稱職的GUI程序,它有菜單,有工具 欄,還有多個子窗口,可以分別顯示源代碼,調(diào)用棧,命令等,它既可以調(diào)試ring 0程序,也可以調(diào)試ring 3程序,其實它只是一個殼而已,當調(diào)試ring 3級程序時它實際上是用cdb/ntsd,而當調(diào)試ring 0級程序時是用kd。WinDbg的到來吸引了很多的人使用,你也將會發(fā)現(xiàn),它確實是一款優(yōu)秀的調(diào)試器。

            2 調(diào)試信息

            調(diào)試器之所以能夠工作,完全是依賴于編譯和鏈接程序時所生成的調(diào)試信息,當然調(diào)試信息是具有一定的格式的。

            2。1 格式

            微 軟的調(diào)試信息格式經(jīng)過了幾代變化,最終形成了Program DataBase這種格式,并且這種格式還在進行版本上的更新,VS.Net所用的新的Program DataBase版本與Visual C++ 6.0所用的老的版本是不兼容的,并且你也可以用編譯器和鏈接器明確指定你想要生成的調(diào)試信息格式,這一點下文中有闡述。

            2。2 內(nèi)容

            關(guān) 于調(diào)試信息我們還必須知道兩件事,一是調(diào)試信息包括哪些內(nèi)容,二是調(diào)試信息儲存在什么地方。其實調(diào)試信息所應該包括的內(nèi)容正是調(diào)試信息格式變化的原因,從 COFF格式,到CodeView格式,到Program DataBase格式,調(diào)試信息變得越來越豐富了,并且是只多不少。Program DataBase格式的調(diào)試信息中主要包括了所有全局函數(shù),static 函數(shù),全局變量,static變量,局部變量,函數(shù)形參的名字及其位置,源代碼與可執(zhí)行文件中指令的映射信息,每個函數(shù)與變量的類型,以及FPO信息,編 輯和繼續(xù)信息。編輯與繼續(xù)信息主要用于在Visual Studio中調(diào)試時,可以在調(diào)試的同時編輯源代碼,并在接下來的調(diào)試中得到體現(xiàn)。Program DataBase格式的調(diào)試信息包含了這么多的內(nèi)容,所以用這種調(diào)試信息來調(diào)試程序時,你將能夠得到更多,更準確,更深入的反饋。

            2。3 存儲位置

            調(diào) 試信息的存儲位置是與其格式相關(guān)的,Program DataBase格式的調(diào)試信息存儲在一個單獨的文件里,擴展名為pdb。像以前的CodeView格式的調(diào)試信息即可存儲在單獨的文件里,又可存儲在編 譯時所生成的obj文件中。知道了這些知識后,我們就可以正確地生成調(diào)試信息了。在后面的內(nèi)核調(diào)試中我們還要繼續(xù)談到它。

            3 用戶模式程序的調(diào)試

            根 據(jù)上面的講述,我們可以用cdb或WinDbg來進行ring 3程序的調(diào)試,這里先講解cdb。cdb允許你啟動某個被調(diào)試程序(以下稱debugee)的一個新的實例來進行調(diào)試,即先創(chuàng)建cdb,然后cdb再把你 所指定的程序創(chuàng)建為一個新進程進而對其調(diào)試,也允許debugee在已經(jīng)運行的情況下被cdb attach上。cdb還可以對Crash Dump(程序崩潰時的內(nèi)存Copy,下文將會說明)進行調(diào)試,只需要加上-z選項,后面再加上Crash Dump的文件名即可。這幾種調(diào)試方式下面將會一一講述。

            3。1 調(diào)試前的準備

            第 2節(jié)中對調(diào)試信息進行了理論上的說明,接下來我們來看看在實際中應該如何操作。首先我們的程序必須要經(jīng)過編譯,鏈接,并且在編譯和鏈接時還要指定一些選項 以正確地生成調(diào)試信息。這里所使用的編譯器是cl.exe,鏈接器是link.exe,都是微軟官方的,Visual Studio就是用的這兩個(CTRL+F5就是順序調(diào)用cl和link的快捷鍵),如果你安裝了Visual C++或Visual Studio,就會有它們,另外一種選擇是安裝SDK,也能夠得到它們。本文所用的cl.exe和link.exe是Visual C++ 6.0的版本。若要生成調(diào)試信息,編譯時我們需要加上的選項應是/Zi,而鏈接時則要加上/debug。在下面的調(diào)試中,我們將用C語言來寫程序,所以你 有必要知道用C語言寫出來的程序與用匯編寫出來的有什么不同。首先,每個程序都有一個入口函數(shù),它的地址需要在鏈接時指定,并被鏈接器放到最終可執(zhí)行文件 的頭部,通常用匯編語言寫的程序,有選擇的,你可以在源代碼中指定入口函數(shù),而用C語言寫的程序則需要在鏈接的時候來指定入口函數(shù),說到這你可能不以為 然,“C語言寫的程序的入口函數(shù)不就是main嗎?“。實際上,控制臺C程序的入口函數(shù)默認情況下是C運行時的啟動函數(shù):mainCRTStartup。 然后由這個函數(shù)調(diào)用你寫的main函數(shù),所以可執(zhí)行文件的頭部存放的入口地址是mainCRTStartup的地址,而不是你寫的main函數(shù)地址。 mainCRTStartup主要做了一些為了正確執(zhí)行C/C++程序的初始化工作。它已經(jīng)由微軟寫好了,由鏈接器自動鏈接到可執(zhí)行文件中。如果你在程序 中不使用C語言的庫以及一些ANSI規(guī)定的全局變量,只是單純地使用C語言這種語法,那么你也可以不鏈接mainCRTStartup,直接指定你自己寫 的某個函數(shù)為入口函數(shù),這也是我們在下文中所使用的方法,具體的做法是在鏈接時加入如下選項:/subsystem:console /entry:你的入口函數(shù)名稱。這個入口函數(shù)應該是不帶參數(shù)的。現(xiàn)在我們來總結(jié)一下上面所講的內(nèi)容,假定你的源程序名為exam.c,你想指定的入口函 數(shù)為main,那么應該如下生成可執(zhí)行程序:

            C:/Pro/>cl /Zi exam.c /link /debug /subsystem:console /entry:main
            另 外,就算你不鏈接mainCRTStartup(它會調(diào)用很多的Win32 API),也不在源程序中調(diào)用任何的系統(tǒng)函數(shù)。那么系統(tǒng)還是會把一些動態(tài)鏈接庫,如kernel32.dll,Ntdll.dll等動態(tài)鏈接到你的程序所 對應的進程里,即把它們映射到你的程序?qū)倪M程地址空間里。這是因為在你所指定的入口函數(shù)運行之前,還會有一系列的 Kernel32.dll,Ntdll.dll中的函數(shù)要運行。即在用戶空間中你指定的入口函數(shù),例如上面的main,根本不是第一個運行的函數(shù)。那么那 些函數(shù)是做什么的呢,通過大量的反匯編和調(diào)試能夠推斷出它們是做一些進程,線程在用戶空間的初始化,設(shè)置一些異常楨等。在下面的調(diào)試中我們將會用一些手段 來研究它們。這些函數(shù)是操作系統(tǒng)的一部分,因些我們必須從官方網(wǎng)站下載它的符號文件,當然不下載也行,那么你將面臨的會是一大堆的警告。說到下載,沒有比 這更簡單的了,你不需要預先的下載,只需要添加一個環(huán)境變量_NT_SYMBOL_PATH即可,而真正的下載工作由調(diào)試器來做,這個環(huán)境變量的值與已存 在的PATH環(huán)境變量類似,是由分號分隔的一系列的路徑組成。這些路徑應該包括你的調(diào)試信息文件(pdb文件)所在地,如前面的C:/Pro/。如果要下 載系統(tǒng)文件如Kernel32.dll,Ntdll.dll的pdb文件,你僅僅需要再加一個這樣的路徑:SRV*D:/Symbols*http: //msdl.microsoft.com/download/symbols,其中D:/Symbols是可更換的,你可以換成任何一個其它的路徑,這 個D:/Symbls是用來存放從后面的URL路徑所下載下來的系統(tǒng)調(diào)試信息文件的。其實你也可以預先下載系統(tǒng)調(diào)試信息文件到一個路徑里,然后在 _NT_SYMBOL_PATH里指定那個目錄,但這樣一來有兩個缺點,一是你必須得進行版本的匹配,做這件事簡直太乏味了,二是你一次需要把整個操作系 統(tǒng)的調(diào)試信息文件都下載下來,可能會需要1G的空間。而通過前面設(shè)置環(huán)境變量的方式,調(diào)試器會根據(jù)需要只下載這次調(diào)試會話所需要的調(diào)試信息文件,并且它會 自動給你匹配版本。由于我們將要編寫的源代碼都在C:/Pro/文件夾中,生成的pdb文件也在C:/Pro/中,所以我們的 _NT_SYMBOL_PATH環(huán)境變量應該如下設(shè)置,假設(shè)你希望系統(tǒng)pdb文件下載到D:/Symbols:
            C:/Pro/>set _NT_SYMBOL_PATH=SRV*D:/Symbols*http://msdl.microsoft.com/download/symbols;C:/Pro/
            最后,我們需要在命令行中啟動cdb調(diào)試器,但當前目錄通常是源代碼文件夾C:/Pro/,為了避免如下冗余的鍵入:

            C:/Pro/>C:/Progs/Debug/cdb example1.exe
            應該為cdb,ntsd,WinDbg設(shè)置PATH環(huán)境變量:

            C:/Pro/>set PATH=%PATH%;C:/Progs/Debug/
            這里的C:/Progs/Debug是Debugging Tools for Windows的安裝目錄。以后就可以這樣來調(diào)試了:

            C:/Pro/>cdb example1.exe

            3。2 cdb啟動新實例的調(diào)試

            3。2。1 編寫一源程序,啟動cdb

            首先我編寫了下面的C程序,先用這個程序來介紹一些基本的命令,并且來驗證一下調(diào)試信息中是否確切包含了上面所說的那些內(nèi)容:

            [example1.c]
            int 		gVar;
            static int sgVar;
            int Inc(int Param);
            static int sDec(int sParam);
            void main(void)
            {
            int lVar;
            static int slVar;
            lVar = 3;
            slVar = 4;
            gVar = Inc(lVar);
            sgVar = sDec(slVar);
            }
            int Inc(int Param)
            {
            return (Param+1);
            }
            int sDec(int sParam)
            {
            return (sParam-1);
            }
            對這個程序用上面所講的方法編譯鏈接:
            C:/Pro/>cl /Zi example1.c /link /debug /subsystem:console /entry:main
            接下來啟動cdb調(diào)試器:

            C:/Pro/>cdb example1.exe

            Microsoft (R) Windows Debugger
            Copyright (c) Microsoft Corporation. All rights reserved.

            CommandLine: example1.exe
            Symbol search path is: SRV*D:/Symbols*http://msdl.microsoft.com/download/symbols
            Executable search path is:
            ModLoad: 00400000 00406000 example1.exe
            ModLoad: 7c920000 7c9b4000 ntdll.dll
            ModLoad: 7c800000 7c91c000 C:/WINDOWS/system32/kernel32.dll
            (c94.c24): Break instruction exception - code 80000003 (first chance)
            eax=00251eb4 ebx=7ffd4000 ecx=00000001 edx=00000002 esi=00251f48 edi=00251eb4
            eip=7c921230 esp=0012fb20 ebp=0012fc94 iopl=0 nv up ei pl nz na po nc
            cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
            ntdll!DbgBreakPoint:
            7c921230 cc int 3
            0:000>
            cdb 輸出了此時主線程的上下文信息(這個例子中也只有這一個線程)以及程序斷點信息后便會進入一個新的提示符:0:000>。以后我們會一直工作在這種 類型的提示符上,下面在這個提示符上輸入一個命令來加載所有的調(diào)試信息文件,此時可能會慢一些,因為要下載系統(tǒng)DLL的pdb文件,所以要確保你能上網(wǎng)。

            0:000>.reload /f

            看到這個以"."號做為前綴的命令,可能你會覺得怪怪的,但實際上還有用"!"號做前綴的呢,用"."號做前綴的命令表示元命令,而用"!“號做前綴的命令表示擴展命令,這里只做一個簡單的區(qū)分即可。

            其 實這時我們所要調(diào)試的程序已經(jīng)運行起來了,不過停在了某處,主線程處于凍結(jié)狀態(tài)。這一點和Linux的Gnu調(diào)試器GDB不一樣,對于GDB調(diào)試器,你先 要設(shè)置一個斷點,然后再鍵入運行命令(如果自己不手動設(shè)置一個斷點,那么程序?qū)恢边\行直到結(jié)束,你根本沒有調(diào)試的機會。),這時程序才處于運行狀態(tài)。 沒有運行和運行之后處于凍結(jié)狀態(tài)是兩個完全不同的概念。那么我們這個example1.exe停在了什么地方呢。下面我將介紹一個很重要的命令,用它我們 可以來研究這方面的問題。

            3。2。2 查看堆棧及用戶空間的初始化

            用kb命令可以來查看堆棧,它顯示棧上一些重要的信息。

            0:000>kb
            ChildEBP RetAddr Args to Child
            0012fb1c 7c95edc0 7ffdf000 7ffd4000 00000000 ntdll!DbgBreakPoint
            0012fc94 7c941639 0012fd30 7c920000 0012fce0 ntdll!LdrpInitializeProcess+0xffa
            0012fd1c 7c92eac7 0012fd30 7c920000 00000000 ntdll!_LdrpInitialize+0x183
            00000000 00000000 00000000 00000000 00000000 ntdll!KiUserApcDispatcher+0x7
            這個命令所列出來的信息后面還要詳細介紹,這里先關(guān)注一下函數(shù)的調(diào)用關(guān)系。從上面的列表可以看到有四個函數(shù),這四個函數(shù)都是ntdll模塊里的,從下至上函數(shù)依次被調(diào)用。要注意這是當前線程的用戶棧里所有的東西,就四個函數(shù),KiUserApcDispatcher是第一個,上面已經(jīng)提到過,在你指定的入口函數(shù)執(zhí)行之前還有很多的函數(shù)被調(diào)用,KiUserApcDispatcher是第一個被調(diào)用的,接下來它再調(diào)用_LdrpInitialize_LdrpInitialize調(diào)用LdrpInitializeProcess,再調(diào)用DbgBreakPoint。至于是誰調(diào)用的KiUserApcDispatcher,我現(xiàn)在只能簡單的告訴你是操作系統(tǒng)調(diào)度例程調(diào)度的結(jié)果。深入地探討它就離開本文的主題了。現(xiàn)在我們可以肯定的是程序停在了DbgBreakPoint里,因為它是棧上最后一個函數(shù)。從cdb調(diào)試器的輸出可以看到example1.exe停在了DbgBreakPoint函數(shù)里的int 3語句上,int 3是一個異常,它將會通知操作系統(tǒng)掛起這個線程,并且通知調(diào)試器,這是操作系統(tǒng)對調(diào)試的一個支持。其實DbgBreakPoint函數(shù)只有一條語句,那就是int 3。敏感點的人可能會想到,這樣一來,所有的程序,無論是否被調(diào)試,在運行的時候最初都會執(zhí)行DbgBreakPoint函數(shù)了,這也太傻了吧?情況并非如此,當我們鍵入cdb example1.exe時,cdb在啟動example1.exe的時候會加一個特殊的標記,在這種情況下LdrpInitializeProcess才會調(diào)用DbgBreakPoint,這又是操作系統(tǒng)對調(diào)試的一個支持。


            本文轉(zhuǎn)自
            http://chenshine.blogbus.com/logs/4414354.html
            久久久久99精品成人片试看| 久久免费国产精品一区二区| 久久免费99精品国产自在现线| 久久久久国产精品三级网| 亚洲国产小视频精品久久久三级| 色欲久久久天天天综合网精品| 国产美女久久久| 久久婷婷午色综合夜啪| 久久精品中文騷妇女内射| 久久久久亚洲AV成人网人人软件| 亚洲午夜久久久| 久久精品亚洲中文字幕无码麻豆| 久久精品成人一区二区三区| 久久久久久亚洲精品成人| 久久久久久A亚洲欧洲AV冫| 久久精品国产亚洲av麻豆小说 | 精品久久人人做人人爽综合| 亚洲午夜久久久影院| 久久99精品久久久久久9蜜桃| 久久夜色精品国产噜噜麻豆 | 97精品国产97久久久久久免费| 99热精品久久只有精品| 人妻无码中文久久久久专区| 污污内射久久一区二区欧美日韩| 国产亚洲欧美成人久久片| 亚洲精品无码久久久久久| 四虎影视久久久免费观看| 激情五月综合综合久久69| 久久免费精品一区二区| 日本久久久久亚洲中字幕| 无码超乳爆乳中文字幕久久| 色悠久久久久久久综合网| 精品久久人人妻人人做精品| 伊人丁香狠狠色综合久久| 97久久国产综合精品女不卡 | 亚洲精品tv久久久久| 久久久久99精品成人片牛牛影视| 激情五月综合综合久久69| 国产午夜电影久久| 国产精品久久久天天影视香蕉| 色综合久久中文色婷婷|