以下以skinhgy為例,windbg附加運行
1.
bp 命令是在某個地址下斷點, 可以 bp 0x7783FEB 也可以 bp MyApp!SomeFunction 。
對於后者,WinDBG 會自動找到MyApp!SomeFunction 對應的地址並設置斷點。 但是使用bp的問題在於:
1)當代碼修改之后,函數地址改變,該斷點仍然保持在相同位置,不一定繼續有效;
2)WinDBG 不會把bp斷點保存工作空間中
bp Address或bp 偽寄存器或bp符號名稱:
- 00640080 Simple1Demo!CSimple1DemoApp::InitInstance (void)
- 0:000> bp 00640080
- 0:000> bl
- 0 e 00640080 0001 (0001) 0:**** Simple1Demo!CSimple1DemoApp::InitInstance
- 0:000> x Kernel32!LoadLibraryW
- 7c80aeeb kernel32!LoadLibraryW = <no type information>
- 0:000> bp Kernel32!LoadLibraryW
- 0:000> bl
- 0 e 00640080 0001 (0001) 0:**** Simple1Demo!CSimple1DemoApp::InitInstance
- 1 e 7c80aeeb 0001 (0001) 0:**** kernel32!LoadLibraryW
- 0:000> bp $exentry
- 0:000> bl
- 0 e 00640080 0001 (0001) 0:**** Simple1Demo!CSimple1DemoApp::InitInstance
- 1 e 7c80aeeb 0001 (0001) 0:**** kernel32!LoadLibraryW
- 2 e 0061c895 0001 (0001) 0:**** Simple1Demo!ILT+14480(_wWinMainCRTStartup)
上例說明三種用法作用是一樣的,都是bp Address(windbg內部會換成符號文件對應的地址,或偽寄存器的地址)
bp /1 Address表示該斷點為一次性斷點,有點類似於F4作用於OD,一旦激活就自動刪除了:
如bp /1 00640080
bp Address Passes表示指定斷點激活之前要忽略的次數
默認情況下,斷點在第一次執行斷點位置的代碼時被激活。這種默認情況和把Passes 設置為1是一樣的。要使得斷點在程序至少執行該代碼一次之后才激活,可以將這個值設置為2或更大。例如,值為2時,使得斷點在第二次執行到該代碼時被激活。該參數創建一個在每次執行斷點處的代碼時被減少1的計數器。要查看Passes 計數器的初始值和當前值,使用bl (Breakpoint List)。Passes 僅當程序響應g (Go)命令並執行通過斷點時才減少。單步或跟蹤(tracing)通過它是不會減少的。當Passes 到達1時,可以通過清除並重設斷點來重置它。
我們來試試,用bc把以前斷點都刪除,再設置在第三次運行LoadLibraryW時激活該處斷點
- 0:000> bl
- 0:000> bp 7c80aeeb 3
- 0:000> bl
- 0 e 7c80aeeb 0003 (0003) 0:**** kernel32!LoadLibraryW
我們注意到這個斷點顯示的是0003 (0003) F5運行:
- Breakpoint 0 hit
- eax=00000002 ebx=7ffdc000 ecx=00000000 edx=00a8660c esi=0263f76e edi=0263f6f2
- eip=7c80aeeb esp=0012fd68 ebp=0012fdb0 iopl=0 nv up ei pl nz na po nc
- cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
- kernel32!LoadLibraryW:
- 7c80aeeb 8bff mov edi,edi
- 0:000> bl
- 0 e 7c80aeeb 0001 (0003) 0:**** kernel32!LoadLibraryW
我們注意到這個斷點現在顯示的是0001 (0003),表示前面忽略了兩次,
bu 命令是針對某個符號下斷點。 比如 bu MyApp!SomeFunction 。 在代碼被修改之后, 該斷點可以隨着函數地址改變而自動更新到最新位置。 而且bu 斷點會保存在WinDbg工作空間中, 下次啟動 Windbg 的時候該斷點會自動設置上去。另外,在模塊沒有被加載的時候,bp 斷點會失敗(因為函數地址不存在),而bu 斷點則可以成功。 新版的WinDBG中 bp失敗后會自動被轉成bu
bm 命令也是針對符號下斷點。 但是它支持匹配表達式。 很多時候你下好幾個斷點。 比如,把MyClass 所有的成員函數都下斷點:bu MyApp!MyClass::* , 或者把所有以CreateWindow開頭的函數都下斷點:bu user32!CreateWindow*
這個函數比較有用,比如我想對Draw開頭的函數都下斷點:
- 0:000> bl
- 0:000> bm *!draw*
- 1: 00695930 @!"Simple1Demo!DrawState"
- 2: 0175c790 @!"SkinLog!DrawState"
- 3: 019f65d0 @!"SkinScroll!DrawState"
- 4: 10119d10 @!"SkinHgy!DrawState"
- 0:000> bl
- 1 e 00695930 0001 (0001) 0:**** Simple1Demo!DrawState
- 2 e 0175c790 0001 (0001) 0:**** SkinLog!DrawState
- 3 e 019f65d0 0001 (0001) 0:**** SkinScroll!DrawState
- 4 e 10119d10 0001 (0001) 0:**** SkinHgy!DrawState
bl(breakpoint list)命令列出已存在的斷點的信息
對於每個斷點,該命令顯示以下信息:
- 斷點ID。該ID是一個可以在其他命令中引用這個斷點的十進制數字。
- 斷點狀態。它可以是e (啟用) 或d (禁用)。
- 如果出現字母"u",說明斷點是未定的。即,該斷點中的符號引用還沒有和任何當前已加載的模塊匹配。
- 斷點位置的虛擬地址或符號表達式。如果啟用了源碼行號加載,bl 命令顯示文件和行號信息而不是地址偏移。如果該斷點未定,則它的地址會被省略並出現在列表末尾。
- (僅數據斷點) 數據斷點的類型和大小信息會顯示出來。類型可以是e (執行)、 r (讀/寫)、w (寫)或 i (輸入/輸出)。類型后面是以字節為單位的大小。關於這種類型斷點的更多信息,查看ba (Break on Access)。
- 斷點被激活前需要忽略的剩余次數,后面是在圓括號中的初始次數。(這種斷點的更多信息,查看bp, bu, bm (Set Breakpoint)中對Passes參數的說明。)
- 關聯的進程和線程。如果線程是用三個星號("***")表示的,說明這不是一個指定線程的斷點。
- 符合斷點地址的模塊和函數以及偏移。如果是未定斷點,這里會用括號括起來的斷點地址替代。如果斷點設置在合法地址,但是沒有符號信息,這個域為空。
- 該斷點觸發時要自動執行的命令。這個命令以引號括起來。
bc(breakpoint clear) 命令在系統中移除先前設置的斷點。
使用星號(*)來指定所有斷點
最后介紹下ba斷點
ba 命令就是針對數據下斷點的命令, 該斷點在指定內存被訪問時觸發。 命令格式為
ba Access Size [地址]
Access 是訪問的方式, 比如 e (執行), r (讀/寫), w (寫)
Size 是監控訪問的位置的大小,以字節為單位。 值為 1、2或4,還可以是 8(64位機)。
比如要對內存0x0483DFE進行寫操作的時候下斷點,可以用命令 ba w4 0x0483DFE
在Access 和Size 之間不能加入空格
0:000> bc*
- 0:000> ba r4 00a76748
- 0:000> bl
- 0 e 00a76748 r 4 0001 (0001) 0:**** Simple1Demo!`string'
be 打開斷點
bd 關閉斷點