Windbg新手入坑指南
文章目錄
- 前言
- 熟悉理論 提高調(diào)試效率
- 定制自己的Windbg界面
- 關(guān)于工作空間
- 命令概述
- 標(biāo)準(zhǔn)命令
- 元命令
- 擴(kuò)展命令
- 調(diào)試技巧
- 偽寄存器
- 開(kāi)始實(shí)戰(zhàn)
- 控制調(diào)試目標(biāo)
- 單步步入和單步步過(guò)
- 單步執(zhí)行到指定地址
- 單步執(zhí)行到下一個(gè)函數(shù)調(diào)用
- 單步執(zhí)行到下一個(gè)分支
- 繼續(xù)運(yùn)行
- 追蹤并監(jiān)視
- 停止調(diào)試
- 總結(jié)
- 使用斷點(diǎn)
- 軟件斷點(diǎn)
- 硬件斷點(diǎn)
- 條件斷點(diǎn)
- 地址表達(dá)式
- 管理斷點(diǎn)
- 總結(jié)
- 觀察棧
- 顯示棧回溯
- 總結(jié)
- 分析內(nèi)存
- 顯示內(nèi)存
- 顯示字符串
- 顯示數(shù)據(jù)類型
- 搜索內(nèi)存
- 修改內(nèi)存
- 其他命令
- 參考資料
前言
這篇文章是我學(xué)習(xí)windbg的一個(gè)筆記和總結(jié),通過(guò)和OD的功能來(lái)對(duì)比學(xué)習(xí)windbg的一些理論和命令,達(dá)到能調(diào)試一個(gè)exe或者sys文件的目的。大神請(qǐng)飄過(guò)~
熟悉理論 提高調(diào)試效率
在開(kāi)始調(diào)試之前,了解以下理論知識(shí)可以幫助你大大提高調(diào)試效率
定制自己的Windbg界面
windbg默認(rèn)打開(kāi)就只有一個(gè)Command窗口,但是這樣調(diào)試效率很低,所以可以先設(shè)置好自己的用戶界面,下面是我的Windbg界面,因?yàn)橛脩T了OD,所以這個(gè)完全就是仿制的OD的界面,
所有窗口都可以狀態(tài)欄里調(diào)出來(lái)
設(shè)置完成之后,你可以保存到工作空間,這樣下次再次打開(kāi)時(shí)這個(gè)界面就會(huì)保留
關(guān)于工作空間
工作空間保存有斷點(diǎn) 用戶定義的別名 調(diào)試器的設(shè)置 圖形界面信息 調(diào)試會(huì)話狀態(tài)等等信息,類似VS的項(xiàng)目文件,PS的工作區(qū)。
命令概述
WinDBG主要是以命令方式工作的,WinDBG共支持三類命令:標(biāo)準(zhǔn)命令、元命令和擴(kuò)展命令
標(biāo)準(zhǔn)命令
標(biāo)準(zhǔn)命令通常是一兩個(gè)字符(version除外)或者符號(hào),用來(lái)提供適用于各種調(diào)試目標(biāo)的最基本調(diào)試功能。標(biāo)準(zhǔn)命令是不分大小寫(xiě)的。比如:
- g 運(yùn)行
- t 單步步入
- p 單步步過(guò)
- r 查看和修改寄存器
元命令
元命令用來(lái)提供標(biāo)準(zhǔn)命令沒(méi)有提供的調(diào)試功能,與標(biāo)準(zhǔn)命令一樣,元命令也是內(nèi)建在調(diào)試器引擎或者WinDBG程序文件中的。
所有元命令都以一個(gè)點(diǎn)(.)開(kāi)始,所以元命令也被稱為點(diǎn)命令,例如:
- .reload 重新載入符號(hào)
- .reboot 重啟目標(biāo)機(jī)器
- .restart 重啟調(diào)試器
- .logfile 顯示信息
擴(kuò)展命令
擴(kuò)展命令用于擴(kuò)展某一方面的調(diào)試功能。與標(biāo)準(zhǔn)命令和元命令是內(nèi)建在WinDBG程序文件中不同,擴(kuò)展命令是實(shí)現(xiàn)在動(dòng)態(tài)加載的擴(kuò)展模塊(DLL)文件中的。
所有的擴(kuò)展命令都以!開(kāi)頭
通過(guò)WinDBG的SDK,用戶可以編寫(xiě)自己的擴(kuò)展模塊和擴(kuò)展命令,例如漏洞測(cè)試常用的一個(gè)mona插件
- !mona
調(diào)試技巧
在開(kāi)始調(diào)試之前,有幾個(gè)要點(diǎn),記住以下幾個(gè)點(diǎn)對(duì)于調(diào)試事半功倍
- 直接按回車可以執(zhí)行上一條命令
- 使用分分號(hào)作為分隔符,可以在同一行輸入多條命令
- 按上下方向鍵可以瀏覽和選擇以前輸入過(guò)的命令
- 當(dāng)命令提示符顯示為BUSY時(shí),即使命令編輯框可以輸入命令,但是這個(gè)命令也不會(huì)被馬上執(zhí)行,要等WinDBG恢復(fù)到空閑狀態(tài)才能執(zhí)行
- 使用Ctrl+Break 來(lái)終止一個(gè)長(zhǎng)時(shí)間未完成的命令。如果使用KD或則CDB,那么用Ctrl+C
- 選擇菜單->Edit_>Write Window Text to File可以把之前敲過(guò)的所有命令記錄到文件
偽寄存器
WinDBG自動(dòng)定義了很多偽寄存器。在命令行和命令文件中都可以使用偽寄存器。WinDBG會(huì)自動(dòng)將其替換(展開(kāi))為合適的值。例如下面這個(gè)@$scopeip就是一個(gè)偽寄存器,它代表當(dāng)前的eip指針
下表列出了windbg所定義的部分寄存器(字典型知識(shí),需要時(shí)查閱即可)
| $ea | 調(diào)試目標(biāo)所執(zhí)行上一條指令的有效地址 |
| $ea2 | 調(diào)試目標(biāo)所執(zhí)行上一條指令的第二個(gè)有效地址 |
| $exp | 表達(dá)式評(píng)估器所評(píng)估的上一條表達(dá)式 |
| $ra | 當(dāng)前函數(shù)的返回地址 |
| $eip | 指令指針寄存器 |
| $eventip | 當(dāng)前調(diào)試事件發(fā)生時(shí)的指令指針 |
| $previp | 上一事件的指令指針 |
| $relip | 與當(dāng)前事件關(guān)聯(lián)的指令指針 |
| $scopeip | 當(dāng)前上下文的指令指針 |
| $exentry | 當(dāng)前進(jìn)程的入口地址 |
| $retreg | 首要的函數(shù)返回值寄存器 |
| $retreg64 | 64位格式的首要函數(shù)返回寄存器 |
| $csp | 棧頂指針ESP |
| $p | 上一個(gè)內(nèi)存顯示命令所打印的第一個(gè)值 |
| $proc | 當(dāng)前進(jìn)程EPROCESS結(jié)構(gòu)的指針 |
| $thread | 當(dāng)前線程ETHREAD結(jié)構(gòu)的指針 |
| $peb | 當(dāng)前進(jìn)程的進(jìn)程環(huán)境塊(PEB)的地址 |
| $teb | 當(dāng)前線程的線程環(huán)境塊(TEB)地址 |
| $tpid | 擁有當(dāng)前線程的進(jìn)程ID(PID) |
| $tid | 當(dāng)前線程的線程ID |
| $bpx | X號(hào)斷點(diǎn)的地址 |
| $frame | 當(dāng)前棧幀的序號(hào) |
| $dbgtime | 當(dāng)前時(shí)間 |
| $callret | 使用.call命令調(diào)用的上一個(gè)函數(shù)的返回值 |
| $ptrsize | 調(diào)試目標(biāo)所在系統(tǒng)的指針類型寬度 |
| $pagesize | 調(diào)試目標(biāo)所在的系統(tǒng)的內(nèi)存頁(yè)字節(jié)數(shù) |
開(kāi)始實(shí)戰(zhàn)
控制調(diào)試目標(biāo)
控制調(diào)試目標(biāo)是調(diào)試器的一個(gè)核心任務(wù)。其宗旨就是使調(diào)試目標(biāo)始終處于調(diào)試器的控制之下,讓調(diào)試人員可以可以隨心所欲的控制程序的執(zhí)行狀態(tài)。在OD可以通過(guò)圖形界面和各種快捷鍵隨心所欲地控制程序,相比windbg就沒(méi)那么方便了。但是WinDBG提供了強(qiáng)大的機(jī)制和豐富的命令來(lái)控制調(diào)試目標(biāo),這些命令要比OD的功能豐富的多。
單步步入和單步步過(guò)
- t 單步步入
- p 單步步過(guò)
命令格式如下:
p|t [r] [=StartAddress] [count] ["Command"]
- r表示禁止顯示寄存器內(nèi)容
- 默認(rèn)情況下,調(diào)試器總是讓目標(biāo)從當(dāng)前位置開(kāi)始單步執(zhí)行,但是也可以通過(guò)等號(hào)(=)來(lái)指定一個(gè)新的起始地址,讓程序從這個(gè)地址開(kāi)始單步
- count用來(lái)指定單步執(zhí)行的次數(shù)
- Command用來(lái)指定每次單步執(zhí)行后要執(zhí)行的命令
例如:
首先查看一下當(dāng)前的反匯編,我想從77e40d8e這個(gè)位置開(kāi)始執(zhí)行單步 單步兩次 不顯示寄存器 單步執(zhí)行完成之后顯示調(diào)用堆棧,就可以執(zhí)行這么一條命令,執(zhí)行完成之后如圖:
tr =77e40d8e 2 "kb"
單步執(zhí)行到指定地址
WinDBG提供了pa和ta命令用來(lái)執(zhí)行到指定的代碼地址,其命令格式為:
pa|ta [r] [=StartAddress] StopAddress
- pa是Step To Address的縮寫(xiě),即單步執(zhí)行到StopAddress參數(shù)所代表的地址處
- pa和ta的區(qū)別在于 ta在遇到函數(shù)時(shí)會(huì)進(jìn)入函數(shù),windbg的執(zhí)行結(jié)果會(huì)顯示函數(shù)內(nèi)容;而pa則是直接步過(guò)函數(shù),windbg的執(zhí)行結(jié)果不顯示函數(shù)內(nèi)容
例如:
查看一下當(dāng)前的反匯編
如果想直接單步到77e9f137的位置,就可以輸入下面這條命令,執(zhí)行結(jié)果如下
par 77e9f137
單步執(zhí)行到下一個(gè)函數(shù)調(diào)用
與pa和ta命令類似,pc和tc命令用來(lái)單步執(zhí)行到下一個(gè)函數(shù)調(diào)用指令(call)
pc|tc [r] [=StratAddress] [Count]
- pc或tc命令都是讓調(diào)試目標(biāo)從當(dāng)前地址或者StartAddress指定的地址恢復(fù)執(zhí)行,直到遇到函數(shù)調(diào)用時(shí)停下來(lái)
- Count用來(lái)指定遇到的函數(shù)調(diào)用指令個(gè)數(shù)
- 這兩個(gè)的差別依然是在進(jìn)入和不進(jìn)入函數(shù)時(shí)windbg顯示的結(jié)果上有區(qū)別
例如:
首先來(lái)查看一下當(dāng)前的反匯編
如果想直接單步到77e9f137這個(gè)位置的call,就可以直接用下面一條命令
pcr
單步執(zhí)行到下一個(gè)分支
CPU有分支的監(jiān)視和記錄功能,利用這一功能可以實(shí)現(xiàn)單步執(zhí)行到分支,但是這個(gè)命令有一個(gè)缺陷就是不能在x86的用戶態(tài)模式下使用,命令格式如下:
tb [r] [=StartAddress] [Count]
繼續(xù)運(yùn)行
g(go)命令的一般形式為:
g[a][=StartAddress] [BreakAddress][;BreakCommands]
- 其實(shí)StartAddress用來(lái)指定開(kāi)始執(zhí)行的起始地址 這個(gè)功能有點(diǎn)像OD的此處為新的EIP
- BreakAddress用來(lái)指定一個(gè)斷點(diǎn)地址
- BreakCommands用來(lái)指定斷點(diǎn)命中后所指定命令
- 如果不帶任何參數(shù),那么g命令就是恢復(fù)目標(biāo)運(yùn)行 相當(dāng)于OD的F9
- 可以用gu命令來(lái)執(zhí)行到返回 相當(dāng)于OD的Ctrl+F9
追蹤并監(jiān)視
如果我們想了解一個(gè)函數(shù)的執(zhí)行路徑和它調(diào)用了哪些其它函數(shù),每個(gè)函數(shù)包含了多少條指令,但我們又不想一步步的跟蹤執(zhí)行,那么可以使用wt命令讓它幫我跟蹤執(zhí)行并生成一份報(bào)告給我
下面通過(guò)一個(gè)例子來(lái)解釋wt命令的用法,注意:wt命令必須在函數(shù)的起始位置處,也就是步入call之后的第一條指令時(shí)執(zhí)行
首先單步步入函數(shù)。然后使用wt命令生成報(bào)告
可以把wt命令的結(jié)果分為六個(gè)部分
- 第一個(gè)部分是標(biāo)題 顯示了追蹤的函數(shù)名和追蹤的結(jié)束地址
- 第二部分是詳細(xì)的執(zhí)行情況 包括如下四列:
- 第一列為指令數(shù),這一列的數(shù)字就是這個(gè)函數(shù)從入口進(jìn)入到下一行所對(duì)應(yīng)的函數(shù)入口所執(zhí)行的指令
- 第二列用來(lái)顯示本行所對(duì)應(yīng)的函數(shù)調(diào)用其他函數(shù)時(shí)所執(zhí)行的總指令數(shù)
- 第三列表示函數(shù)的調(diào)用深度 沒(méi)進(jìn)入一個(gè)函數(shù)深度加一
- 第四列為函數(shù)名稱 名稱前的縮進(jìn)用來(lái)表示深度
停止調(diào)試
- q 停止調(diào)試
- .detach 分離調(diào)試器
區(qū)別在于停止調(diào)試時(shí)調(diào)試器和目標(biāo)程序的偶停止運(yùn)行,而分離調(diào)試器則是調(diào)試器顯示No Target,而目標(biāo)程序繼續(xù)運(yùn)行
總結(jié)
| p | Step | 單步步過(guò) |
| t | Trace | 單步步入 |
| pa | Step to Address | 單步到指定地址 不進(jìn)入子函數(shù) |
| ta | Trace to Address | 追蹤到指定地址 進(jìn)入子函數(shù) |
| pc | Step to Next Call | 單步執(zhí)行到下一個(gè)函數(shù)調(diào)用 |
| tc | Trace to Next Call | 追蹤執(zhí)行到下一個(gè)函數(shù)調(diào)用 |
| tb | Trace to Next Branch | 追蹤到下一條分支指令 |
| g | Go | 恢復(fù)運(yùn)行 |
| gu | Go Up | 執(zhí)行到函數(shù)返回 |
| q | Quit | 停止調(diào)試 |
| .detach | detach | 分離調(diào)試器 |
使用斷點(diǎn)
軟件斷點(diǎn)
WinDBG設(shè)計(jì)了三條命令來(lái)設(shè)置軟件斷點(diǎn),分別是bp、bu和bm。其中bp是基本的而且最常用的,其命令格式如下:
bp[ID] [Options] [Address [Passes]] ["Command String"]
- ID用來(lái)指定斷點(diǎn)編號(hào) 不指定默認(rèn)從0開(kāi)始編排
- Options用來(lái)指定選項(xiàng)
- Address用來(lái)指定斷點(diǎn)地址
- Passes用來(lái)指定經(jīng)過(guò)斷點(diǎn)的次數(shù) 默認(rèn)經(jīng)過(guò)一次斷下
- CommandString用來(lái)指定設(shè)置斷點(diǎn)后執(zhí)行的命令 用雙引號(hào)包圍命令,多個(gè)命令用分號(hào)分隔
bu命令用來(lái)設(shè)置一個(gè)延遲的以后再求解的斷點(diǎn),用于對(duì)尚未加載模塊中的代碼設(shè)置斷點(diǎn)。當(dāng)指定的模塊被加載時(shí),WinDBG會(huì)真正落實(shí)這個(gè)斷點(diǎn)。所以bu命令對(duì)于調(diào)試動(dòng)態(tài)加載模塊的入口函數(shù)或者初始化代碼特別有用
bm命令用來(lái)設(shè)置一批斷點(diǎn),相當(dāng)于幫我們自動(dòng)執(zhí)行很多次bp或者bu命令。比如以下命令對(duì)于msvcr80d模塊中的所有print開(kāi)頭的函數(shù)設(shè)置斷點(diǎn):
bm msvcr80d!print*
bm和bu是命令格式如下:
bu[ID] [Options] [Address [Passes]] ["Command String"] bm[Options] SymbolPattern [Passes] ["Command String"]其中的Options可以為以下內(nèi)容
- /1如果指定此選項(xiàng),那么這個(gè)斷點(diǎn)命中一次后便會(huì)便自動(dòng)從斷點(diǎn)列表中刪除。這種斷點(diǎn)被稱為一次命中斷點(diǎn)
- /p這個(gè)開(kāi)關(guān)只能用在內(nèi)核調(diào)試中,/p后跟一個(gè)進(jìn)程的EPROCESS結(jié)構(gòu),作用是只有當(dāng)前進(jìn)程是指定進(jìn)程時(shí)才觸發(fā)這個(gè)斷點(diǎn)
- /t與/p開(kāi)關(guān)類似,只能用在內(nèi)核調(diào)試中,用來(lái)指定一個(gè)ETHREAD結(jié)構(gòu),作用是只有在執(zhí)行指定的線程訪問(wèn)斷點(diǎn)地址時(shí)才觸發(fā)斷點(diǎn)
- /c和/C這兩個(gè)開(kāi)關(guān)后面可以帶一個(gè)數(shù)字,用來(lái)指定中斷給用戶的最大函數(shù)調(diào)用深度和最小函數(shù)調(diào)用深度。舉例來(lái)說(shuō),使用命令bp/c5msvcr80d!printf設(shè)置的斷點(diǎn)只有當(dāng)函數(shù)調(diào)用深度淺于5時(shí)才中斷給用戶
硬件斷點(diǎn)
WinDBG的ba命令用來(lái)設(shè)置硬件斷點(diǎn),其格式如下:
ba [ID] Access Size [Option] [Address[Passes]] ["Command String"]
-
ID用來(lái)指定斷點(diǎn)序號(hào)
-
Access用來(lái)指定觸發(fā)斷點(diǎn)的訪問(wèn)方式 可以為以下幾個(gè)字母之一
- e 讀取和執(zhí)行時(shí)觸發(fā)斷點(diǎn)
- r 讀取和寫(xiě)入時(shí)觸發(fā)斷點(diǎn)
- w 寫(xiě)入時(shí)觸發(fā)斷點(diǎn)
- i 有IO操作時(shí)觸發(fā)斷點(diǎn)
-
Size用來(lái)指定訪問(wèn)的長(zhǎng)度 x86系統(tǒng)可以為1 2 4三種值
-
Passes參數(shù)和CommandString參數(shù)的用法與設(shè)置軟件斷點(diǎn)命令中的一樣
例如:
ba r1 0x401000
那么對(duì)內(nèi)存地址0041717c的一字節(jié)訪問(wèn)、字訪問(wèn)、雙字訪問(wèn)(讀寫(xiě))都會(huì)觸發(fā)這個(gè)斷點(diǎn)
如果想要查看硬件斷點(diǎn)和狀態(tài)可以直接看寄存器窗口的DR0-DR7寄存器
條件斷點(diǎn)
對(duì) 沒(méi)有錯(cuò)!windbg也支持條件斷點(diǎn),但是這玩意有點(diǎn)復(fù)雜,而且實(shí)用性好像不大,反正我在OD里從來(lái)沒(méi)用過(guò),直接PASS吧。另外windbg好像是沒(méi)有內(nèi)存斷點(diǎn)的
地址表達(dá)式
可以使用以下三種方法來(lái)指定斷點(diǎn)命令中的地址參數(shù)
-
直接使用內(nèi)存地址,比如bp 00411390
-
使用模塊名加函數(shù)符號(hào)的方式,比如bp dbgee!wmain代表對(duì)dbgee模塊中的wmain函數(shù)設(shè)置斷點(diǎn)。也可以在符號(hào)后增加一個(gè)地址偏移,比如bp dbgee!wmain+3
-
如果是使用完全的調(diào)試符號(hào),調(diào)試符號(hào)中包含源代碼行信息,那么可以使用如下形式:
`[[Module!]Filename][:LineNumber]`
其中Module為模塊名,Filename為源程序文件名,LInenumber為行號(hào)。整個(gè)表達(dá)式要用兩個(gè)波浪號(hào)包起來(lái)``,要有調(diào)試符號(hào)才能實(shí)現(xiàn),對(duì)于逆向來(lái)說(shuō)沒(méi)什么用 這個(gè)也pass
-
對(duì)于C++的類方法,也可以使用類名雙冒號(hào)(::)或者雙下劃線(__)來(lái)連接類名和方法名,比如:
bp MyClass__MyMethod bp MyClass:MyMethod bp@@(MyClass::MyMethod)管理斷點(diǎn)
使用bl命令可以列出當(dāng)前已經(jīng)設(shè)置的所有斷點(diǎn),例如:
-
第一列是斷點(diǎn)的序號(hào)
-
第二列是斷點(diǎn)的狀態(tài)
- e代表啟用(enable)
- d代表禁用(disable)
- 對(duì)于bu設(shè)置的斷點(diǎn)還可能有字母u,表示尚未解決(unresolved)
-
第三列是斷點(diǎn)的地址
-
第四列是斷點(diǎn)觸發(fā)剩余次數(shù)
-
第五列是斷點(diǎn)的初始計(jì)數(shù)
-
第六列是斷點(diǎn)所關(guān)聯(lián)的進(jìn)程和線程,冒號(hào)前是進(jìn)程號(hào),冒號(hào)后是線程號(hào)
-
第七列是斷點(diǎn)地址的符號(hào)表示
命令bc、bd、be分別用來(lái)刪除、禁止和啟用斷點(diǎn),它們的格式都是:
bc|bd|be 斷點(diǎn)號(hào)
其中斷點(diǎn)號(hào)可以使用*來(lái)通配所有斷點(diǎn),使用-來(lái)表示一個(gè)范圍,或者使用逗號(hào)來(lái)指定多個(gè)斷點(diǎn)號(hào)。例如以下命令都是有效的:
bd 0-2,4 禁止0 1 2 4號(hào)斷點(diǎn) be * 啟用所有斷點(diǎn)總結(jié)
最后來(lái)一個(gè)表格總結(jié)
| bp | 設(shè)置軟件斷點(diǎn) |
| bu | 對(duì)未加載的模塊設(shè)置斷點(diǎn) |
| bm | 批量設(shè)置斷點(diǎn) |
| ba | 設(shè)置硬件斷點(diǎn) |
| bl | 列出所有斷點(diǎn) |
| bc | 刪除斷點(diǎn) |
| bd | 禁止斷點(diǎn) |
| be | 啟用斷點(diǎn) |
觀察棧
顯示棧回溯
WinDBG的k系列命令就是用來(lái)幫助我們進(jìn)行棧回溯的,先來(lái)看一個(gè)例子
- 其中的每一行代表?xiàng)I系囊粋€(gè)棧幀 也就是一個(gè)函數(shù)
- 最上面一行表示的是當(dāng)前正在執(zhí)行的函數(shù) 每個(gè)函數(shù)下面一行是上一行的父函數(shù)
- 第一列是棧幀的基地址EBP
- 第二列是函數(shù)的返回地址
- 第三列是函數(shù)名以及執(zhí)行位置
K命令顯示了函數(shù)名信息,但是沒(méi)有顯示每個(gè)函數(shù)的參數(shù)。命令kb可以顯示放在棧上的前三個(gè)參數(shù),例如(L是不顯示源文件信息):
- 前兩列以及最后一列的內(nèi)容與k命令結(jié)果是一樣的
- 中間三列是函數(shù)的參數(shù) 只顯示三個(gè),如果要觀察第四個(gè)參數(shù)可以用 dd ebp+x014
- 這只是棧上的前三個(gè)參數(shù),如果函數(shù)的調(diào)用約定為fastcall,那么前兩個(gè)參數(shù)還是在ecx和edx
其他K系列的命令:
- kp命令可以把參數(shù)和參數(shù)值都以函數(shù)原型格式顯示出來(lái),但是需要有符號(hào),對(duì)于逆向來(lái)說(shuō)沒(méi)什么用
- kv命令可以在kb命令的基礎(chǔ)上增加顯示FPO信息和調(diào)用約定
- kn命令會(huì)在每行前顯示棧幀的序號(hào)
總結(jié)
| k | 顯示調(diào)用堆棧 |
| kb | 顯示調(diào)用堆棧和棧上的前三個(gè)參數(shù) |
| kp | 參數(shù)和參數(shù)值都以函數(shù)原型格式顯示出來(lái)(必須有符號(hào)) |
| kv | kb命令的基礎(chǔ)上增加顯示FPO信息和調(diào)用約定 |
| kn | 命令會(huì)在每行前顯示棧幀的序號(hào) |
分析內(nèi)存
顯示內(nèi)存
WinDBG的d系列命令用來(lái)顯示指定內(nèi)存區(qū)域的數(shù)據(jù)內(nèi)容。這些命令的格式為:
d{a|b|c|d|D|f|p|q|u|w|W} [Options] [Range] dy{b|d} [Options] [Range] d [Options] [Range]其中大括號(hào)中的字母(區(qū)分大小寫(xiě))用來(lái)指定數(shù)據(jù)的顯示方式,含義如下:
- a表示ASCII碼
- b表示字節(jié)和ASCII碼
- c表示DWORD和ASCII碼
- d表示DWORD
- D表示雙精度浮點(diǎn)數(shù)
- f表示單精度浮點(diǎn)數(shù)
- p表示按指針寬度顯示
- q表示四字(8字節(jié))
- u表示UNICODE字符
- w表示字
- W表示字和ASCII碼
- yb表示二進(jìn)制和字節(jié)
- yd表示二進(jìn)制和雙字
Range參數(shù)用來(lái)指定要顯示的內(nèi)存范圍。可以有以下幾種表示方法:
- 第一種方法是起始地址加空格加終止地址,比如dd 0012fd9c 0012fda8命令以雙字格式顯示從0012fd9c開(kāi)始到0012fda8結(jié)束的16字節(jié)內(nèi)存數(shù)據(jù)
- 第二種方法是起始地址加空格加L(或者1)和對(duì)象個(gè)數(shù),比如上面的命令可以等價(jià)的寫(xiě)為:dd 0012fd9c L4
- 第三種方式是結(jié)束地址加空格加L(或者1)加負(fù)號(hào)和對(duì)象個(gè)數(shù)。使用這種方式可以把上面的命令寫(xiě)為:dd 0012fdac L-4
顯示字符串
可以以0結(jié)尾的簡(jiǎn)單字符串,可以使用da或者du命令來(lái)顯它的內(nèi)容,前者用于使用單字節(jié)字符集的字符串,后者用于采用UNICODE字符集的字符串。當(dāng)遇到字符串末尾的0時(shí),會(huì)自動(dòng)停止顯示。例如:du 003a2e9c
顯示數(shù)據(jù)類型
WinDBG的dt命令用來(lái)顯示數(shù)據(jù)類型以及按照類型來(lái)顯示數(shù)據(jù)。Dt的含義是Dump symbolic Type information。Dt是個(gè)比較復(fù)雜的命令,下面我們按照用法分別來(lái)介紹
首先,可以使用dt來(lái)顯示一個(gè)數(shù)據(jù)類型(數(shù)據(jù)結(jié)構(gòu))。這種用法的典型格式是:
dt[模塊名!]類型名
其中模塊名部分可以省略,如果省略,那么調(diào)試器會(huì)自動(dòng)搜索所有模塊。類型名即程序中定義數(shù)據(jù)結(jié)構(gòu)或者通過(guò)typedef定義的類姓名。類型名中可以包含通配符,比如以下命令會(huì)列出NTDLL模塊中的所有類型:
dt ntdll!*
如果類型名是確定的類型,那么dt便會(huì)顯示這個(gè)類型的定義,如果類型中還包含子類型,那么可以用-b開(kāi)關(guān)來(lái)遞歸式顯示所有子類型,也可以使用-r開(kāi)關(guān)來(lái)指定顯示深度。-r0表示不顯示子類型,-r1表示顯示1級(jí)子類型,依此類推,例如:
dt -r1 _TEB
如果不想顯示整個(gè)結(jié)構(gòu),而只顯示某些字段,那么可以在類型名后使用-ny開(kāi)關(guān)附加字段搜索選項(xiàng),比如以下命令只顯示TEB結(jié)構(gòu)的LastError開(kāi)始的字段:
dt _TEB -ny LastError
Dt命令的第二種用法是在上一種方法的基礎(chǔ)上增加內(nèi)存地址,讓dt 按照類型顯示指定地址的變量。例如,以下命令使用_PEB結(jié)構(gòu)來(lái)顯示內(nèi)存地址7ffdd000出的數(shù)據(jù):
dt _PEB 7ffdd000
Dt命令的第三種用法是顯示類型的實(shí)例,包括全局變量、靜態(tài)變量和函數(shù)。比如以下命令顯示dbgee程序的g_szGlobal全局變量:
dt dbgee!*wmain*
搜索內(nèi)存
S命令用于搜索內(nèi)存,有三種使用方法。
-
第一種用法是在指定的內(nèi)存范圍內(nèi)搜索任何ASCⅡ字符或者UNICODE字符串,其格式如下:
- s-[[Flags]]sa|su Range
- Range用來(lái)指定內(nèi)存范圍
- sa用來(lái)搜索ASCII字符串 su用來(lái)搜索unicode字符串
- Flag可以指定搜索選項(xiàng)
例如,以下命令搜索nt!PsInitialSystemProcess變量所指向地址開(kāi)始的512個(gè)字節(jié)范圍內(nèi)任何長(zhǎng)度不小于5的ASCIⅡ字符串:
s-[l5]sa poi(nt!)PsInitialSystemProcessl200
-
第二種用法是在指定內(nèi)存地址范圍內(nèi)搜索與指定對(duì)象相同類型的對(duì)象,這里的對(duì)象是指包含虛擬函數(shù)表的使用面向?qū)ο笳Z(yǔ)言(如C++)編寫(xiě)的類(Class)對(duì)象。其格式為:
- s[[Flags]]v Range Object
-
S命令的第三種用法是在指定范圍內(nèi)搜索某一內(nèi)容模式,其語(yǔ)法格式為:
- s[-[[Flags]]Type] Range Pattern
- 其中類型表示搜索的內(nèi)容的數(shù)據(jù)類型(寬度),可以為b(字節(jié)) d(雙字)
- Pattern參數(shù)用來(lái)指定要搜索的內(nèi)容
如果你覺(jué)得上面一段話理解起來(lái)有點(diǎn)費(fèi)勁,不妨直接看下面的例子
s 0012ff40 L20 'H' 'e' 'l' 'l' 'o' s 0012ff40 L20 48 65 6c 6c 6f s -a 0012ff40 L20 "Hello"它們都是等效的。意為在0012ff40到0012ff60之間搜索hello字符,-a參數(shù)指定以ACSII的方式搜索字符,類似的還有-u,它指定以UNICODE的方式搜索字符
修改內(nèi)存
命令e用來(lái)修改指定內(nèi)置地址或者區(qū)域的內(nèi)容,
-
第一種是按字符串編輯,其命令格式為:
- e{a|u|za|zu}Address "String"
- 其中Address是要修改的內(nèi)存的起始地址
- za代表以0結(jié)尾的ASCII字符 zu代表以0結(jié)尾的Unicode字符
- a和u分別代表不是以0結(jié)尾的ASCII和Unicode字符
-
第二種用法是以數(shù)值方式編輯,其格式為:
- e{b|d|D|f|p|q|w} Address [Values]
- 其中大括號(hào)中的字母用來(lái)表示要修改的數(shù)據(jù)類型,也決定要修改的內(nèi)存方式
- Address用來(lái)指定要修改的內(nèi)存起始地址
- Values用來(lái)指定新的值
例如:
Eb 00100000 01 02 03 04 數(shù)據(jù)類型為BYTE Ed 00100000 0201 0403 數(shù)據(jù)類型為DWORD Ea 00100000 ‘hello’ 數(shù)據(jù)類型為ASCII Eu 00100000 ‘你好’ 數(shù)據(jù)類型為UNICODE其他命令
下表記錄了我個(gè)人認(rèn)為在調(diào)試時(shí)經(jīng)常會(huì)用到的一些命令,記錄的不全,歡迎補(bǔ)充
| .attach | .attach PID 附加到指定ID的進(jìn)程 |
| .restart | 重啟被調(diào)試應(yīng)用 |
| .cls | 清理屏幕 |
| .formats | 顯示數(shù)字的各種格式信息 |
| lm | 顯示模塊 |
| .reboot | 重啟虛擬機(jī) |
| r | 查看或修改寄存器 |
| u | 顯示匯編 |
| .help | 查看幫助 |
參考資料
《windbg用法詳解》
WinDbg命令三部曲
從Ollydbg說(shuō)起-----WinDbg用戶態(tài)調(diào)試教程:https://bbs.pediy.com/thread-34379.htm
總結(jié)
以上是生活随笔為你收集整理的Windbg新手入坑指南的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 160个Crackme023
- 下一篇: 160个Crackme024之Opcod