windbg是一個強大win平台上的調試工具,現在介紹一下它的準系統。
加入要偵錯工具代碼debugee.cpp如下:
// debugee.cpp : Defines the entry point for the console application.//#include "stdafx.h"void loop(void){for (int i = 0; i < 1000; i ++){printf("loop [%d]\n", i);}}int main(int argc, char* argv[]){printf("Hello World!\n");loop();return 0;}
===============================================================
斷點
===============================================================
設定符號斷點,如果正確載入了符號表檔案(-y 指定, 或者ctrl+s)。
bm debugee!main
在main函數入口的位置設定斷點,用用tab鍵看看,還有提示哦。
在源檔案的行號上設定斷點,如果正確指定了源檔案路徑(-srcpath指定,或者ctrl+p)
bp `debugee.cpp:10`
bp `:10`
條件斷點指令, 當i=500的時候停止,否則從斷點開始繼續執行gc:
bp `debugee.cpp:10` "j (poi(i)=500) ' ' ; 'gc' "
執行到800以上的時候停止
bp `debugee.cpp:10` "j (poi(i)>0n800) ' ' ; 'gc' "
硬體資料斷點,很酷的功能哦(真正的硬體斷點有個數限制,cpu的dr寄存器個數)
在變數i的記憶體位置開始寫入4個位元組大小的時候,斷點
ba w 4 i
在變數i的記憶體位置開始讀取4個位元組大小的時候,斷點
ba r 4 i
指令斷點
先u一段loop函數的反組譯碼看看
0:000> u debugee!loopdebugee!loop [H:\temp\debugee\debugee.cpp @ 7]:0040d6f0 55 push ebp0040d6f1 8bec mov ebp,esp0040d6f3 83ec44 sub esp,44h0040d6f6 53 push ebx0040d6f7 56 push esi0040d6f8 57 push edi0040d6f9 8d7dbc lea edi,[ebp-44h]0040d6fc b911000000 mov ecx,11h0:000> udebugee!loop+0x11 [H:\temp\debugee\debugee.cpp @ 7]:0040d701 b8cccccccc mov eax,0CCCCCCCCh0040d706 f3ab rep stos dword ptr es:[edi]0040d708 c745fc00000000 mov dword ptr [ebp-4],00040d70f eb09 jmp debugee!loop+0x2a (0040d71a)0040d711 8b45fc mov eax,dword ptr [ebp-4]0040d714 83c001 add eax,10040d717 8945fc mov dword ptr [ebp-4],eax0040d71a 817dfce8030000 cmp dword ptr [ebp-4],3E8h0:000> udebugee!loop+0x31 [H:\temp\debugee\debugee.cpp @ 8]:0040d721 7d13 jge debugee!loop+0x46 (0040d736)0040d723 8b4dfc mov ecx,dword ptr [ebp-4]0040d726 51 push ecx0040d727 681c204200 push offset debugee!`string' (0042201c)0040d72c e82f39ffff call debugee!printf (00401060)0040d731 83c408 add esp,80040d734 ebdb jmp debugee!loop+0x21 (0040d711)0040d736 5f pop edi0:000> udebugee!loop+0x47 [H:\temp\debugee\debugee.cpp @ 12]:0040d737 5e pop esi0040d738 5b pop ebx0040d739 83c444 add esp,44h0040d73c 3bec cmp ebp,esp0040d73e e89d39ffff call debugee!_chkesp (004010e0)0040d743 8be5 mov esp,ebp0040d745 5d pop ebp0040d746 c3 ret
好的,接下來在,調用printf的時候給它斷住。
bc *
ba e 1 0x0040d72c
注意:ba e指令斷點的時候,位元組限制必須是1,
===============================================================
語句控制
===============================================================
執行一句,遇到函數,飛過去,相當於gdb的next,vc的f10
p
執行一句,遇到函數,跟進去,相當於gdb的step,vc的f11
t
執行到一個ret語句停止,一般用來完成一個子函數, 執行到子函數即將返回的位置
pt 或者tt 區別是如果當前是ret指令怎麼辦
執行到下一個call指令
pc
0:000> pceax=cccccccc ebx=7ffdd000 ecx=00000000 edx=003710d8 esi=00000000 edi=0012ff70eip=004010d6 esp=0012ff20 ebp=0012ff80 iopl=0 nv up ei pl nz na pe nccs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206> 19: printf("Hello World!\n");debugee!main+0x36:004010d6 e875000000 call debugee!printf (00401150)0:000> udebugee!main+0x36 [H:\temp\debugee\debugee.cpp @ 19]:004010d6 e875000000 call debugee!printf (00401150)004010db 83c404 add esp,4004010de c745fc00000000 mov dword ptr [ebp-4],0004010e5 e820ffffff call debugee!ILT+5(?loopYAXXZ) (0040100a)004010ea eb13 jmp debugee!main+0x5f (004010ff)004010ec 682c504200 push offset debugee!`string' (0042502c)004010f1 e85a000000 call debugee!printf (00401150)004010f6 83c404 add esp,4
從子函數中執行到調用子函數語句的下一句位置 go up
gu
在子函數的開始位置執行wt, 顯示子函數的所有執行路徑,最後給出統計資訊
wt
34 0 [ 4] debugee!write_char 70 68 [ 3] debugee!write_string 34 0 [ 4] debugee!write_char 84 102 [ 3] debugee!write_string 742 520 [ 2] debugee!_output 34 0 [ 3] debugee!write_char 789 554 [ 2] debugee!_output 34 0 [ 3] debugee!write_char 808 588 [ 2] debugee!_output 29 1469 [ 1] debugee!printf 7 0 [ 2] debugee!_ftbuf641971 instructions were executed in 641970 events (0 from other threads)Function Name Invocations MinInst MaxInst AvgInstdebugee!_aulldiv 790 17 17 17debugee!_aullrem 790 15 15 15debugee!_flush 299 51 51 51debugee!_ftbuf 300 7 44 43debugee!_isatty 300 14 14 14debugee!_output 300 726 808 792debugee!_stbuf 300 59 59 59debugee!_write 299 330 380 370debugee!get_int_arg 300 12 12 12debugee!loop 1 3323 3323 3323debugee!printf 300 29 37 36debugee!write_char 3190 34 34 34debugee!write_multi_char 300 10 10 10debugee!write_string 600 12 84 43kernel32!WriteConsoleA 299 11 11 11kernel32!WriteConsoleInternal 299 60 61 60kernel32!WriteFile 299 30 30 30kernel32!_SEH_epilog 598 9 9 9kernel32!_SEH_prolog 598 19 19 19kernel32!__security_check_cookie 299 5 5 5ntdll!CsrClientCallServer 299 39 39 39ntdll!KiFastSystemCall 299 2 2 2ntdll!NtRequestWaitReplyPort 598 1 2 1ntdll!ZwRequestWaitReplyPort 299 1 1 1299 system calls were executedCalls System Call 299 ntdll!KiFastSystemCall
===============================================================
資料顯示
===============================================================
0:000> dt i
Local var @ 0x12ff28 Type int8030:000> ?? iint 8030:000> ? poi(i)Evaluate expression: 803 = 00000323
===============================================================
記憶體
===============================================================
顯示記憶體
0:000> db i L200012ff18 16 00 00 00 80 ff 12 00-ea 10 40 00 00 00 00 00 ..........@.....0012ff28 00 00 00 00 ....0:000> ds i L200012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0012ff80 "..."0:000> dd i L200012ff18 00000016 0012ff80 004010ea 000000000012ff28 00000000 7ffd4000 cccccccc cccccccc0012ff38 cccccccc cccccccc cccccccc cccccccc0012ff48 cccccccc cccccccc cccccccc cccccccc0012ff58 cccccccc cccccccc cccccccc cccccccc
記憶體搜尋
0:000> n16 ; s i L20 ccbase is 160012ff30 cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc ................0012ff31 cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc ................0012ff32 cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc ................0012ff33 cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc ................0012ff34 cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc ................0012ff35 cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc ................0012ff36 cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc ................0012ff37 cc cc cc cc cc cc cc cc-cc cc cc cc cc cc cc cc ................
記憶體編輯
設定變數i的值為20
n 20; ed i 20 設定10進位,在i的記憶體位置(變數名之時記憶體位址,poi(i)表示i的值)編輯雙字, 設定成20
設定源檔案選項
l+ls 設定在命令視窗提示源檔案代碼
===============================================================
寄存器
===============================================================
查看所有寄存器的資訊
r
修改寄存器的值
r @eax=0x00000323 或者r eax=0x00000323 或者 n 16 ; r eax=323
n命令的意思是切換數的進位,n 16表示使用16進位,323的字面就是16進位的0x323
顯示和設定浮點數
0:000> rFfpcw=027F: rn 53 puozdi fpsw=0000: top=0 cc=0000 -------- fptw=FFFFfopcode=0000 fpip=0000:00000000 fpdp=0000:00000000st0= 0.000000000000000000000e+0000 st1= 0.000000000000000000000e+0000st2= 0.000000000000000000000e+0000 st3= 0.000000000000000000000e+0000st4= 0.000000000000000000000e+0000 st5= 0.000000000000000000000e+0000st6= 0.000000000000000000000e+0000 st7= 0.000000000000000000000e+0000
rF st0=123.5e10
顯示和設定sse寄存器
0:000> rXxmm0=0 0 0 0xmm1=0 0 0 0xmm2=0 0 0 0xmm3=0 0 0 0xmm4=0 0 0 0xmm5=0 0 0 0xmm6=0 0 0 0xmm7=0 0 0 0
rX xmm0=1 2 3 4
===============================================================
線程和棧
===============================================================
線程和棧操作指令:
切換到3號線程(順序是按照線程建立的順序編碼的)
~3s
掛起當前線程
~n
掛起所有線程
~*n
掛起10號線程
~10n
喚醒當前線程
~m
喚醒所有線程
~*m
喚醒10號線程
~10m
顯示棧, 類似於gdb的bt命令
k kd kn ~kd ~*kn
移動棧幀到第10層,0層是當前執行位置
0:000> ~kn # ChildEBP RetAddr 00 0012ff80 00401209 debugee!main+0x2a [H:\temp\debugee\debugee.cpp @ 19]01 0012ffc0 77e6f23b debugee!mainCRTStartup+0xe9 [crt0.c @ 206]02 0012fff0 00000000 kernel32!BaseProcessStart+0x230:000> .frame 202 0012fff0 00000000 kernel32!BaseProcessStart+0x23
===============================================================
windbg的快速鍵
===============================================================
ctrl+s 設定符號表
ctrl+p 設定源檔案路徑
ctrl+e 建立子進程開始調試
f6 附加進程進行調試
f5 繼續執行go
shift+f5 停止
ctrl+shift+f5 重啟
f10 單步
F11, F8 步入
shift+f11 步出函數
alt+1 命令視窗
alt+2 局部變數
alt+3 觀察watch
alt+4 寄存器
alt+5 記憶體
alt+6 調用棧
alt+7 反組譯碼
alt+8 記事本
alt+9 進程和線程
===============================================================
異常處理
===============================================================
// debugee.cpp : Defines the entry point for the console application.
//#include "stdafx.h"void loop(void){for (int i = 0; i < 1000; i ++){printf("loop [%d]\n", i);}*(int *)0 = 0;}int main(int argc, char* argv[]){printf("Hello World!\n");try{loop();}catch (...){printf("exception caught.\n");}return 0;}
如果在調試狀態下,調試器首先接管異常處理,這個時候,
1, 如果執行gN,調試器會放棄處理,讓棧回溯代碼繼續尋找異常處理handler,這個時候如果你在執行gN之前,在catch裡面的printf上打一個斷點,可以攔截到異常處理。
2, 如果執行gh, 那麼調試器告訴作業系統說,異常已經處理好了,於是作業系統傻傻的來重啟異常語句,於是又異常。。。轉悠吧。。。但是,如果你在這個時候,手動處理一下異常,比如說,把eip設定到一個安全的位置,例如,下一個語句。
0040105c e8ef000000 call debugee!printf (00401150)00401061 83c408 add esp,800401064 ebdb jmp debugee!loop+0x21 (00401041)>>>異常在這一句 00401066 c7050000000000000000 mov dword ptr ds:[0],0 ds:0023:00000000=????????00401070 5f pop edi00401071 5e pop esi00401072 5b pop ebx00401073 83c444 add esp,44h00401076 3bec cmp ebp,esp00401078 e853010000 call debugee!_chkesp (004011d0)0040107d 8be5 mov esp,ebp0040107f 5d pop ebp00401080 c3 ret
修改 r eip=0x00401070 設定到下一句,恢複執行的時候,就ok了(當然也可以真正的把異常修複了,例如把寫入地址的指標賦給正確的值)
===============================================================
dump檔案
===============================================================
產生小dump
.dump /m f:\debugee_mini.dmp
產生大dump
.dump /ma f:\debugee_large.dmp
===============================================================
源檔案和符號表
===============================================================
0:000> lmstart end module name00400000 0042f000 debugee C (private pdb symbols) H:\temp\debugee\Debug\debugee.pdb77e40000 77f42000 kernel32 (pdb symbols) f:\symbols\kernel32.pdb\DAE455BF1E4B4E249CA44790CD7673182\kernel32.pdb7c800000 7c8c0000 ntdll (pdb symbols) f:\symbols\ntdll.pdb\93E72E109DC84F16AA54797E4DA8C1682\ntdll.pdb0:000> ls 1: // debugee.cpp : Defines the entry point for the console application. 2: // 3: 4: #include "stdafx.h" 5: 6: void loop(void) 7: { 8: for (int i = 0; i < 1000; i ++) 9: { 10: printf("loop [%d]\n", i);0:000> lscCurrent: H:\temp\debugee\debugee.cpp(11)0:000> lsf debugee.cpp
===============================================================
符號伺服器
===============================================================
在windbg或者vs啟動時候設定環境變數,可以調試windows系統的dll
Set _NT_SYMBOL_PATH = symsrv*symsrv.dll*f:\localsymbols*http://msdl.microsoft.com/download/symbols
可以先把符號表下載下來
symchk.exe /r c:\windows\system32 /s SRV*c:\symbolcache\*http://msdl.microsoft.com/download/symbols
參考文獻:
http://www.windbg.info/doc/1-common-cmds.html