windbg命令熟悉

windbg命令分標準命令、元命令和擴展命令。

標準命令提供基本功能,不區分大小寫。比如dt、lm、g、bl、bc、p等。

提供標準命令沒有提供的功能,也內建在調試引擎中,以.開頭。如.sympath  .reload等。

 擴展命令用於擴展某一方面的調試功能,實現在動態加載的擴展模塊中,以!開頭。如!analyze等。

 使用;作爲分隔符,可以在同一行輸入多條命令。

一次可以執行多條命令,命令間用分號;分隔 【:bp main;bp `view.cpp:120`】,一次打2個斷點。

爲了保證windbg流暢運行,在調試時,儘量不要開啓Watch、Locals、Registers、Call Stack、Processes and Threads窗口,直接用command來獲取信息。

?   // 打印出所有標準命令

.help  // 打印出所有元命令

.hh  // 打開windbg的chm幫助文件

.hh bp  // 打開windbg的chm幫助文件bp命令介紹頁

command /?  // 打印命令command具體參數用法

*  // 註釋整行

$$ // 註釋(遇到分號結束)

配置調試環境

.sympath   // 查看當前符號查找路徑

.sympath c:\symbols   // 將符號查找路徑設爲:c:\symbols

.sympath+ c:\symbols  // 將c:\symbols添加到符號查找路徑集合中

.symfix // 將符號查找路徑設爲:SRV*WinDbg安裝目錄\Sym*http://msdl.microsoft.com/download/symbols

.symfix f:\symbols // 將符號查找路徑設爲:SRV*f:\symbols*http://msdl.microsoft.com/download/symbols

.symfix+ f:\symbols  // 將SRV*f:\symbols*http://msdl.microsoft.com/download/symbols添加到符號查找路徑集合中

.srcpath // 查看當前源文件查找路徑

.srcpath f:\src // 將源文件查找路徑設爲:f:\src

.srcpath+ f:\src  // 將f:\src添加到源文件查找路徑集合中

.exepath // 查看可執行文件查找路徑

.exepath f:\bin // 將可執行文件查找路徑設爲:f:\bin

.exepath+ f:\bin  // 將f:\bin添加到可執行文件查找路徑集合中

vertarget // os信息

!cpuid  // cpu信息


.effmach  // 查看當前調試mode:x86、x64等

.load wow64exts  // [!load wow64exts] 加載wow64exts.dll模塊  注:!sw就是wow64exts中的命令

.unload wow64exts  // [!unload wow64exts] 卸載wow64exts.dll模塊

!sw  // [!wow64exts.sw]  在多個mode:x86、x64上進行循環切換  注:如果win32程序在x64的mode下,會看到地址是64位的

!k  // [!wow64exts.k]  打印32位、64位堆棧

!k 5 // [!wow64exts.k 5]  打印32位、64位堆棧,棧幀個數爲5

!info // [!wow64exts.info]  輸出wow64相關的PEB、TEB和TLS基本信息

!r // [!wow64exts.r]  輸出處理器當前上下文信息

!r dumpTest!main  // [!wow64exts.r dumpTest!main]  輸出main函數地址的上下文信息

除了使用ld和.reload命令直接加載符號文件,某些使用符號的命令也可以觸發調試器來加載符號,如:棧回溯命令(k*)和反彙編命令(u)等。

值得說明的是,windbg缺省使用的是懶惰式符號加載策略,當它收到模塊加載事件時,它通常是不會加載符號的,符號狀態顯示爲deferred(延遲加載)。

.symopt // 顯示當前所有符號選項

.symopt+ flags // 添加符號選項

.symopt- flags // 刪除符號選項

!sym noisy   // 激活詳細符號加載(noisy symbol loading)顯示

!sym quiet   // 禁止詳細符號加載顯示

ld * // 爲所有模塊加載符號

ld kernel32 // 加載kernel32.dll的符號

.reload // 爲所有已加載模塊載入符號信息

.reload /i // 重新加載不匹配符號的模塊【dmp文件沒有對應的pdb時使用

.reload /i TGame.exe // 重新加載不匹配符號的TGame.exe

.reload /f /v // f:強制立即模式(不允許延遲載入)  v:詳細模式

.reload /f @"c:\windows\System32\verifier.dll" // 爲指定模塊加載符號信息

.reload /f TGame.exe // 爲TGame.exe加載符號信息

.chain  // 顯示已經加載進來的模塊

x *! // 列出所有模塊對應的符號信息

lm // 列出所有模塊(加載和未加載)對應的符號信息

lmv // 列出所有模塊(加載和未加載)對應的符號信息

lmvm ntdll  // 查看ntdll.dll的詳細信息(注意exe、dll等都不要帶後綴名)

x ConsoleTest!* // 列出ConsoleTest模塊中的所有符號

x ConsoleTest!add* // 列出ConsoleTest模塊中的所有add開頭的符號

x /t /v ConsoleTest!* // 帶數據類型、符號類型和大小信息,列出ConsoleTest模塊中的所有符號

x kernel32!*LoadLib* // 列出kernel32模塊中所有含LoadLib字樣的符號

|   // 列出調試進程

|*  // 列出調試進程

|N  // 參看序數爲N的調試進程

|Ns // 切換序數爲N的進程爲當前調試進程

~   // 列出線程

~*  // 所有線程

~* k // 所有線程堆棧信息

~* r // 所有線程寄存器信息

~.  // 查看當前線程

~0s // 查看主線程

~# // 查看導致當前事件或異常的線程

~N  // 查看序數爲N的線程

~~[n]  // 查看線程ID爲n的線程

~Ns   // 切換序數爲N的線程爲當前調試線程

~N f  // 凍結序數爲N的線程

~N u // 解凍序數爲N的線程

~N n  // Suspend序數爲N的線程

~N m // Resume序數爲N的線程

!runaway // 顯示所有線程的CPU消耗

bl   // 列出所有斷點

bc * // 清除所有斷點

bc 1 // 清除1號斷點

bc 1 2 5  // 清除1號、2號、5號斷點

be *  // 啓用所有斷點

be 1  // 啓用1號斷點

be 1 2 5 // 啓用1號、2號、5號斷點

bd *  // 禁用所有斷點

bd 1  // 禁用1號斷點

bd 1 2 5 // 禁用1號、2號、5號斷點

bp 7c801b00  // 在7c801b00地址處放置一個斷點

bp `ConsoleTest.cpp:36`  // 在ConsoleTest.cpp的36行處放置一個斷點

bp main // 在main函數的起始處放置一個斷點

bp CSecondLoader::CSecondLoader  // 在CSecondLoader的構造函數處放置一個斷點

bp TestCommon! CTest::add  // 在TestCommon.dll的Test.cpp文件的CTest::add()函數起始處放置一個斷點

bp `ConsoleTest.cpp:40` "j (poi(pVar)>5) '''g'" // j爲條件表示式:條件斷點 pVar指針指向的值>5,執行空語句;,斷住  否則繼續執行

bp `ConsoleTest.cpp:40` "j @eax = 0xa3 ''; 'g'" // j爲條件表示式:條件斷點 寄存器eax的值爲0xa3時斷住

bp kernel32!CreateFileA  // 在系統API的CreateFileA函數處放置一個斷點

bp kernel32!CreateFileA ".echo;.printf\"CreateFileA(%ma,%p,%p), ret=\",poi(esp+4),dwo(esp+8),dwo(esp+c);gu;.printf\"%N\",eax;.echo;g" // 不斷住進程情況下,打印所有的CreateFileA調用

bp advapi32!RegOpenKeyExA ".echo;.printf\"RegOpenKeyExW(%p,\\\"%ma\\\",%N,%N,%p) returned: \", dwo(esp+4), poi(esp+8), dwo(esp+c), dwo(esp+10), dwo(esp+14);gu;.printf\"%N\",eax;.echo;g"  // 不斷住進程情況下,打印所有的RegOpenKeyExA調用(打開註冊表鍵值)

bu  // 保存斷點,其用法和bp一樣

bm add_*  // 匹配add_開頭的函數,並在這些函數起始處都打上斷點

ba w4 0483dfe0 // 當對0483dfe0地址寫操作時停下

                          // ba [r|w|e] [Size] Addr      [r=read/write, w=write, e=execute], Size=[1|2|4 bytes]

g  // Go(F5)

gH // 執行gH命令強制讓調試器返回已經處理了這個異常。【Go with Exception Handled

     // 系統收到這個回覆後會停止分發異常(因爲調試器聲稱已經處理了異常),恢復調試目標繼續執行,

     //  但由於異常條件仍在,所以還會產生異常,於是再次分發,WinDBG再次中斷到命令模式。

gN // Go with Exception Not Handled

     // 執行gN命令強制讓調試器返回沒有處理了這個異常,那麼系統會進一步分發該異常,

     // 如果沒有其他調試器也不處理,最後系統會彈出程序終止對話框。

gu  // 執行到當前函數完成時停下 【Go Up

Ctrl+Break  // 暫停正在運行的程序

p    // 單步執行(F10)  【Step

p 2 // 2爲步進數目

pc   // 執行到下一個函數調用處停下 【Step to  Next Call

pa 7c801b0b // 執行到7c801b0b地址處停下  【Step to Adress

t     // Step into(F11) 【Trace

tc    // 執行到下一個進入點處停下 【Trace to Next Call

ta 7c801b12  // 執行到7c801b12地址處停下 【Trace to Adress

!handle  // 查看所有句柄的ID

!handle 000007f8 1  // 查看ID爲000007f8的句柄的類型

!handle 000007f8 4  // 查看ID爲000007f8的句柄的名稱

!handle 0 5  // 查看所有句柄的類型和名稱


===  0n(十進制)  0x(十六進制)  0t(8進制)  0y(2進制)    可以使用n [8|10|16]命令來修改數值進製表示方式(輸入n可查看當前進制,默認爲16進制)===

dt nRet  // 查看局部變量nRet的類型與值(函數參數變量請用dv命令)

dt myApp!g_app // 表示顯示myApp進程裏全局變量g_app的內存佈局

dt WindbgTest!CTest // 查看模塊WindbgTest的CTest的內存佈局

dt WindbgTest!CTest 0x0041f8d4  // 將0x0041f8d4地址處內容按照模塊WindbgTest的CTest的內存佈局來解析

Windbg默認會用寄存器ECX裏面的值作爲this指針地址,其實這樣是有時候是錯誤的。
有些C++編譯器在做代碼優化之後會把 this指針放在其他寄存器裏面,比如ESI。 
所以在調試的時候還需要讀一下彙編代碼來確定this 在哪個寄存器裏面。
比如我們看到 MOV EAX, dword ptr [ESI + 0x48h](獲取當前對象內存偏移爲0x48h處的4字節成員變量),就可以判斷ESI 是this 指針。
這時可以通過如下命令打印this的內存結構:dt -b 模塊名!類名 @esi

t this // 查看this指針的類型及成員變量

dt -b this  // 查看this指針的類型及成員變量,如果某一成員變量爲結構體,則把其結構成員也一一打印出來

dt _PEB @$PEB // 查看PEB(process's environment block)內存結構

?? this->m_nPen  // 查看成員變量的值(注:vc6見上述說明)

?? this // 查看this指針中的成員變量(注:vc6見上述說明)

? nCount // 顯示局部變量nCount的地址(前面4198608爲10進製表示地址,004010d0爲16進製表示地址) 形如:Evaluate expression: 4198608 = 004010d0

? HeapTest!CTest::Add  // 顯示HeapTest模塊中CTest類中的Add函數地址

dv   // 顯示當前函數內所有局部變量,函數參數的值

dv n*  // 顯示當前函數內n開頭的所有局部變量,函數參數的值

dv nCount // 查看局部變量nCount的值

dv a // 查看函數參數變量a的值

dv /t /i /V /a|/n|/z


/***************************************** 

更加詳細地顯示當前函數內所有局部變量,函數參數信息
i = type (local, global, parameter)
t = data type
V = memory address or register location
-----------------------
a = sort by Addr, n = sort by name, z = sort by size

*****************************************/

x  // 用法和dv命令一致,顯示當前函數內所有局部變量,函數參數的地址與值


調用堆棧

k  // 顯示當前調用堆棧

kn // 帶棧編號顯示當前調用堆棧

kb  // 打印出前3個函數參數的當前調用堆棧

02a9ffec 00000000 01e511f9 0174c570 00000000 kernel32!BaseThreadStart+0x37
----------------------------------------------
kernel32!BaseThreadStart+0x37 這個是函數地址。
01e511f9 0174c570 00000000 這是前三個參數。注:如果是成員函數,this指針通過ecx來傳遞
02a9ffec 00000000是 ebp 和 返回地址。

kb 5 // 只顯示最上的5層調用堆棧

kv   // 在kb的基礎上增加了函數調用約定等信息

kp  // 顯示每一層函數調用的完整參數,包括參數類型、名字、取值(必須是完整符號的情況下,private symbols);注意:若程序被優化,這些值不一定對

kd  // 打印堆棧的地址

.frame // 顯示當前棧幀

.frame n // 設置編號n的棧幀爲當前棧幀

.frame /r n // 設置編號n的棧幀爲當前棧幀 並顯示寄存器變量

!uniqstack // 顯示所有線程的調用堆棧

查看彙編

u .  // 反彙編當前ip寄存器地址的後8條指令

u $ip  // 反彙編當前ip寄存器地址的後8條指令

ub .  // 反彙編當前ip寄存器地址的前8條指令

ub $ip  // 反彙編當前ip寄存器地址的前8條指令

u main+0x29 L30 // 反彙編main+0x29地址的後30條指令

u  // 反編譯下8條指令

uf CTest::add  // 反彙編CTest類的add函數

uf /c main  // 反彙編main函數,通過/c可以查看main函數中的函數調用(call)都有哪些

ub 000c135d L20  // 查看地址爲000c135d指令前的20條指令內容

函數調用如果還沒開始,即一般函數入口代碼
push ebp
mov ebp, esp
還未執行,則[esp+4]表示第一參數值, [esp+8]表示第二參數,以此類推, [esp]表示的是返回地址
如果上面的入口代碼已經執行,則一般通過ebp來獲取函數參數和局部變量
[ebp+8]表示第一參數, [ebp+0xC]表示第二個參數,以此類推
[ebp+4]表示返回地址 [ebp]表示上一堆棧楨的基地址 [ebp-4]表示函數第一個局部變量

 

寄存器

r // 顯示所有寄存器信息及發生core所在的指令

r eax, edx // 顯示eax,edx寄存器信息

r eax=5, edx=6  // 對寄存器eax賦值爲5,edx賦值爲6

內存

!address 7ffd8000  // 查看7ffd8000地址處內存頁屬性

dd /c 5 7c801e02  // 從7c801e02內存處開始以dword爲單位顯示內存(寬度爲:5)【默認顯示128字節長度的內容】

dd /c 5 7c801e02 L8  // 從7c801e02內存處開始以dword爲單位顯示內存(寬度爲:5)【顯示8個dword】

da /c 100 7c80ff03  // 從7c80ff03內存處開始顯示Ascii字符串(寬度爲:100)

du /c 100 7c8022f5  // 從7c8022f5內存處開始顯示Unicode字符串(寬度爲:100)

/*****************************************

d[a| u| b| w| W| d| c| q| f| D] [/c 列數] [地址]

a = ascii chars
u = Unicode chars
b = byte + ascii
w = word (2b)
W = word (2b) + ascii
d = dword (4b)
c = dword (4b) + ascii
q = qword (8b)
f = floating point (single precision - 4b)
D = floating point (double precision - 8b)

****************************************


dyb /c 3 7c801e02  // 從7c801e02內存處開始,顯示byte及二進制(寬度爲:3)

/*****************************************

dy[b | d] ..   // b = binary+byte     d = binary+dword

*****************************************/

s -w 522e0000 L0x100  0x1212 0x2212 0x1234 // 表示在起始地址522e0000之後的0x100個單位內搜索0x1212 0x2212 0x1234系列的起始地址

s -u 522e0000 527d1000 "web"  //表示在522e0000 和527d1000之間搜索Unicode 字符串”web”

ea 0x445634 "abc"  // 表示在0x445634地址寫入Ascii字符串abc, 不包含結束符0

eza 0x445634 "abc"  // 表示在0x445634地址寫入Ascii字符串abc, 包含結束符0

eu 0x445634 "abc"  // 表示在0x445634地址寫入Unicode字符串abc, 不包含結束符0

ezu 0x445634 "abc"  // 表示在0x445634地址寫入Unicode字符串abc, 包含結束符0

ed nCounter 80  // 將變量nCounter的值修改爲80(注:80爲10進制還是16進制,還是其他,取決於當前進制)

#查看堆(Heap)

!heap -s  // 顯示進程堆的個數(每一項是一個堆,也就是_HEAP結構指針,對應的API是HeapCreate)

Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast 
(k) (k) (k) (k) length blocks cont. heap 
-----------------------------------------------------------------------------
00140000 50000062 1024 12 12 1 1 1 0 0 L 
00240000 50001062 64 24 24 15 1 1 0 0 L 
00250000 50008060 64 12 12 10 1 1 0 0 
00380000 50001063 64 12 12 4 2 1 0 bad 
-----------------------------------------------------------------------------

dt _HEAP 00140000  // 選取一個堆的地址,打印該堆的內存結構

ntdll!_HEAP
+0x000 Entry : _HEAP_ENTRY
+0x008 Signature : 0xeeffeeff
+0x00c Flags : 0x50000062
+0x010 ForceFlags : 0x40000060
+0x014 VirtualMemoryThreshold : 0xfe00
+0x018 SegmentReserve : 0x100000
+0x01c SegmentCommit : 0x2000
+0x020 DeCommitFreeBlockThreshold : 0x200
+0x024 DeCommitTotalFreeThreshold : 0x2000
+0x028 TotalFreeSize : 0xaf
+0x02c MaximumAllocationSize : 0x7ffdefff
+0x030 ProcessHeapsListIndex : 1
+0x032 HeaderValidateLength : 0x608
+0x034 HeaderValidateCopy : (null) 
+0x038 NextAvailableTagIndex : 0
+0x03a MaximumTagIndex : 0
+0x03c TagEntries : (null) 
+0x040 UCRSegments : (null) 
+0x044 UnusedUnCommittedRanges : 0x00140598 _HEAP_UNCOMMMTTED_RANGE
+0x048 AlignRound : 0x17
+0x04c AlignMask : 0xfffffff8
+0x050 VirtualAllocdBlocks : _LIST_ENTRY [ 0x140050 - 0x140050 ]
+0x058 Segments : [64] 0x00140640 _HEAP_SEGMENT
+0x158 u : __unnamed
+0x168 u2 : __unnamed
+0x16a AllocatorBackTraceIndex : 0
+0x16c NonDedicatedListLength : 1
+0x170 LargeBlocksIndex : (null) 
+0x174 PseudoTagEntries : (null) 
+0x178 FreeLists : [128] _LIST_ENTRY [ 0x142a90 - 0x142a90 ]
+0x578 LockVariable : 0x00140608 _HEAP_LOCK
+0x57c CommitRoutine : (null) 
+0x580 FrontEndHeap : 0x00140688 Void
+0x584 FrontHeapLockCount : 0
+0x586 FrontEndHeapType : 0x1 ''
+0x587 LastSegmentIndex : 0 ''

!heap -a 00140000 // 選取一個堆的地址,打印該堆的信息,比上面打印內存命令更詳細直觀



設置事件發生時windbg行爲

sx // 顯示windbg遇到每個異常和事件時的行爲

sxr // 將所有異常和事件過濾器的狀態重設爲默認值

sxe  ld // 當加載模塊時,立即中斷(Break)到調試器中(第一次處理機會)

sxe ud // 當卸載模塊時,windbg不會在第一次處理機會時中斷(雖然會顯示信息)。如果其他錯誤處理器沒有處理掉該異常,執行會停止下來並中斷(Break)到windbg中(第二次處理機會)

sxn et // 當線程退出時,windbg會打印出一條消息

sxi ct // 當線程創建時,windbg不中斷也不打印消息

dump輸出

 .dump /ma "d:\mydmpfile.dmp" // 將當前調試進程輸出Dump文件


其他元命令

.tlist  // 顯示所有進程

.cls  // 清除屏幕

.logopen c:\1.log   // 將command內容輸出到c:\1.log文件中

其他擴展命令

!analyze -v  // 詳細顯示當前異常信息

!peb // 格式化輸出PEB信息(process's environment block)

!gle  // 打印當前線程最近的錯誤信息LastError

!gle -all  // 打印所有線程的最近的錯誤信息

!error  897// 顯示錯誤碼爲897的詳細描述信息

幫助:

  1. http://www.dbgtech.net/windbghelp/index.html
  2. windbg cmd: http://www.slideshare.net/kewuc/windbg-cmds
  3. http://www.cnblogs.com/gaochundong/p/windbg_cheat_sheet.html


發佈了96 篇原創文章 · 獲贊 7 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章