轉載註明>> 【作者:張佩】【鏡像:http://www.yiiyee.cn/Blog】
1. 概述
用戶成功安裝微軟Windows調試工具集後,能夠在安裝目錄下發現四個調試器程序,分別是:cdb.exe、ntsd.exe、kd.exe和Windbg.exe。其中cdb.exe和ntsd.exe只能調試用戶程序,Kd.exe主要用於內核調試,有時候也用於用戶態調試,上述三者的一個共同特點是,都只有控制檯界面,以命令行形式工作。
Windbg.exe在用戶態、內核態下都能夠發揮調試功能,尤其重要的是,它不再是命令行格式而是採用了可視化的用戶界面。所以絕大部分情況下,我們在談及Windows調試工具的時候,都直接指向Windbg,而不大談及前三者。
Windbg在用戶態和內核態下,都支持兩種調試模式,即“實時調試模式(Living)”和“事後調試模式(Postmortem)”。所謂實時模式,是被調試的目標對象(Target)當前正在運行當中,調試器可以實時分析、修改被調試目標的狀態,如寄存器、內存、變量,調試exe可執行程序或雙擊實時調試都屬於這種模式;所謂事後模式,是被調試的目標對象(Target)已經結束了,現在只是事後對它保留的快照進行分析,這個快照稱爲轉儲文件(Dump文件)。
Windbg另一個重大優點,還在於它支持源碼級的調試,就像VC自帶的調試器一樣。
雖然提供了用戶界面,但Windbg歸根結底還是需要用戶一個個地輸入命令來指揮其行動。這就是他的Command窗口。
每個調試命令都各有使用範圍,有些命令只能用於內核調試,有些命令只能用於用戶調試,有些命令只能用於活動調試。但用戶也不必記得這許多,一旦在某個環境下,使用了不被支持的命令,都會顯示“No export XXX found”的字樣。就拿!process命令來說吧,它顯示進程信息,但只能用於內核調試中,如果在用戶調試中使用,就是下面的情景:
0:001> !process No export process found
1.1 尋求幫助
我們首先來看如何在使用過程中獲取有用的幫助。Windbg中的調試命令,分爲三種:基本命令,元命令和擴展命令。基本命令和元命令是調試器自帶的,元命令總是以“.”開頭,而擴展命令是外部加入的,總是以感嘆號“!”開頭。各種調試命令成千上萬,我們首先要想辦法把它們都列舉出來,並取得使用方法。
基本命令最少了,大概40個左右。列舉所有的基本命令,使用如下命令:
- ?
元命令有一百多個,使用下面命令列舉所有元命令:
- .help [/D]
如使用“/D”參數,命令列表將以DML格式顯示。DML是一種類似於HTML的標識語言,下面會講到。下圖以DML格式顯示所以有字母a開頭的元命令:
最後講擴展命令。所謂擴展命令,顧名思義是可以“擴展”的。擴展命令從動態連接庫中暴露出來,一般以DLL文件名來代表一類擴展命令集,首先我們要搜索出系統中有多少個這樣的DLL文件,使用下面命令:
- .chain [/D]
此命令能夠給出一個擴展命令集的鏈表。和.help命令一樣,也可以使用/D參數以DML格式顯示。如下所示:
0:001> .chain Extension DLL search Path: C:\Program Files (x86)\Windows Kits\8.0\Debuggers\x64\WINXP; Extension DLL chain: dbghelp: image 6.2.9200.20512, API 6.2.6, built Fri Sep 07 13:45:49 2012 [path: C:\Program Files (x86)\Windows Kits\8.0\Debuggers\x64\dbghelp.dll] ext: image 6.2.9200.16384, API 1.0.0, built Thu Jul 26 10:11:33 2012 [path: C:\Program Files (x86)\Windows Kits\8.0\Debuggers\x64\winext\ext.dll] exts: image 6.2.9200.16384, API 1.0.0, built Thu Jul 26 10:15:20 2012 [path: C:\Program Files (x86)\Windows Kits\8.0\Debuggers\x64\WINXP\exts.dll] uext: image 6.2.9200.16384, API 1.0.0, built Thu Jul 26 10:15:09 2012 [path: C:\Program Files (x86)\Windows Kits\8.0\Debuggers\x64\winext\uext.dll] ntsdexts: image 6.2.9200.16384, API 1.0.0, built Thu Jul 26 10:16:01 2012 [path: C:\Program Files (x86)\Windows Kits\8.0\Debuggers\x64\WINXP\ntsdexts.dll]
最上面兩行顯示了擴展模塊的搜索路徑。接下來共列出了六個Windbg自帶的擴展模塊:wdfkd、dbghellp、ext、exts、uext和ntsdexts。可以查看到這些擴展模塊的版本信息、鏡像文件路徑。如何列出某個擴展庫中所包含的擴展命令列表呢?絕大部分擴展模塊可使用如下命令:
- !模塊名.help
此外,擴展命令模塊是可“擴展”的。如果讀者從第三方處獲取,或自己編寫了一個擴展調試模塊,則可通過.load/.unload命令動態加載/卸載。
1.2 DML語言
DML(Debugger Markup Language調試器標記語言)像HTML一樣,可從一處鏈接到另一處。不同處在於,DML的鏈接內容需要用戶點擊後纔會動態生成。一般用來以精簡方式顯示大量信息和擴展功能。
DML有很多實用的功能,如果使用者一時不知道從何下手,最好就是輸入.dml_start命令,開始DML之旅。
DML鏈接以更加可視化的方式,引導用戶查看調試信息,使得調試工具的使用相比純指令格式而言,更爲友好。DML如同是對原指令的一層輕微的包裝一樣,讓生硬的指令更加溫和了。所以建議讀者總是把DML默認開啓。
- .prefer_dml 1
開始DML。
- .prefer_dml 0
關閉DML。
一旦開啓DML後,像k等支持DML的調試命令,將默認以DML格式顯示輸出內容。
DML還能以一種很特殊的方式爲函數畫流程圖。它主要的原理是使用反彙編,類似於uf,但在邏輯分支處,它會停止反彙編並顯示分支讓用戶選擇。另外,它能顯示彙編代碼對應的行號,這一點真的非常好。如果稍加精進,他就能畫出非常漂亮的流程圖了。他的一個特點是反彙編的順序是從後往前推。只要細想一想,就會覺得很有道理。如果正推的話,分支太多;而反推則分支順序在用戶的參與下(即用戶進行分支選擇),是固定了的。
- .dml_flow FindAllInfFilesA FindAllInfFilesA+30
這是一個非常簡單、實用的例子,對Kernel32庫中的FindAllInfFilesA接口函數進行反彙編,效果類似uf命令卻更強大。
1.3 基本信息
本節講解和調試器軟件本身相關的命令,比如:查看軟件版本、啓動參數,以及最基本的軟件設置命令。首先看版本命令:
- version
此命令顯示操作系統的版本信息以及Windbg本身的版本信息,Windbg的配置和操作系統密切相關,所以將操作系統的版本信息一併顯示出來是很有必要的。在內核環境與用戶環境下運行此命令,會得到不同的輸出。下圖爲內核環境下輸出結果:
0:001> version Windows 7 Version 7601 (Service Pack 1) MP (8 procs) Free x64 Product: WinNt, suite: SingleUserTS kernel32.dll version: 6.1.7601.18015 (win7sp1_gdr.121129-1432) Machine Name: Debug session time: Thu Aug 22 10:11:04.000 2013 (UTC + 8:00) System Uptime: 14 days 17:26:44.613 Process Uptime: 14 days 17:14:25.000 Kernel time: 0 days 0:09:02.000 User time: 0 days 0:42:36.000 Full memory user mini dump: C:\Users\mozhang\AppData\Local\Temp\dwm.DMP Microsoft (R) Windows Debugger Version 6.2.9200.16384 AMD64 Copyright (c) Microsoft Corporation. All rights reserved.
除了Windbg版本信息,上面的輸出中還包括目標系統信息。如果純粹是爲了查看目標系統的版本信息,可使用下面的vertarget命令:
- vertarget
Windbg支持對多個調試系統中的多個調試目標同時進行調試。上面我們通過version或vertarget命令列出了當前調試系統的版本信息,還可以查看當前目標系統的狀態:
- ||
如Windbg中同時打開多個調試對象,“||”命令將列出對象列表。筆者爲了演示此種情況,先在Windbg中開啓Local Debug環境,然後兩次調用.opendump命令打開兩個DUMP文件,這樣就同時擁有了三個被調試的目標對象。下圖顯示了這個情況:
上圖中的活動對象是0號對象(可從數字0前面的小數點看出)。調試器需要在多個調試目標之間進行切換的話,使用“s”參數。如要切換到1號目標可使用下面的命令:
- || 1 s
最後一個命令用來查看系統時間。這包括系統當前時間,以及系統正常運行持續時間;用戶模式下還會顯示當前進程的持續時間。命令格式如下:
- .time
0:001> .time Debug session time: Thu Aug 22 10:11:04.000 2013 (UTC + 8:00) System Uptime: 14 days 17:26:44.613 // 系統運行時間 Process Uptime: 14 days 17:14:25.000// 當前進程運行時間 Kernel time: 0 days 0:09:02.000 User time: 0 days 0:42:36.000
1.4 基本設置
首先看一個清屏命令:
- .cls
當命令窗口中的內容太亂的時候,這個命令幫你快刀斬亂麻。
下面看一個設置默認數字進制的命令:
- n [8|10|16]
軟件默認是16進制,但有時候我們也需要把默認進制改成八進制或十進制的。下面嘗試在八進制下面求數字11的值,如下:
0:001> n 8 base is 8 0:001> ? 11 Evaluate expression: 9 = 00000000`00000009
最後再來說一個處理器模式指令。關於處理器模式很值得一說,很重要。處理器模式的設置,反映了Windbg軟件的強大。舉例來說,主機爲32位的系統,卻可以同時調試X86、IA64、X64的目標系統——前提是先將主機的處理器模式設置正確了。可用處理器模式值有:x86、adm64、ia64、ebc。
- .effmach x86
命令.effmach表示Effective Machine Type,即有效的機器類型。此命令將當前的處理器模式設置爲x86模式。
1.5 格式化顯示
將一個整數以各種格式顯示,包括:16進制、10進制、8進制、二進制、字符串、日期、浮點數等。是不是很方便?這個命令是:
- .formats 整數
下面以0x123abc爲例:
0:001> .formats 0x123abc Evaluate expression: Hex: 00000000`00123abc Decimal: 1194684 Octal: 0000000000000004435274 Binary: 00000000 00000000 00000000 00000000 00000000 00010010 00111010 10111100 Chars: ......:. Time: Thu Jan 15 03:51:24 1970 Float: low 1.67411e-039 high 0 Double: 5.90252e-318
1.6 開始調試
現在領大家進入調試階段。首先看看如何讓調試器附載到一個已運行的進程中去?比如IE軟件在運行過程中發生了崩潰,打開Windbg後如何調試呢?第一步就是把Windbg附載到發生崩潰的IE進程上。使用如下命令格式:
- .attach PID
或者通過Windbg的啓動參數進行掛載:
- Windbg –p PID
上面兩個命令中,PID指定了進程ID。如果覺得指定PID不方便,也可以通過進程名進行掛載:
- Windbg -pn 進程名
比如掛載到記事本就可以這樣:
windbg –pn notepad.exe
上面的命令是把調試器掛載到已經存在的進程上,另外調試器可以創建新進程並對它進行調試,這二者使用了不同的侵入方法。使用下面的命令:
- .create 程序啓動命令行
或者Windbg啓動參數
- Windbg 程序啓動命令行
比如創建並調試一個記事本子進程,可用.create notepad或者windbg notepad命令。也可以打開Windbg後,在File菜單中選擇“Open Executable…”啓動Notepad子進程,但這個選項只能被執行一次(之後會灰掉)。
使用上述命令可將調試器連續附載到多個進程,也就是說,能夠同時調試多個進程,這一點看上去很神奇哦。下例中,調試器先創建子程序IOCTL.exe,然後又調用.attach命令附加到記事本進程,使用命令“|”列出所有被調試進程。
讀者可能會奇怪,多個進程同時調試怎麼兼顧呢?只要有一個切換指令就可以了,這樣就能夠切換到任意的進程(令其爲當前進程)並對之進行調試。比如上圖顯示1號進程爲當前進程(注意1前面的小點),如何將當前進程切換到0號進程呢?可以使用進程列表命令“|”輕鬆切換,比如:
- | 0 s
此命令把當前調試環境切換到0號IOCTL.exe進程。另外需注意的是,多個用戶進程調試目標都處於同一個調試會話中,使用“||”命令會看到,它們屬於同一個 “Live user mode”調試會話。
下面看dump文件調試,使用命令:
- .opendump 文件名
此命令打開一個dump文件,並建立一個DUMP調試會話。如何手動創建一個dump文件呢?比如在調試過程中,遇到了無法解決的問題,希望獲得異地幫助,則把當前調試環境保存到Dump文件中發送給能提供幫助的人,不失爲一種好辦法。
- .dump 文件名
Dump文件一般以.dmp爲後綴,系統生成的Dump文件都默認以.dmp爲後綴的,但使用.dump命令時,使用者可以設置任意後綴,甚至無後綴。下例中,首先爲當前進程生成一個dump文件保存到a.txt中(即後綴名爲.txt),然後將之打開並分析:
0:001> .dump a.txt Creating a.txt - mini user dump Dump successfully written 0:001> .opendump a.txt Loading Dump File [C:\Program Files (x86)\Windows Kits\8.0\Debuggers\a.txt] User Mini Dump File: Only registers, stack and portions of memory are available Opened 'a.txt' // 打開成功
上文講到進程掛載命令,當需要解除掛載時,可使用解掛命令,如下:
- .detach
此命令結束當前調試會話, Windbg解除和被調試進程之間的調試關係(不管是通過掛載,還是通過創建方式建立的調試關係),解掛後,被調試進程能夠獨立運行;如果當前的調試會話是一個Dump文件,此命令直接結束對dump文件的調試,即結束調試會話。
如果需要徹底結束調試,下面的命令更有用:
- q | qq | qd
q是Quit的縮寫。結束當前調試會話,並返回到最簡單的工作空間,甚至把命令行界面也關閉掉。q和qq兩個命令將結束(close)被調試的進程,qd不會關閉調試進程,而是進行解掛操作。
雙機調試的時候,如果你感覺調試已經陷入僵局,比如目標機Hang住了動都動不了,此時通過主機讓目標機強制宕機或重啓,不失爲一個好主意。
- .crash
- .reboot
crash命令能引發一個系統藍屏,並生成dump文件;而.reboot使系統重啓,不產生dump文件。