轉載收藏於:http://www.cnblogs.com/kekec/archive/2012/12/02/2798020.html
#調試命令窗口
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#使用gflags.exe工具(在windbg所在目錄下),讓某個進程啟動時,拉取windbg進行調試
如下截圖:當名稱為captcomm.exe的進程啟動時,拉起windbg調試
也可通過腳本命令來實現:
// 運行captcomm.exe時,啟動windbg調試 reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\captcomm.exe" /v Debugger /t REG_SZ /d "C:\Program Files\Debugging Tools for Windows (x86)\windbg.exe" /f // 解除啟動時windbg調試 reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\captcomm.exe" /f // 64位系統上,也可以設置以下注冊表節點 reg add "HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\captcomm.exe" /v Debugger /t REG_SZ /d "C:\Program Files\Debugging Tools for Windows (x86)\windbg.exe" /f // 解除啟動時windbg調試 reg delete "HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\captcomm.exe" /f // 測試發現:HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options和HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options指向的是同一數據,修改其中任何一個都可以
安全軟件可能會禁止修改注冊表的Image File Execution項:
-- 對於360安全衛士,在“設置”中去掉“開啟360自我保護”的勾選來關閉
-- 對於McAfee,需要禁止IPS(Intrusion Prevension Systems)。
-- 然而,電腦管家,則不會對該鍵值的注冊表修改進行阻止。
#重要說明
(1) windbg命令分為標准命令,元命令和擴展命令。
標准命令提供最基本的調試功能,不區分大小寫。如:bp g dt dv k等
元命令提供標准命令沒有提供的功能,也內建在調試引擎中,以.開頭。如.sympath .reload等
擴展命令用於擴展某一方面的調試功能,實現在動態加載的擴展模塊中,以!開頭。如!analyze等
(2) 進入調試狀態時,直接回車可重復執行上一條命令;按上下方向鍵可以瀏覽和選擇以前輸入過的命令
(3) 神奇的Tab鍵,進行命令補全;ESC清除當前命令輸入框中的文本
(4) 選擇Command窗口中的內容,然后右擊進行復制
(5) 使用;作為分隔符,可以在同一行輸入多條命令
(6) 上圖紅色框中的“0:000”。【0為當前調試會話的進程號;000為調試會話的線程號】
(7) 當命令提示符顯示*BUSY*時,即使命令輸入框可以輸入命令,但輸入的命令不會立即被執行,要等windbg空閑時才能執行。
可使用Ctrl + Break來終止一個長時間未完成的命令
(8) 一次可以執行多條命令,命令間用分號;分隔 【如:bp main;bp `view.cpp:120`】,一次打2個斷點
(9)按Ctrl + Alt + V開啟/關閉verbose Output(詳細輸出模式)
(10) 為了保證windbg流暢運行,在調試時,盡量不要開啟Watch、Locals、Registers、Call Stack、Processes and Threads窗口,直接用command來獲取信息
#啟動調試
windbg -I // 將windbg設置成默認調試器
windbg "notepad.exe" arguments // 使用windbg啟動調試notepad.exe
windbg -p 4200 // 將windbg附加到一個正在運行的pid為4200的進程上
windbg -pn "notepad.exe" // 將windbg附加到一個正在運行的名為notepad.exe的進程上
windbg -p 4200 -c "sxd av;sxi c0000005;sxi c0000008;g" // 將windbg附加到一個正在運行的pid為4200的進程上,附加成功后,執行sxd av;sxi c0000005;sxi c0000008;g命令
windbg –z "c:\mydumpfile.dmp" // 調試mydumpfile.dmp文件
.opendump "c:\mydumpfile.dmp" // 調試mydumpfile.dmp文件
windbg -y d:\mySymbols // 指示symbol路徑
windbg -srcpath d:\Src // 指示源文件路徑
windbg -i d:\myApp //指示exe、dll等可執行模塊路徑
.attach 0n4220 // 4220為十進制pid,使用該命令附加調試時,必須先存在一個調試會話
.detach // 分離調試
.restart // 重啟並調試
.kill // 強制結束當前調試
q // 結束當前調試會話,回到基礎工作空間,並結束調試進程
qd // 結束當前調試會話,回到基礎工作空間,但不結束調試進程
CTRL+ALT+V // 打開或關閉 Verbose 模式開關,某些命令在此模式下可以給出更多詳細信息
.time // 調試會話時間信息
.lastevent // 顯示最新的異常信息或事件信息
version // 顯示windbg和已加載的調試器擴展相關的信息
vercommand // 顯示windbg的啟動路徑及命令行信息
.chain // 顯示已經加載進來的調試器擴展
.extmatch /D /e wow64exts * // 顯示wow64exts調試器擴展中的命令
#獲取幫助
? // 打印出所有標准命令
.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 注:必須勾選上菜單“Debug”-“Source Mode”;另外pdb須與exe、dll等執行模塊匹配上
.srcpath+ f:\src // 將f:\src添加到源文件查找路徑集合中
.exepath // 查看可執行文件查找路徑
.exepath f:\bin // 將可執行文件查找路徑設為:f:\bin
.exepath+ f:\bin // 將f:\bin添加到可執行文件查找路徑集合中
#系統信息
vertarget // os信息
!cpuid // cpu信息
#wow64模式 【x64版windbg調試win32程序】
.load wow64exts // [!load wow64exts] 加載wow64exts.dll模塊 注:!sw就是wow64exts中的命令
.unload wow64exts // [!unload wow64exts] 卸載wow64exts.dll模塊
.effmach // 查看當前調試mode:x86、x64等
.effmach x86 // 切換到x86棧環境 注:需要先執行.load wow64exts來加載wow64exts.dll模塊
.effmach . // 切換回x64
!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函數地址的上下文信息
注 -- 32位windbg無法打開64位應用程序,會提示如下錯誤:
注 -- 32位windbg無法attach上64位應用程序,會提示如下錯誤:
#符號加載與查看
除了使用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加載符號信息
.reload /u TGame.exe // 卸載TGame.exe及其載符號信息
x *! // 列出所有模塊對應的符號信息
lm // 列出所有模塊(加載和未加載)對應的符號信息
lmv // 列出所有模塊(加載和未加載)對應的符號信息
lmvm ntdll // 查看ntdll.dll的詳細信息(注意exe、dll等都不要帶后綴名)
!lmi ntdll // 查看ntdll.dll的詳細信息(注意exe、dll等都不要帶后綴名)
!dlls -l // 按照加載順序(默認項)列出所有加載的模塊
!dlls -i // 按初始化順序列出所有加載的模塊
!dlls -v -c ntdll // 查看ntdll.dll的詳細信息(注意exe、dll等都不要帶后綴名)
ln 0x65777588 // 查看地址0x65777588處或附近的符號信息
x ConsoleTest!* // 列出ConsoleTest模塊中的所有符號
x ConsoleTest!add* // 列出ConsoleTest模塊中的所有add開頭的符號
x /t /v ConsoleTest!* // 帶數據類型、符號類型和大小信息,列出ConsoleTest模塊中的所有符號
x kernel32!*LoadLib* // 列出kernel32模塊中所有含LoadLib字樣的符號
!itoldyouso mono D:\mySymbols\mono.pdb // 查看mono.dll與D:\mySymbols\mono.pdb符號是否匹配上
0:000> !itoldyouso mono D:\mySymbols\mono.pdb
mono.dll
Timestamp: 559AAA60
SizeOfImage: 230000
pdb: C:\buildslave\mono-runtime-and-classlibs\build\builds\embedruntimes\win32\mono.pdb
pdb sig: 728334C1-72C3-4A51-B310-C44087FC4B2E
age: 1
mono.pdb
pdb sig: 728334C1-72C3-4A51-B310-C44087FC4B2E
age: 1
MATCH: mono.pdb and mono.dll
-------------------------------------------------------------------------
使用windbg提供的symchk.exe工具來查找模塊的pdb
symchk.exe Paladins.exe /v /s .\ //在當前目錄查找Paladins.exe的pdb,/s后面指定搜索路徑 帶上/v會輸出詳細的log
如果匹配上,會顯示如下log:
[SYMCHK] [ 0x00000000 - 0x001f0001 ] Checked "G:\TGame\symbols\ClientPackaging\Paladins.exe" SYMCHK: FAILED files = 0 SYMCHK: PASSED + IGNORED files = 1
沒有匹配上,則顯示log為:
SYMCHK: Paladins.exe FAILED - ShippingPC-ChaosGameTencent.pdb mismatched or not found SYMCHK: FAILED files = 1 SYMCHK: PASSED + IGNORED files = 0
#進程
| // 列出調試進程
|* // 列出調試進程
|N // 參看序數為N的調試進程
|Ns // 切換序數為N的進程為當前調試進程
!dml_proc // 顯示當前進程信息
#線程
~ // 列出線程
~* // 所有線程
~* k // 所有線程堆棧信息
~* r // 所有線程寄存器信息
~. // 查看當前線程
~0s // 查看主線程
~# // 查看導致當前事件或異常的線程
~N // 查看序數為N的線程
~~[n] // 查看線程ID為n的線程 n為16進制
~Ns // 切換序數為N的線程為當前調試線程
~~[n]s // 切換線程ID為n的線程為當前調試線程 n為16進制
~N f // 凍結序數為N的線程
~N u // 解凍序數為N的線程
~N n // Suspend序數為N的線程
~N m // Resume序數為N的線程
~* e !gle // 顯示所有線程最后的一個錯誤信息 e后可以為任意windbg命令
.ttime // 查看當前線程時間信息
!runaway //顯示當前進程的所有線程用戶態時間信息
!runaway f //顯示當前進程的所有線程用戶態、內核態、存活時間信息
!locks // 顯示死鎖
!cs // 列出CriticalSection(臨界段)的詳細信息
#斷點
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 MyDll+0x1032 // 在模塊MyDll.dll偏移0x1032處放置一個斷點
bp `ConsoleTest.cpp:36` // 在ConsoleTest.cpp的36行處放置一個斷點
bp main // 在main函數的起始處放置一個斷點
bp @$exentry // 在進程的入口放置一個斷點
bp CSecondLoader::CSecondLoader // 在CSecondLoader的構造函數處放置一個斷點
bp TestCommon! CTest::add // 在TestCommon.dll的Test.cpp文件的CTest::add()函數起始處放置一個斷點
bp `ConsoleTest.cpp:40` ".if (poi(pVar)>5) {}; {g}" // ".if (Condition) {Optional Commands}; {g}" 條件斷點 pVar指針指向的值>5,執行空語句(;),斷住 否則繼續執行
bp `ConsoleTest.cpp:40` "j (poi(pVar)>5) ' '; 'g'" // "j (Condition) 'Optional Commands'; 'g'" j為條件表示式:條件斷點 pVar指針指向的值>5,執行空語句(;),斷住 否則繼續執行
注:Condition表達式語法默認的是MASM表達式語法。使用復雜C++表達式時我們需要用@@c++()將表達式包圍住;如:"j @@c++(*pVar>5) ' '; 'g'"
---------------------------------
x表示的一個地址
hi(x) 高16 bits
low(x) 低16 bits
by(x) 返回第一個byte
wo(x) 返回第一個word
dwo(x) 返回第一個dword
qwo(x) 返回第一個4 word(Quad-word)
poi(x) 返回第一個指針所指向的值
---------------------------------
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 kernel32!CreateFileW ".echo;.printf\"CreateFileW(%mu,%p,%p), ret=\",poi(esp+4),dwo(esp+8),dwo(esp+c);kn;g;" // 不斷住進程,打印所有的CreateFileW調用及堆棧信息
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調用(打開注冊表鍵值)
---------------------------------
注意:有些函數Symbol Name與導出函數名可能不一致,例如SetWindowPos,這時可以用Dependency查看相應的導出函數地址(Entry Point列):0x00018E5E,然后在windbg菜單“Debug”—〉“Modules...”對話框中獲得user32.dll模塊起始地址0x77d10000,在兩個值相加后的絕對地址處直接設置斷點:bp 77d28E5E;也可以通過x user32!*命令列出全部Symbols列表,查找77d28E5E,找到SetWindowPos對應的Symbol Name為“NtUserSetWindowPos”,然后通過符號設置斷點:bp user32!NtUserSetWindowPos。通過符號設置斷點的好處是當dll代碼改變時,不需要修改,windbg會根據符號來自動匹配函數地址。
---------------------------------
bu // 保存斷點,其用法和bp一樣
bm add_* // 匹配add_開頭的函數,並在這些函數起始處都打上斷點
ba w4 0x0483dfe0 // 當對0483dfe0地址寫操作時停下,前面要帶上0x,否則會報錯
// ba [r|w|e] [Size] Addr [r=read/write, w=write, e=execute], Size=[1|2|4 bytes]
windbg無參腳本
// 當CreateFileW讀取UnityLockfile文件時斷住進程,在命令輸入框輸入:$$><d:\CreateFileWNoArguScript.txt,CreateFileWNoArguScript.txt內容如下:
bp kernel32!CreateFileW "
r $t1=poi(esp+4)
as /mu $FileName $t1
.echo
.printf\"File:%mu\",$t1
.echo
.block
{
.if($spat(\"${$FileName}\",\"*UnityLockfile\"))
{
.echo 'find...';
ad ${/v:$FileName}
}
.else
{
.echo no find...
ad ${/v:$FileName}
gc
}
}"
windbg有參腳本
// 當CreateFileW讀取mscorlib.dll文件時斷住進程,在命令輸入框輸入:$$>a<d:\CreateFileWArguScript.txt mscorlib.dll,CreateFileWArguScript.txt內容如下:
bp kernel32!CreateFileW " r $t1=poi(esp+4) as /mu $FileName $t1 .echo .printf\"File:%mu\",$t1 .echo .block { .if($spat(\"${$FileName}\",\"*${$arg1}\")) { .echo 'find...'; ad ${/v:$FileName} } .else { .echo no find... ad ${/v:$FileName} gc } }"
#調試執行控制
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 // 執行到下一個進入點(Call指令)處停下 【Trace to Next Call】
tb // 執行到分支指令停下【分支指令包括calls、returns、jumps、loops】
ta 7c801b12 // 執行到7c801b12地址處停下 【Trace to Adress】
WT Trace and Watch Data,一條強大指令,對執行流程做Profile
# 查看句柄
!handle // 查看所有句柄的ID
!handle 000007f8 1 // 查看ID為000007f8的句柄的類型
!handle 000007f8 4 // 查看ID為000007f8的句柄的名稱
!handle 0 5 // 查看所有句柄的類型和名稱
!htrace -enable // 使用windbg調試運行時,啟用跟蹤所有打開句柄或關閉句柄的調用以及相應的棧回溯
!htrace // 進程運行結束后,打印所有打開句柄或關閉句柄的調用以及相應的棧回溯
!htrace -diff // 只打印沒有關閉的句柄的信息及棧回溯
Handle = 0x00000038 - OPEN
Thread ID = 0x00001f34, Process ID = 0x00000638
0x049ca83c: +0x049ca83c
0x049d5eb4: +0x049d5eb4
0x046c8313: +0x046c8313
0x76d2d90a: +0x76d2d90a
0x7451c1ff: +0x7451c1ff
0x7450d18f: +0x7450d18f
0x74492776: +0x74492776
0x7450d286: +0x7450d286
0x7450c69e: +0x7450c69e
0x76d210d6: +0x76d210d6
0x76d7dc30: +0x76d7dc30
0x76d0b17e: +0x76d0b17e
0x76ee0166: ntdll!NtCreateFile+0x00000012
0x7542c76b: KERNELBASE!CreateFileW+0x0000035e
0x752c3f66: kernel32!CreateFileW+0x0000004a
0x752c53c4: kernel32!CreateFileA+0x00000036
--------------------------------------
Parsed 0x1 stack traces.
Dumped 0x1 stack traces.
# 查看變量
=== 0n(十進制) 0x(十六進制) 0t(8進制) 0y(2進制) 可以使用n [8|10|16]命令來修改數值進制表示方式(輸入n可查看當前進制,默認為16進制)===
-- VC6.0的Link選項需要將/pdbtype:sept改為/pdbtype:con, 否則生成的pdb文件中將不包含如自定義結構體,類等信息
dt nRet // 查看局部變量nRet的類型與值(函數參數變量請用dv命令) --注:編譯器很多時候會把一些局部變量優化掉,這個時候就會出現找不到nRet符號的情況
dt ntdll!* // 顯示ntdll里的所有類型信息
dt *!*IMAGE_DOS* // 顯示所有模塊中含有IMAGE_DOS字符的類型信息
test1!IMAGE_DOS_HEADER
test1!PIMAGE_DOS_HEADER
test1!_IMAGE_DOS_HEADER
ntdll!_IMAGE_DOS_HEADER
ntdll32!_IMAGE_DOS_HEADER
MSVCR90D!IMAGE_DOS_HEADER
MSVCR90D!PIMAGE_DOS_HEADER
MSVCR90D!_IMAGE_DOS_HEADER
dt myApp!g_app // 表示顯示myApp進程里全局變量g_app的內存布局(注:vc6見上述說明)
dt WindbgTest!CTest // 查看模塊WindbgTest的CTest的內存布局,加上-b -r參數可以顯示內部類及數組的信息(注:vc6見上述說明)
dt WindbgTest!CTest 0x0041f8d4 // 將0x0041f8d4地址處內容按照模塊WindbgTest的CTest的內存布局來解析(注:vc6見上述說明)
Windbg默認會用寄存器ECX里面的值作為this指針地址,其實這樣是有時候是錯誤的。
有些C++編譯器在做代碼優化之后會把 this指針放在其他寄存器里面,比如ESI。
所以在調試的時候還需要讀一下匯編代碼來確定this 在哪個寄存器里面。
比如我們看到 MOV EAX, dword ptr [ESI + 0x48h](獲取當前對象內存偏移為0x48h處的4字節成員變量),就可以判斷ESI 是this 指針。
這時可以通過如下命令打印this的內存結構:dt -b 模塊名!類名 @esi
dt tagMSG 0x0336e54c // 類型要使用tagMSG,不能使用typedef產生出的MSG
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG, *PMSG;
dt this // 查看this指針的類型及成員變量(注:vc6見上述說明)
dt -b this // 查看this指針的類型及成員變量,如果某一成員變量為結構體,則把其結構成員也一一打印出來
// -b開關指定遞歸顯示所有子類型信息,-r[n]指定遞歸顯示的深度,如-r0表示不顯示子類型信息
dt -v _PEB @$PEB // 使用詳細模式查看PEB(process's environment block)內存結構
dt _TEB ny LastErrorValue // 只查看TEB(thread's environment block)結構成員LastErrorValue
?? 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 當前函數kernel32!BaseThreadStart執行的指令地址。
01e511f9 0174c570 00000000 參數相關的數值【從左到右 -- 參數1 參數2:offset為sizeof(參數1) 參數3:offset為sizeof(參數1)+sizeof(參數2) ...】。注:如果是成員函數,this指針通過ecx或其他寄存器來傳遞
02a9ffec 00000000是 當前函數ebp 和 上層函數返回地址。
======================================================
Windows 7 Ultimate Service Pack 1 [Build 6.1.7601]
CPU: Intel(R) Core(TM) i3-2100 CPU @ 3.10GHz
《Game》 20.15.1112 6EF76A43E6B1DD58907F3E066506E918
----------------------------------------
Type: EXCEPTION_ACCESS_VIOLATION//非法地址訪問異常
Error: Read address 0x00074685//讀取0x00074685地址出錯(該地址對應的內存頁,進程無讀取權限)
Address: 64DCAF68//崩潰發生的指令地址
CallStack:
//0x64D90000為模塊MSVCR90.dll的基地址,3AF68為崩潰指令在模塊中的偏移值,(0492B5D0,00074685,0000000C,00462482)為參數信息
0x64D90000[3AF68] MSVCR90.dll: (0492B5D0,00074685,0000000C,00462482)
0X00400000[11158A] tgame.exe: (0492B5D0,00074685,00000000,00000000)
kb 5 // 只顯示最上的5層調用堆棧
kv // 在kb的基礎上增加了函數調用約定、FPO等信息
kp // 顯示每一層函數調用的完整參數,包括參數類型、名字、取值(必須是完整符號的情況下,private symbols);注意:若程序被優化,這些值不一定對
kd // 打印堆棧的地址
kD // 從當前esp地址處,向高地址方向搜索符號(注:函數是符號的一種)
dds 02a9ffec // 從02a9ffec地址處,向高地址方向搜索符號(注:函數是符號的一種)
dds // 執行完dds 02a9ffec后,可通過dds命令繼續進行搜索
.frame // 顯示當前棧幀
.frame n // 顯示編號為n的棧幀(n為16進制數)
.frame /r n // 顯示編號n的棧幀(n為16進制數) 並顯示寄存器變量
.frame /c n // 設置編號n的棧幀為當前棧幀(n為16進制數)
!uniqstack // 顯示所有線程的調用堆棧
!findstack kernel32 2 // 顯示包含kernel32模塊(用星號標出)的所有棧的信息
+++++++++++++++++++++++++++++++++++++++++++
案例:某個Unity游戲在關閉時的崩潰堆棧
具體崩潰的原因:0x47e2740為游戲腳本中編寫的新窗口處理函數地址,關閉程序時,游戲腳本從內存中被卸載,0x47e2740變成了野指針引發崩潰
注:0x47e2740是游戲腳本新窗口處理函數被虛擬機JIT產生出來的地址,在線程的Native棧上是沒有符號的,托管代碼都有這個特點
#查看匯編
u . // 反匯編當前eip寄存器地址的后8條指令
u $eip // 反匯編當前eip寄存器地址的后8條指令
ub . // 反匯編當前ip寄存器地址的前8條指令
ub $eip // 反匯編當前eip寄存器地址的前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條指令內容
#寄存器
r // 顯示所有寄存器信息及發生core所在的指令
r eax, edx // 顯示eax,edx寄存器信息
r eax=5, edx=6 // 對寄存器eax賦值為5,edx賦值為6
#內存
-- 注:windbg不支持中文顯示
!address // 查看進程的所有內存頁屬性
!address -summary // 顯示進程的內存統計信息 要為fulldmp才會准確
!address -f:stack // 查看棧的內存信息,紅框為主線程、籃框為windbg注入的遠程線程
!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 -- 和UE一樣,左邊為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進制,還是其他,取決於當前進制)
.writemem D:\Test\0041a5e4.bin 0041a5e4 L1000 // 將內存地址處0x0041a5e4后面0x1000長度的內容拷貝存儲到D:\Test\0041a5e4.bin中
#查看堆(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 // 選取一個堆的地址,打印該堆的信息,比上面打印內存命令更詳細直觀
Index Address Name Debugging options enabled
1: 00140000
Segment at 00140000 to 00240000 (00003000 bytes committed)
Flags: 50000062
ForceFlags: 40000060
Granularity: 8 bytes
Segment Reserve: 00100000
Segment Commit: 00002000
DeCommit Block Thres: 00000200
DeCommit Total Thres: 00002000
Total Free Size: 000000af
Max. Allocation Size: 7ffdefff
Lock Variable at: 00140608
Next TagIndex: 0000
Maximum TagIndex: 0000
Tag Entries: 00000000
PsuedoTag Entries: 00000000
Virtual Alloc List: 00140050
UCR FreeList: 00140598
FreeList Usage: 00000000 00000000 00000000 00000000
FreeList[ 00 ] at 00140178: 00142a90 . 00142a90
00142a88: 00050 . 00578 [14] - free
Segment00 at 00140640:
Flags: 00000000
Base: 00140000
First Entry: 00140680
Last Entry: 00240000
Total Pages: 00000100
Total UnCommit: 000000fd
Largest UnCommit:000fd000
UnCommitted Ranges: (1)
00143000: 000fd000
Heap entries for Segment00 in Heap 00140000
00140000: 00000 . 00640 [01] - busy (640)
00140640: 00640 . 00040 [01] - busy (40)
00140680: 00040 . 01818 [07] - busy (1800), tail fill - unable to read heap entry extra at 00141e90
00141e98: 01818 . 00040 [07] - busy (22), tail fill - unable to read heap entry extra at 00141ed0
00141ed8: 00040 . 00050 [07] - busy (36), tail fill - unable to read heap entry extra at 00141f20
00141f28: 00050 . 002f0 [07] - busy (2d8), tail fill - unable to read heap entry extra at 00142210
00142218: 002f0 . 00330 [07] - busy (314), tail fill - unable to read heap entry extra at 00142540
00142548: 00330 . 00330 [07] - busy (314), tail fill - unable to read heap entry extra at 00142870
00142878: 00330 . 00040 [07] - busy (24), tail fill - unable to read heap entry extra at 001428b0
001428b8: 00040 . 00028 [07] - busy (10), tail fill - unable to read heap entry extra at 001428d8
001428e0: 00028 . 00058 [07] - busy (40), tail fill - unable to read heap entry extra at 00142930
00142938: 00058 . 00058 [07] - busy (40), tail fill - unable to read heap entry extra at 00142988
00142990: 00058 . 00060 [07] - busy (44), tail fill - unable to read heap entry extra at 001429e8
001429f0: 00060 . 00020 [07] - busy (1), tail fill - unable to read heap entry extra at 00142a08
00142a10: 00020 . 00028 [07] - busy (10), tail fill - unable to read heap entry extra at 00142a30
00142a38: 00028 . 00050 [07] - busy (36), tail fill - unable to read heap entry extra at 00142a80
00142a88: 00050 . 00578 [14] free fill
00143000: 000fd000 - uncommitted bytes.
#虛擬內存
!vadump // 查看虛擬內存布局
#設置事件發生時windbg行為
sx // 顯示windbg遇到每個異常和事件時的行為
sxr // 將所有異常和事件過濾器的狀態重設為默認值
sxe ld // 當加載模塊時,立即中斷(Break)到調試器中(First-Chance)
sxe ld mono.dll // 當加載mono.dll模塊時,立即中斷(Break)到調試器中(First-Chance)
sxd ud // 當卸載模塊時,windbg不會在第一次處理機會時中斷(雖然會顯示信息)。如果其他錯誤處理器沒有處理掉該異常,執行會停止下來並中斷(Break)到windbg中(Second-Chance)
sxd av // 所有異常和事件只有Second-Chance才中斷到調試器
sxn et // 當線程退出時,windbg會打印出一條消息
sxi ct // 當線程創建時,windbg不中斷也不打印消息
#dump輸出
.dump /ma "d:\mydmpfile.dmp" // 將當前調試進程輸出Dump文件
#其他元命令
.tlist // 顯示所有進程
.cls // 清除屏幕
.shell config.bat // 執行config.bat批處理文件
.shell tasklist // 列出所有進程信息
.formats 'a' // 顯示字母a的各種類型對應的信息
.logopen c:\1.log // 將command內容輸出到c:\1.log文件中
.logclose // 關閉當前打開的日志
#其他擴展命令
!analyze -v // 詳細顯示當前異常信息
!analyze -hang // 診斷線程調用棧上是否有任何線程阻塞了其他線程
!analyze -f // 查看異常分析信息,盡管調試器並未診斷出異常
!tls -1 // 顯示當前線程所有的slot信息
!tls 2 // 顯示當前線程索引為2的slot信息
!peb // 格式化輸出PEB信息(process's environment block)
PEB at 7efde000
InheritedAddressSpace: No
ReadImageFileExecOptions: No
BeingDebugged: No
ImageBaseAddress: 00f20000
Ldr 76fa0200
Ldr.Initialized: Yes
Ldr.InInitializationOrderModuleList: 003a4d78 . 003e4a00
Ldr.InLoadOrderModuleList: 003a4ce8 . 003e49f0
Ldr.InMemoryOrderModuleList: 003a4cf0 . 003e49f8
Base TimeStamp Module
f20000 54772f74 Nov 27 22:04:36 2014 C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe
76ea0000 5684255b Dec 31 02:41:31 2015 C:\windows\SysWOW64\ntdll.dll
74790000 568425ff Dec 31 02:44:15 2015 C:\windows\syswow64\kernel32.dll
75b00000 56842600 Dec 31 02:44:16 2015 C:\windows\syswow64\KERNELBASE.dll
... ...
71d40000 55a5cad6 Jul 15 10:52:06 2015 C:\windows\System32\msxml6.dll
71d20000 4a5bdb38 Jul 14 09:11:20 2009 C:\windows\System32\bcrypt.dll
71ce0000 5600ce51 Sep 22 11:43:13 2015 C:\windows\SysWOW64\bcryptprimitives.dll
SubSystemData: 00000000
ProcessHeap: 003a0000
ProcessParameters: 003a2188
CurrentDirectory: 'C:\windows\system32\'
WindowTitle: '"C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe"'
ImageFile: 'C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe'
CommandLine: '"C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe" -Embedding'
DllPath: 'C:\Program Files (x86)\Citrix\ICA Client;C:\windows\system32;C:\windows\system;C:\windows;
Environment: 003a07f0
=::=::\
ALLUSERSPROFILE=C:\ProgramData
APPDATA=C:\Users\kekec\AppData\Roaming
CommonProgramFiles=C:\Program Files (x86)\Common Files
CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
CommonProgramW6432=C:\Program Files\Common Files
COMPUTERNAME=KEKEC-PC1
ComSpec=C:\windows\system32\cmd.exe
DXSDK_DIR=D:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\
FP_NO_HOST_CHECK=NO
HOMEDRIVE=C:
HOMEPATH=\Users\kekec
include=D:\Program Files (x86)\Microsoft Visual Studio\VC98\atl\include;D:\Program Files (x86)\Microsoft Visual Studio\VC98\mfc\include;
lib=D:\Program Files (x86)\Microsoft Visual Studio\VC98\mfc\lib;D:\Program Files (x86)\Microsoft Visual Studio\VC98\lib
LOCALAPPDATA=C:\Users\kekec\AppData\Local
LOGONSERVER=\\GM-HEIJI
MSDevDir=D:\Program Files (x86)\Microsoft Visual Studio\Common\MSDev98
NUMBER_OF_PROCESSORS=8
OS=Windows_NT
Path=C:\ProgramData\Oracle\Java\javapath;C:\windows\system32;C:\windows;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_ARCHITEW6432=AMD64
PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 60 Stepping 3, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=3c03
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files (x86)
ProgramFiles(x86)=C:\Program Files (x86)
ProgramW6432=C:\Program Files
PSModulePath=C:\windows\system32\WindowsPowerShell\v1.0\Modules\
PUBLIC=C:\Users\Public
SESSIONNAME=Console
SystemDrive=C:
SystemRoot=C:\windows
TEMP=C:\Users\kekec\AppData\Local\Temp
TMP=C:\Users\kekec\AppData\Local\Temp
USERDNSDOMAIN=TENCENT.COM
USERDOMAIN=TENCENT
USERNAME=kekec
USERPROFILE=C:\Users\kekec
VS120COMNTOOLS=D:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\
VS80COMNTOOLS=D:\Program Files (x86)\Microsoft Visual Studio 8\Common7\Tools\
VS90COMNTOOLS=d:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\
windir=C:\windows
!gle // 打印當前線程最近的錯誤信息LastError
!gle -all // 打印所有線程的最近的錯誤信息
!error 897// 顯示錯誤碼為897的詳細描述信息
#幫助
中文在線幫助:http://www.dbgtech.net/windbghelp/index.html
windbg cmd: http://www.slideshare.net/kewuc/windbg-cmds 【下載】
#調試命令窗口
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#使用gflags.exe工具(在windbg所在目錄下),讓某個進程啟動時,拉取windbg進行調試
如下截圖:當名稱為captcomm.exe的進程啟動時,拉起windbg調試
也可通過腳本命令來實現:
// 運行captcomm.exe時,啟動windbg調試 reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\captcomm.exe" /v Debugger /t REG_SZ /d "C:\Program Files\Debugging Tools for Windows (x86)\windbg.exe" /f // 解除啟動時windbg調試 reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\captcomm.exe" /f // 64位系統上,也可以設置以下注冊表節點 reg add "HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\captcomm.exe" /v Debugger /t REG_SZ /d "C:\Program Files\Debugging Tools for Windows (x86)\windbg.exe" /f // 解除啟動時windbg調試 reg delete "HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\captcomm.exe" /f // 測試發現:HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options和HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options指向的是同一數據,修改其中任何一個都可以
安全軟件可能會禁止修改注冊表的Image File Execution項:
-- 對於360安全衛士,在“設置”中去掉“開啟360自我保護”的勾選來關閉
-- 對於McAfee,需要禁止IPS(Intrusion Prevension Systems)。
-- 然而,電腦管家,則不會對該鍵值的注冊表修改進行阻止。
#重要說明
(1) windbg命令分為標准命令,元命令和擴展命令。
標准命令提供最基本的調試功能,不區分大小寫。如:bp g dt dv k等
元命令提供標准命令沒有提供的功能,也內建在調試引擎中,以.開頭。如.sympath .reload等
擴展命令用於擴展某一方面的調試功能,實現在動態加載的擴展模塊中,以!開頭。如!analyze等
(2) 進入調試狀態時,直接回車可重復執行上一條命令;按上下方向鍵可以瀏覽和選擇以前輸入過的命令
(3) 神奇的Tab鍵,進行命令補全;ESC清除當前命令輸入框中的文本
(4) 選擇Command窗口中的內容,然后右擊進行復制
(5) 使用;作為分隔符,可以在同一行輸入多條命令
(6) 上圖紅色框中的“0:000”。【0為當前調試會話的進程號;000為調試會話的線程號】
(7) 當命令提示符顯示*BUSY*時,即使命令輸入框可以輸入命令,但輸入的命令不會立即被執行,要等windbg空閑時才能執行。
可使用Ctrl + Break來終止一個長時間未完成的命令
(8) 一次可以執行多條命令,命令間用分號;分隔 【如:bp main;bp `view.cpp:120`】,一次打2個斷點
(9)按Ctrl + Alt + V開啟/關閉verbose Output(詳細輸出模式)
(10) 為了保證windbg流暢運行,在調試時,盡量不要開啟Watch、Locals、Registers、Call Stack、Processes and Threads窗口,直接用command來獲取信息
#啟動調試
windbg -I // 將windbg設置成默認調試器
windbg "notepad.exe" arguments // 使用windbg啟動調試notepad.exe
windbg -p 4200 // 將windbg附加到一個正在運行的pid為4200的進程上
windbg -pn "notepad.exe" // 將windbg附加到一個正在運行的名為notepad.exe的進程上
windbg -p 4200 -c "sxd av;sxi c0000005;sxi c0000008;g" // 將windbg附加到一個正在運行的pid為4200的進程上,附加成功后,執行sxd av;sxi c0000005;sxi c0000008;g命令
windbg –z "c:\mydumpfile.dmp" // 調試mydumpfile.dmp文件
.opendump "c:\mydumpfile.dmp" // 調試mydumpfile.dmp文件
windbg -y d:\mySymbols // 指示symbol路徑
windbg -srcpath d:\Src // 指示源文件路徑
windbg -i d:\myApp //指示exe、dll等可執行模塊路徑
.attach 0n4220 // 4220為十進制pid,使用該命令附加調試時,必須先存在一個調試會話
.detach // 分離調試
.restart // 重啟並調試
.kill // 強制結束當前調試
q // 結束當前調試會話,回到基礎工作空間,並結束調試進程
qd // 結束當前調試會話,回到基礎工作空間,但不結束調試進程
CTRL+ALT+V // 打開或關閉 Verbose 模式開關,某些命令在此模式下可以給出更多詳細信息
.time // 調試會話時間信息
.lastevent // 顯示最新的異常信息或事件信息
version // 顯示windbg和已加載的調試器擴展相關的信息
vercommand // 顯示windbg的啟動路徑及命令行信息
.chain // 顯示已經加載進來的調試器擴展
.extmatch /D /e wow64exts * // 顯示wow64exts調試器擴展中的命令
#獲取幫助
? // 打印出所有標准命令
.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 注:必須勾選上菜單“Debug”-“Source Mode”;另外pdb須與exe、dll等執行模塊匹配上
.srcpath+ f:\src // 將f:\src添加到源文件查找路徑集合中
.exepath // 查看可執行文件查找路徑
.exepath f:\bin // 將可執行文件查找路徑設為:f:\bin
.exepath+ f:\bin // 將f:\bin添加到可執行文件查找路徑集合中
#系統信息
vertarget // os信息
!cpuid // cpu信息
#wow64模式 【x64版windbg調試win32程序】
.load wow64exts // [!load wow64exts] 加載wow64exts.dll模塊 注:!sw就是wow64exts中的命令
.unload wow64exts // [!unload wow64exts] 卸載wow64exts.dll模塊
.effmach // 查看當前調試mode:x86、x64等
.effmach x86 // 切換到x86棧環境 注:需要先執行.load wow64exts來加載wow64exts.dll模塊
.effmach . // 切換回x64
!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函數地址的上下文信息
注 -- 32位windbg無法打開64位應用程序,會提示如下錯誤:
注 -- 32位windbg無法attach上64位應用程序,會提示如下錯誤:
#符號加載與查看
除了使用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加載符號信息
.reload /u TGame.exe // 卸載TGame.exe及其載符號信息
x *! // 列出所有模塊對應的符號信息
lm // 列出所有模塊(加載和未加載)對應的符號信息
lmv // 列出所有模塊(加載和未加載)對應的符號信息
lmvm ntdll // 查看ntdll.dll的詳細信息(注意exe、dll等都不要帶后綴名)
!lmi ntdll // 查看ntdll.dll的詳細信息(注意exe、dll等都不要帶后綴名)
!dlls -l // 按照加載順序(默認項)列出所有加載的模塊
!dlls -i // 按初始化順序列出所有加載的模塊
!dlls -v -c ntdll // 查看ntdll.dll的詳細信息(注意exe、dll等都不要帶后綴名)
ln 0x65777588 // 查看地址0x65777588處或附近的符號信息
x ConsoleTest!* // 列出ConsoleTest模塊中的所有符號
x ConsoleTest!add* // 列出ConsoleTest模塊中的所有add開頭的符號
x /t /v ConsoleTest!* // 帶數據類型、符號類型和大小信息,列出ConsoleTest模塊中的所有符號
x kernel32!*LoadLib* // 列出kernel32模塊中所有含LoadLib字樣的符號
!itoldyouso mono D:\mySymbols\mono.pdb // 查看mono.dll與D:\mySymbols\mono.pdb符號是否匹配上
0:000> !itoldyouso mono D:\mySymbols\mono.pdb
mono.dll
Timestamp: 559AAA60
SizeOfImage: 230000
pdb: C:\buildslave\mono-runtime-and-classlibs\build\builds\embedruntimes\win32\mono.pdb
pdb sig: 728334C1-72C3-4A51-B310-C44087FC4B2E
age: 1
mono.pdb
pdb sig: 728334C1-72C3-4A51-B310-C44087FC4B2E
age: 1
MATCH: mono.pdb and mono.dll
-------------------------------------------------------------------------
使用windbg提供的symchk.exe工具來查找模塊的pdb
symchk.exe Paladins.exe /v /s .\ //在當前目錄查找Paladins.exe的pdb,/s后面指定搜索路徑 帶上/v會輸出詳細的log
如果匹配上,會顯示如下log:
[SYMCHK] [ 0x00000000 - 0x001f0001 ] Checked "G:\TGame\symbols\ClientPackaging\Paladins.exe" SYMCHK: FAILED files = 0 SYMCHK: PASSED + IGNORED files = 1
沒有匹配上,則顯示log為:
SYMCHK: Paladins.exe FAILED - ShippingPC-ChaosGameTencent.pdb mismatched or not found SYMCHK: FAILED files = 1 SYMCHK: PASSED + IGNORED files = 0
#進程
| // 列出調試進程
|* // 列出調試進程
|N // 參看序數為N的調試進程
|Ns // 切換序數為N的進程為當前調試進程
!dml_proc // 顯示當前進程信息
#線程
~ // 列出線程
~* // 所有線程
~* k // 所有線程堆棧信息
~* r // 所有線程寄存器信息
~. // 查看當前線程
~0s // 查看主線程
~# // 查看導致當前事件或異常的線程
~N // 查看序數為N的線程
~~[n] // 查看線程ID為n的線程 n為16進制
~Ns // 切換序數為N的線程為當前調試線程
~~[n]s // 切換線程ID為n的線程為當前調試線程 n為16進制
~N f // 凍結序數為N的線程
~N u // 解凍序數為N的線程
~N n // Suspend序數為N的線程
~N m // Resume序數為N的線程
~* e !gle // 顯示所有線程最后的一個錯誤信息 e后可以為任意windbg命令
.ttime // 查看當前線程時間信息
!runaway //顯示當前進程的所有線程用戶態時間信息
!runaway f //顯示當前進程的所有線程用戶態、內核態、存活時間信息
!locks // 顯示死鎖
!cs // 列出CriticalSection(臨界段)的詳細信息
#斷點
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 MyDll+0x1032 // 在模塊MyDll.dll偏移0x1032處放置一個斷點
bp `ConsoleTest.cpp:36` // 在ConsoleTest.cpp的36行處放置一個斷點
bp main // 在main函數的起始處放置一個斷點
bp @$exentry // 在進程的入口放置一個斷點
bp CSecondLoader::CSecondLoader // 在CSecondLoader的構造函數處放置一個斷點
bp TestCommon! CTest::add // 在TestCommon.dll的Test.cpp文件的CTest::add()函數起始處放置一個斷點
bp `ConsoleTest.cpp:40` ".if (poi(pVar)>5) {}; {g}" // ".if (Condition) {Optional Commands}; {g}" 條件斷點 pVar指針指向的值>5,執行空語句(;),斷住 否則繼續執行
bp `ConsoleTest.cpp:40` "j (poi(pVar)>5) ' '; 'g'" // "j (Condition) 'Optional Commands'; 'g'" j為條件表示式:條件斷點 pVar指針指向的值>5,執行空語句(;),斷住 否則繼續執行
注:Condition表達式語法默認的是MASM表達式語法。使用復雜C++表達式時我們需要用@@c++()將表達式包圍住;如:"j @@c++(*pVar>5) ' '; 'g'"
---------------------------------
x表示的一個地址
hi(x) 高16 bits
low(x) 低16 bits
by(x) 返回第一個byte
wo(x) 返回第一個word
dwo(x) 返回第一個dword
qwo(x) 返回第一個4 word(Quad-word)
poi(x) 返回第一個指針所指向的值
---------------------------------
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 kernel32!CreateFileW ".echo;.printf\"CreateFileW(%mu,%p,%p), ret=\",poi(esp+4),dwo(esp+8),dwo(esp+c);kn;g;" // 不斷住進程,打印所有的CreateFileW調用及堆棧信息
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調用(打開注冊表鍵值)
---------------------------------
注意:有些函數Symbol Name與導出函數名可能不一致,例如SetWindowPos,這時可以用Dependency查看相應的導出函數地址(Entry Point列):0x00018E5E,然后在windbg菜單“Debug”—〉“Modules...”對話框中獲得user32.dll模塊起始地址0x77d10000,在兩個值相加后的絕對地址處直接設置斷點:bp 77d28E5E;也可以通過x user32!*命令列出全部Symbols列表,查找77d28E5E,找到SetWindowPos對應的Symbol Name為“NtUserSetWindowPos”,然后通過符號設置斷點:bp user32!NtUserSetWindowPos。通過符號設置斷點的好處是當dll代碼改變時,不需要修改,windbg會根據符號來自動匹配函數地址。
---------------------------------
bu // 保存斷點,其用法和bp一樣
bm add_* // 匹配add_開頭的函數,並在這些函數起始處都打上斷點
ba w4 0x0483dfe0 // 當對0483dfe0地址寫操作時停下,前面要帶上0x,否則會報錯
// ba [r|w|e] [Size] Addr [r=read/write, w=write, e=execute], Size=[1|2|4 bytes]
windbg無參腳本
// 當CreateFileW讀取UnityLockfile文件時斷住進程,在命令輸入框輸入:$$><d:\CreateFileWNoArguScript.txt,CreateFileWNoArguScript.txt內容如下:
bp kernel32!CreateFileW "
r $t1=poi(esp+4)
as /mu $FileName $t1
.echo
.printf\"File:%mu\",$t1
.echo
.block
{
.if($spat(\"${$FileName}\",\"*UnityLockfile\"))
{
.echo 'find...';
ad ${/v:$FileName}
}
.else
{
.echo no find...
ad ${/v:$FileName}
gc
}
}"
windbg有參腳本
// 當CreateFileW讀取mscorlib.dll文件時斷住進程,在命令輸入框輸入:$$>a<d:\CreateFileWArguScript.txt mscorlib.dll,CreateFileWArguScript.txt內容如下:
bp kernel32!CreateFileW " r $t1=poi(esp+4) as /mu $FileName $t1 .echo .printf\"File:%mu\",$t1 .echo .block { .if($spat(\"${$FileName}\",\"*${$arg1}\")) { .echo 'find...'; ad ${/v:$FileName} } .else { .echo no find... ad ${/v:$FileName} gc } }"
#調試執行控制
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 // 執行到下一個進入點(Call指令)處停下 【Trace to Next Call】
tb // 執行到分支指令停下【分支指令包括calls、returns、jumps、loops】
ta 7c801b12 // 執行到7c801b12地址處停下 【Trace to Adress】
WT Trace and Watch Data,一條強大指令,對執行流程做Profile
# 查看句柄
!handle // 查看所有句柄的ID
!handle 000007f8 1 // 查看ID為000007f8的句柄的類型
!handle 000007f8 4 // 查看ID為000007f8的句柄的名稱
!handle 0 5 // 查看所有句柄的類型和名稱
!htrace -enable // 使用windbg調試運行時,啟用跟蹤所有打開句柄或關閉句柄的調用以及相應的棧回溯
!htrace // 進程運行結束后,打印所有打開句柄或關閉句柄的調用以及相應的棧回溯
!htrace -diff // 只打印沒有關閉的句柄的信息及棧回溯
Handle = 0x00000038 - OPEN
Thread ID = 0x00001f34, Process ID = 0x00000638
0x049ca83c: +0x049ca83c
0x049d5eb4: +0x049d5eb4
0x046c8313: +0x046c8313
0x76d2d90a: +0x76d2d90a
0x7451c1ff: +0x7451c1ff
0x7450d18f: +0x7450d18f
0x74492776: +0x74492776
0x7450d286: +0x7450d286
0x7450c69e: +0x7450c69e
0x76d210d6: +0x76d210d6
0x76d7dc30: +0x76d7dc30
0x76d0b17e: +0x76d0b17e
0x76ee0166: ntdll!NtCreateFile+0x00000012
0x7542c76b: KERNELBASE!CreateFileW+0x0000035e
0x752c3f66: kernel32!CreateFileW+0x0000004a
0x752c53c4: kernel32!CreateFileA+0x00000036
--------------------------------------
Parsed 0x1 stack traces.
Dumped 0x1 stack traces.
# 查看變量
=== 0n(十進制) 0x(十六進制) 0t(8進制) 0y(2進制) 可以使用n [8|10|16]命令來修改數值進制表示方式(輸入n可查看當前進制,默認為16進制)===
-- VC6.0的Link選項需要將/pdbtype:sept改為/pdbtype:con, 否則生成的pdb文件中將不包含如自定義結構體,類等信息
dt nRet // 查看局部變量nRet的類型與值(函數參數變量請用dv命令) --注:編譯器很多時候會把一些局部變量優化掉,這個時候就會出現找不到nRet符號的情況
dt ntdll!* // 顯示ntdll里的所有類型信息
dt *!*IMAGE_DOS* // 顯示所有模塊中含有IMAGE_DOS字符的類型信息
test1!IMAGE_DOS_HEADER
test1!PIMAGE_DOS_HEADER
test1!_IMAGE_DOS_HEADER
ntdll!_IMAGE_DOS_HEADER
ntdll32!_IMAGE_DOS_HEADER
MSVCR90D!IMAGE_DOS_HEADER
MSVCR90D!PIMAGE_DOS_HEADER
MSVCR90D!_IMAGE_DOS_HEADER
dt myApp!g_app // 表示顯示myApp進程里全局變量g_app的內存布局(注:vc6見上述說明)
dt WindbgTest!CTest // 查看模塊WindbgTest的CTest的內存布局,加上-b -r參數可以顯示內部類及數組的信息(注:vc6見上述說明)
dt WindbgTest!CTest 0x0041f8d4 // 將0x0041f8d4地址處內容按照模塊WindbgTest的CTest的內存布局來解析(注:vc6見上述說明)
Windbg默認會用寄存器ECX里面的值作為this指針地址,其實這樣是有時候是錯誤的。
有些C++編譯器在做代碼優化之后會把 this指針放在其他寄存器里面,比如ESI。
所以在調試的時候還需要讀一下匯編代碼來確定this 在哪個寄存器里面。
比如我們看到 MOV EAX, dword ptr [ESI + 0x48h](獲取當前對象內存偏移為0x48h處的4字節成員變量),就可以判斷ESI 是this 指針。
這時可以通過如下命令打印this的內存結構:dt -b 模塊名!類名 @esi
dt tagMSG 0x0336e54c // 類型要使用tagMSG,不能使用typedef產生出的MSG
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG, *PMSG;
dt this // 查看this指針的類型及成員變量(注:vc6見上述說明)
dt -b this // 查看this指針的類型及成員變量,如果某一成員變量為結構體,則把其結構成員也一一打印出來
// -b開關指定遞歸顯示所有子類型信息,-r[n]指定遞歸顯示的深度,如-r0表示不顯示子類型信息
dt -v _PEB @$PEB // 使用詳細模式查看PEB(process's environment block)內存結構
dt _TEB ny LastErrorValue // 只查看TEB(thread's environment block)結構成員LastErrorValue
?? 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 當前函數kernel32!BaseThreadStart執行的指令地址。
01e511f9 0174c570 00000000 參數相關的數值【從左到右 -- 參數1 參數2:offset為sizeof(參數1) 參數3:offset為sizeof(參數1)+sizeof(參數2) ...】。注:如果是成員函數,this指針通過ecx或其他寄存器來傳遞
02a9ffec 00000000是 當前函數ebp 和 上層函數返回地址。
======================================================
Windows 7 Ultimate Service Pack 1 [Build 6.1.7601]
CPU: Intel(R) Core(TM) i3-2100 CPU @ 3.10GHz
《Game》 20.15.1112 6EF76A43E6B1DD58907F3E066506E918
----------------------------------------
Type: EXCEPTION_ACCESS_VIOLATION//非法地址訪問異常
Error: Read address 0x00074685//讀取0x00074685地址出錯(該地址對應的內存頁,進程無讀取權限)
Address: 64DCAF68//崩潰發生的指令地址
CallStack:
//0x64D90000為模塊MSVCR90.dll的基地址,3AF68為崩潰指令在模塊中的偏移值,(0492B5D0,00074685,0000000C,00462482)為參數信息
0x64D90000[3AF68] MSVCR90.dll: (0492B5D0,00074685,0000000C,00462482)
0X00400000[11158A] tgame.exe: (0492B5D0,00074685,00000000,00000000)
kb 5 // 只顯示最上的5層調用堆棧
kv // 在kb的基礎上增加了函數調用約定、FPO等信息
kp // 顯示每一層函數調用的完整參數,包括參數類型、名字、取值(必須是完整符號的情況下,private symbols);注意:若程序被優化,這些值不一定對
kd // 打印堆棧的地址
kD // 從當前esp地址處,向高地址方向搜索符號(注:函數是符號的一種)
dds 02a9ffec // 從02a9ffec地址處,向高地址方向搜索符號(注:函數是符號的一種)
dds // 執行完dds 02a9ffec后,可通過dds命令繼續進行搜索
.frame // 顯示當前棧幀
.frame n // 顯示編號為n的棧幀(n為16進制數)
.frame /r n // 顯示編號n的棧幀(n為16進制數) 並顯示寄存器變量
.frame /c n // 設置編號n的棧幀為當前棧幀(n為16進制數)
!uniqstack // 顯示所有線程的調用堆棧
!findstack kernel32 2 // 顯示包含kernel32模塊(用星號標出)的所有棧的信息
+++++++++++++++++++++++++++++++++++++++++++
案例:某個Unity游戲在關閉時的崩潰堆棧
具體崩潰的原因:0x47e2740為游戲腳本中編寫的新窗口處理函數地址,關閉程序時,游戲腳本從內存中被卸載,0x47e2740變成了野指針引發崩潰
注:0x47e2740是游戲腳本新窗口處理函數被虛擬機JIT產生出來的地址,在線程的Native棧上是沒有符號的,托管代碼都有這個特點
#查看匯編
u . // 反匯編當前eip寄存器地址的后8條指令
u $eip // 反匯編當前eip寄存器地址的后8條指令
ub . // 反匯編當前ip寄存器地址的前8條指令
ub $eip // 反匯編當前eip寄存器地址的前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條指令內容
#寄存器
r // 顯示所有寄存器信息及發生core所在的指令
r eax, edx // 顯示eax,edx寄存器信息
r eax=5, edx=6 // 對寄存器eax賦值為5,edx賦值為6
#內存
-- 注:windbg不支持中文顯示
!address // 查看進程的所有內存頁屬性
!address -summary // 顯示進程的內存統計信息 要為fulldmp才會准確
!address -f:stack // 查看棧的內存信息,紅框為主線程、籃框為windbg注入的遠程線程
!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 -- 和UE一樣,左邊為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進制,還是其他,取決於當前進制)
.writemem D:\Test\0041a5e4.bin 0041a5e4 L1000 // 將內存地址處0x0041a5e4后面0x1000長度的內容拷貝存儲到D:\Test\0041a5e4.bin中
#查看堆(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 // 選取一個堆的地址,打印該堆的信息,比上面打印內存命令更詳細直觀
Index Address Name Debugging options enabled
1: 00140000
Segment at 00140000 to 00240000 (00003000 bytes committed)
Flags: 50000062
ForceFlags: 40000060
Granularity: 8 bytes
Segment Reserve: 00100000
Segment Commit: 00002000
DeCommit Block Thres: 00000200
DeCommit Total Thres: 00002000
Total Free Size: 000000af
Max. Allocation Size: 7ffdefff
Lock Variable at: 00140608
Next TagIndex: 0000
Maximum TagIndex: 0000
Tag Entries: 00000000
PsuedoTag Entries: 00000000
Virtual Alloc List: 00140050
UCR FreeList: 00140598
FreeList Usage: 00000000 00000000 00000000 00000000
FreeList[ 00 ] at 00140178: 00142a90 . 00142a90
00142a88: 00050 . 00578 [14] - free
Segment00 at 00140640:
Flags: 00000000
Base: 00140000
First Entry: 00140680
Last Entry: 00240000
Total Pages: 00000100
Total UnCommit: 000000fd
Largest UnCommit:000fd000
UnCommitted Ranges: (1)
00143000: 000fd000
Heap entries for Segment00 in Heap 00140000
00140000: 00000 . 00640 [01] - busy (640)
00140640: 00640 . 00040 [01] - busy (40)
00140680: 00040 . 01818 [07] - busy (1800), tail fill - unable to read heap entry extra at 00141e90
00141e98: 01818 . 00040 [07] - busy (22), tail fill - unable to read heap entry extra at 00141ed0
00141ed8: 00040 . 00050 [07] - busy (36), tail fill - unable to read heap entry extra at 00141f20
00141f28: 00050 . 002f0 [07] - busy (2d8), tail fill - unable to read heap entry extra at 00142210
00142218: 002f0 . 00330 [07] - busy (314), tail fill - unable to read heap entry extra at 00142540
00142548: 00330 . 00330 [07] - busy (314), tail fill - unable to read heap entry extra at 00142870
00142878: 00330 . 00040 [07] - busy (24), tail fill - unable to read heap entry extra at 001428b0
001428b8: 00040 . 00028 [07] - busy (10), tail fill - unable to read heap entry extra at 001428d8
001428e0: 00028 . 00058 [07] - busy (40), tail fill - unable to read heap entry extra at 00142930
00142938: 00058 . 00058 [07] - busy (40), tail fill - unable to read heap entry extra at 00142988
00142990: 00058 . 00060 [07] - busy (44), tail fill - unable to read heap entry extra at 001429e8
001429f0: 00060 . 00020 [07] - busy (1), tail fill - unable to read heap entry extra at 00142a08
00142a10: 00020 . 00028 [07] - busy (10), tail fill - unable to read heap entry extra at 00142a30
00142a38: 00028 . 00050 [07] - busy (36), tail fill - unable to read heap entry extra at 00142a80
00142a88: 00050 . 00578 [14] free fill
00143000: 000fd000 - uncommitted bytes.
#虛擬內存
!vadump // 查看虛擬內存布局
#設置事件發生時windbg行為
sx // 顯示windbg遇到每個異常和事件時的行為
sxr // 將所有異常和事件過濾器的狀態重設為默認值
sxe ld // 當加載模塊時,立即中斷(Break)到調試器中(First-Chance)
sxe ld mono.dll // 當加載mono.dll模塊時,立即中斷(Break)到調試器中(First-Chance)
sxd ud // 當卸載模塊時,windbg不會在第一次處理機會時中斷(雖然會顯示信息)。如果其他錯誤處理器沒有處理掉該異常,執行會停止下來並中斷(Break)到windbg中(Second-Chance)
sxd av // 所有異常和事件只有Second-Chance才中斷到調試器
sxn et // 當線程退出時,windbg會打印出一條消息
sxi ct // 當線程創建時,windbg不中斷也不打印消息
#dump輸出
.dump /ma "d:\mydmpfile.dmp" // 將當前調試進程輸出Dump文件
#其他元命令
.tlist // 顯示所有進程
.cls // 清除屏幕
.shell config.bat // 執行config.bat批處理文件
.shell tasklist // 列出所有進程信息
.formats 'a' // 顯示字母a的各種類型對應的信息
.logopen c:\1.log // 將command內容輸出到c:\1.log文件中
.logclose // 關閉當前打開的日志
#其他擴展命令
!analyze -v // 詳細顯示當前異常信息
!analyze -hang // 診斷線程調用棧上是否有任何線程阻塞了其他線程
!analyze -f // 查看異常分析信息,盡管調試器並未診斷出異常
!tls -1 // 顯示當前線程所有的slot信息
!tls 2 // 顯示當前線程索引為2的slot信息
!peb // 格式化輸出PEB信息(process's environment block)
PEB at 7efde000
InheritedAddressSpace: No
ReadImageFileExecOptions: No
BeingDebugged: No
ImageBaseAddress: 00f20000
Ldr 76fa0200
Ldr.Initialized: Yes
Ldr.InInitializationOrderModuleList: 003a4d78 . 003e4a00
Ldr.InLoadOrderModuleList: 003a4ce8 . 003e49f0
Ldr.InMemoryOrderModuleList: 003a4cf0 . 003e49f8
Base TimeStamp Module
f20000 54772f74 Nov 27 22:04:36 2014 C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe
76ea0000 5684255b Dec 31 02:41:31 2015 C:\windows\SysWOW64\ntdll.dll
74790000 568425ff Dec 31 02:44:15 2015 C:\windows\syswow64\kernel32.dll
75b00000 56842600 Dec 31 02:44:16 2015 C:\windows\syswow64\KERNELBASE.dll
... ...
71d40000 55a5cad6 Jul 15 10:52:06 2015 C:\windows\System32\msxml6.dll
71d20000 4a5bdb38 Jul 14 09:11:20 2009 C:\windows\System32\bcrypt.dll
71ce0000 5600ce51 Sep 22 11:43:13 2015 C:\windows\SysWOW64\bcryptprimitives.dll
SubSystemData: 00000000
ProcessHeap: 003a0000
ProcessParameters: 003a2188
CurrentDirectory: 'C:\windows\system32\'
WindowTitle: '"C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe"'
ImageFile: 'C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe'
CommandLine: '"C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe" -Embedding'
DllPath: 'C:\Program Files (x86)\Citrix\ICA Client;C:\windows\system32;C:\windows\system;C:\windows;
Environment: 003a07f0
=::=::\
ALLUSERSPROFILE=C:\ProgramData
APPDATA=C:\Users\kekec\AppData\Roaming
CommonProgramFiles=C:\Program Files (x86)\Common Files
CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
CommonProgramW6432=C:\Program Files\Common Files
COMPUTERNAME=KEKEC-PC1
ComSpec=C:\windows\system32\cmd.exe
DXSDK_DIR=D:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\
FP_NO_HOST_CHECK=NO
HOMEDRIVE=C:
HOMEPATH=\Users\kekec
include=D:\Program Files (x86)\Microsoft Visual Studio\VC98\atl\include;D:\Program Files (x86)\Microsoft Visual Studio\VC98\mfc\include;
lib=D:\Program Files (x86)\Microsoft Visual Studio\VC98\mfc\lib;D:\Program Files (x86)\Microsoft Visual Studio\VC98\lib
LOCALAPPDATA=C:\Users\kekec\AppData\Local
LOGONSERVER=\\GM-HEIJI
MSDevDir=D:\Program Files (x86)\Microsoft Visual Studio\Common\MSDev98
NUMBER_OF_PROCESSORS=8
OS=Windows_NT
Path=C:\ProgramData\Oracle\Java\javapath;C:\windows\system32;C:\windows;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_ARCHITEW6432=AMD64
PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 60 Stepping 3, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=3c03
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files (x86)
ProgramFiles(x86)=C:\Program Files (x86)
ProgramW6432=C:\Program Files
PSModulePath=C:\windows\system32\WindowsPowerShell\v1.0\Modules\
PUBLIC=C:\Users\Public
SESSIONNAME=Console
SystemDrive=C:
SystemRoot=C:\windows
TEMP=C:\Users\kekec\AppData\Local\Temp
TMP=C:\Users\kekec\AppData\Local\Temp
USERDNSDOMAIN=TENCENT.COM
USERDOMAIN=TENCENT
USERNAME=kekec
USERPROFILE=C:\Users\kekec
VS120COMNTOOLS=D:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\
VS80COMNTOOLS=D:\Program Files (x86)\Microsoft Visual Studio 8\Common7\Tools\
VS90COMNTOOLS=d:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\
windir=C:\windows
!gle // 打印當前線程最近的錯誤信息LastError
!gle -all // 打印所有線程的最近的錯誤信息
!error 897// 顯示錯誤碼為897的詳細描述信息
#幫助
中文在線幫助:http://www.dbgtech.net/windbghelp/index.html
windbg cmd: http://www.slideshare.net/kewuc/windbg-cmds 【下載】