debug常用命令解析

debug常用命令解析:

1 !address eax查看對應內存頁的屬性

2 vertarget 顯示當前進程的大致信息

3 !peb 顯示process Environment Block

4 lmvm 可以查看任意一個dll的詳細信息  例如:0:026 lmvm msvcrt (deferred)表示察看msvcrt.dll的信息,但是沒有加載 symbol可以通過.reload命令來加載  

5.reload /!sym 加載符號文件  

6 lmf 列出當前進程中加載的所有dll文件和對應的路徑 0:018> lmf  

7 r 命令顯示和修改寄存器上的值 r命令顯示和修改寄存器上的值 0:018> r     顯示寄存器的值 0:018> r eax=0 修改了寄存器,把eax的值修改爲0x0  

8 d命令顯示esp寄存器指向的內存如下 0:018>d esp   用dd命令直接指定054efc14地址 0:018>dd 054efc14  注意:第二個d表示DWORD格式,此外還有db(byte),du(Unicode),dc(char)等等。數據查看指令 d{a|b|c|d|D|f|p|q|u|w|W}d{b|c|d|D|f|p|q}分別是顯示:byte&ASCII, double-word&ASCII,double-word,double-precision,float,pointer-sized,quad-word數據;DA用於顯示ASCII,DU用於顯示UNICODE;BYB,BYD,顯示binary和Byte及binary和DWORD補充一個DV,用於查看本地變量用的

9 e命令可以用來修改內存地址跟d命令一樣,e命令後面也可以跟類型後綴,比如ed命令表示用DWORD的方式修改。下面的命令把054efc14地址上的值修改爲11112222。 0:018>ed 054efc14 11112222 修改後可以用dd命令來查看內存。 0:018>dd 0543fc14 L4 L4參數指定內存區間的長度爲4個DWORD,這樣輸出只有1行,而不是8行了。  

10s 命令用來搜索內存具體見help文檔

11!runaway 可以顯示每一個線程的cpu消耗 0:018> !runaway 結果如下:  0:83c       0 days 0:00:00.406  13:bd4       0 days 0:00:00.046  10:ac8       0 days 0:00:00.046  24:4f4       0 days 0:00:00.031  上面輸出的第一列是線程的編號和線程ID,後一列對應的是該線程在用戶態模式中的總的繁忙時間。  在該命令加上f參數,還可以看到內核態的繁忙時間,當進程內存佔用率比較高的時候,通過該命令可以方便的找到對應的繁忙線程。  

12 ~ 命令是用來切換目標線程 0:018> ~ 可以顯示線程的信息 0:018> ~0s把當前的線程切換到0號線程,也就是主線程,切換後提示符會變爲0:000.

13 ~* 命令列出當前進程中的所有線程的詳細信息

14~*kb命令列出所有線程的堆棧

15 k 命令用來顯示當前線程的堆棧,如下 0:018> k 跟d命令一樣,k後面也可以跟很多後綴,比如kb kp,kn,kv,kl等,這些後綴控制了顯示的格式和信息。棧指令k[b|p|P|v]這四條指令顯示的內容類似,但是每個指令都有特色,KB顯示三個參數,Kp顯示所有的參數,但需要Full Symbols或Private PDBSymbols支持。KP與Kp相似,只是KP將參數換行顯示了。Kv用於顯示FPO和調用約定,KD,用於顯示Stack的Dump,在跟蹤棧時比較有用。這些指令區分大小。

16 u命令把指定地址上的代碼翻譯成彙編輸出 0:018> u 7739d023 USER32!NtUserWaitMessage: 7739d023 b84a120000       mov     eax,0x124a 7739d028 ba0003fe7f       mov     edx,0x7ffe0300 7739d02d ff12             call    dword ptr [edx] 7739d02f c3               ret 如果符號文件加載正確,可以用uf命令直接反彙編整個函數,比如uf USER32! NtUserWaitMessage  

17 x 查找符號的二進制地址如下 0:018> x msvcr!printf 77bd27c2 msvcrt!printf = <no type information> 上面的命令找到了printf函數的入口地址在77bd27c2   0:001> x ntdll!GlobalCounter 7c99f72c ntdll!GlobalCounter = <no type information> 上面的命令表示ntdll!GlobalCounter這個變量保存的地址是7c99f72c。注意:符號對應的是變量和變量所在的地址,不是變量的值,上面只是找到GlobalCounter這個變量的值是7c99f72,要找到變量的值,需要用d命令讀取內存地址來獲取。   X命令還支持通配符,比如x ntdll !*命令列出ntdll模塊中的所有的符號,以及對應的二進制地址。  

18 dds 打印內存地址上的二進制值同時自動搜索二進制值對應的符號。比如要看看當前**中保存了那些函數地址,就可以檢查ebp指向的內存 0:018>dds ebp 0013ed98  0013ee24 0013ed9c  75ecb30f BROWSEUI!BrowserProtectedThreadProc+0x44 0013eda0  00163820 0013eda4  0013ee50 0013eda8  00163820 0013edac  00000000 0013edb0  0013ee10 0013edb4  75ece83a BROWSEUI!__delayLoadHelper2+0x23a 0013edb8  00000005 0013edbc  0013edcc 0013edc0  0013ee50 0013edc4  00163820 0013edc8  00000000 0013edcc  00000024 0013edd0  75f36d2c BROWSEUI!_DELAY_IMPORT_DESCRIPTOR_SHELL32 0013edd4  75f3a184 BROWSEUI!_imp__SHGetInstanceExplorer 0013edd8  75f36e80 BROWSEUI!_sz_SHELL32 0013eddc  00000001 0013ede0  75f3726a BROWSEUI!urlmon_NULL_THUNK_DATA_DLN+0x116 0013ede4  7c8d0000 SHELL32!_imp__RegCloseKey <PERF> (SHELL32+0x0) 0013ede8  7c925b34 SHELL32!SHGetInstanceExplorer   這裏dds命令從ebp指向的內存地址0013ed98開始打印,第一列是內存地址的值,第二列是地址上對應的二進制數據,第三列是二進制對應的符號。上面的命令自動找到了75ecb390f對應的符號是BROWSEUI!BrowserProtectedThreadProc +0x44.   Com interface 和c++ vtable裏面的成員函數都是順序排列的。所以,dds命令可以方便的找到虛函數表中的具體的函數地址,比如用下面的命令可以找到OpaqueDatinfo類型中虛函數的實際函數地址。首先通過x命令找到OpaqueDataInfo虛函數地址 0:000> x ole32!OpaqueDataInfo::vftable’ 7768265c ole32!OpaqueDataInfo::`vftable' = <no type information> 77682680 ole32!OpaqueDataInfo::`vftable' = <no type information> 接下來dds命令可以打印出虛函數表中的函數名字 0:000> dds 7768265c

19 .frame 命令在棧中切換以便檢查局部變量要查看局部變量的需要如下: 1查看線程的callstack 0:018>knl 00 0012f7a0 7c821c94 ntdll!KiFastSystemCallRet 01 0012f7a4 7c836066 ntdll!NtRequestWaitReplyPort+0xc 02 0012f7c4 77eaaba3 ntdll!CsrClientCallServer+0x8c 03 0012f8bc 77eaacb8 kernel32!ReadConsoleInternal+0x1b8 04 0012f944 77e41990 kernel32!ReadConsoleA+0x3b   第一列的號稱爲Frame num,通過.frame命令就可以切換到對應的函數中檢查局部變量,比如我們檢查kernel32!ReadConsoleA,這個函數的frame num是4,於是,我們如下 2 iframe切換到指定行號的函數中 0:018> .frame 4 3然後調用x顯示當前frame的局部變量,比如這個函數中有兩個局部變量pcls和rawptr 0:018> x 0012fced pcls = 0x0039ba80 0012fcd8 rawptr = 0x0039ba80  

20 dt 格式化顯示資料 Dt命令格式化顯示變量的資料和結構 0:000> dt pcls Local var @ 0x12fce4 Type MyCls* 0x0039ba80    +0x000 str              : 0x00416648  "abcd"    +0x004 inobj            : inner 上面的命令打印出pcls的類型是MyCls指針,指向的地址是0x0039ba80,其中的兩個class成員的偏移分別在+0和+4,對應的值在第2列顯示。加上-b -r參數可以顯示inner class和數組的信息: 0:000> dt pcls -b -r Local var @ 0x12fce4 Type MyCls* 0x0039ba80    +0x000 str              : 0x00416648  "abcd"    +0x004 inobj            : innner       +0x000 arr              :  "abcd"        [00] 97 'a'        [01] 98 'b'        [02] 99 'c'        [03] 100 'd'        [04] 0 ''        [05] 0 ''        [06] 0 ''        [07] 0 ''        [08] 0 ''        [09] 0 '' 對於任意的地址,也可以手動指定符號類型來格式化顯示。比如把0x0039ba80地址上的數據用MyCls類型來顯示: 0:000> dt 0x0039ba80 MyCls    +0x000 str              : 0x00416648  "abcd"    +0x004 inobj            : innner

21bp設定調試斷點  比如可以這樣寫:0:018>bp notepad!WinMain 在notepade的winmain函數處下斷點斷點的位置可以用符號來表示,如上,也可以直接用地址以及windbg的Pseudo_Register(虛擬寄存器)。比如,我們用$exentry表示進程的入口,那麼可以用bp @$exentry在進程的入口設置斷點,如果notepade的winmain的入口地址爲01006420,那麼斷點也可以這麼寫 Bp 01006420 bp mysource.cpp:143` "j (poi(MyVar)”0n20) ''; 'g' "意思就是:當myvar的值等於0x20時,g命令繼續執行下面一個設置條件斷點 0:001> bp exceptioninject!foo3 “k; .echo ‘breaks’ ; g” 在exceptioninject!foo3上設置斷點後,每次斷下來後,先用k顯示callstack,然後用.echo命令輸出簡單的字符串‘breaks’,最後g命令繼續執行。下面看一個更復雜的設置條件斷點的例子: ba w4 execptioninject!i ”j(poi(exceptioninject!i)<0n40) ‘.printf/”exceptioninject!i value is :%d/”,poi(exceptioninject!i); g’ ; ‘.echo stop!’ ” 首先ba w4 exceptioninject!i 表示在修改exceptioninject!i這個全局變量的時候,停下來, j(judge)命令的作用就是對後面的表達式作條件判斷如果爲true,執行第一個單引號裏面的命令,否則執行第2個單引號裏面的命令。條件表達式是(poi(exceptioninject!i)<0n40),在windbg中excepioninject!i符號表示符號所在的內存地址,而不是符號的數值,相當於c語言的&操作符的作用,poi命令就是取這個地址上的值,相當於c語言的*操作符。所以這個條件判斷的意思就是判斷exceptioninject!i的值,是否小於十進制的40。如果爲真,就執行第一個單引號,‘.printf/”exceptioninject!i value is :%d/”,poi(exceptioninject!i); g’,如果爲假,就執行第二個單引號‘.echo stop!’ 第一個單引號裏有三個命令,.printf .echo 和g。這裏的printf和c語言的printf函數語法一樣,不過由於這個printf命令本身是在ba命令的雙引號裏面,所以需要用/來轉義print中的引號。第一個引號的作用是:打印出當前exceptioninject!i的值,.echo命令換行 g命令繼續執行第二個引號的作用就是顯示stop,由於後面沒有g命令,所以windbg會停下。

22 bm 使用模式匹配設置斷點這個功能需要符號表的支持,bm可以通過模式一次設置多個斷點,比如 bm mydriver!FastIO* 可以將所有與FastIO*模式匹配的函數下設置斷點,比如FastIoRead ,FastIoWriter等函數都會被設置上斷點。需要注意的是,bm命令需要full or export symbols支持。

23 ba 對內存訪問設置斷點 break on access 就是對於內存訪問設置斷點,對於在多核處理或者多核處理器調試的時候很有用,對於調試多線程也很有用,比如說,我們可以對一個全局變量設置斷點, ba mydriver!gMonitoreedDevices , 如果你認爲這個變量的值被莫名的修改了,相信通過ba設置的斷點,你可以很快找到是誰修改的。也可以這樣 ba w4 0x4000000 "kb;g" 當0x4000000地址有寫操作時,進入斷點 。w表示類型爲寫 4表示長度爲4個字節

24 bl 列出所有的斷點 break list

25 bc 清除斷點       break clear

26 be 開啓斷點      break enable

27 bd禁用斷點       break disable 以上提到的斷點指令通過和j指令很容易形成條件斷點,比如 bp USER32!GetMessageW "r $t1=poi(esp+4);r $t2=poi(@$t1+4); j(@$t2 = 0x102 ) 'du @$t1+8 L2;gc';'gc'"這個條件斷點,截取WM_CHAR消息,並將字符(包括中文)顯示出來。條件斷點的最簡形式:bp Address "j (Condition) 'OptionalCommands'; 'gc' "Address是指令的地址,Condition是一個條件表達式,如果@eax=1,'OptionalCommands'是在斷點被擊中並且表達式成立時要執行的指令;gc指定是從一個條件斷點返回,是不可少的一部分。

28跟蹤指令T,TA,TB,TC,WT,P,PA,PC   T指令單步執行,在源碼調試狀態下,可指源碼的一行,根據不同的選項也可以爲一行ASM指令;TA單步跟蹤到指定地址,如果沒有參數將運行到斷點處。TB執行到分支指令,分支指令包括calls, returns, jumps, counted loops, and while loopsTC執行到Call指令WT Trace and Watch Data,一條強大指令,對執行流程做Profile,執行一下看看結果吧P,PA,PC相信不用多做解釋,大家也都明白了

29源代碼操作指令.,lsf,lsc,ls,l,lsp .指令打一個源文件,可以打開一個全路徑的文件,也可以通過函數地址來打開並定位到源文件中函數的位置,如. –a myapp!main,. j:/mydriver/mydriver.clsf指定一個源文件爲當前源文件,使用lsc可顯示當前指定的源文件ls可顯示源文件的代碼。Lsf可以使用全路徑,如果源路徑已經設置,也可以直接指定源文件名稱。如lsf mydriver.c,lsf j:/mydriver/mydriver.clsc顯示當前源文件ls顯示當前源文件的代碼,如ls 200顯示第200行l 用於設置源文件選項lsp 設置源文件行在調試時顯示範圍比如,顯示當前行的前50,後50,lsp 100但通常使用Windbg時,可以直接用Ctrl+O來打開並查看源文件

30 查詢符號 kd> x nt!KeServiceDescriptorTable* 8046e100 nt!KeServiceDescriptorTableShadow = <no type information> 8046e0c0 nt!KeServiceDescriptorTable = <no type information> kd> ln 8046e100 (8046e100)     nt!KeServiceDescriptorTableShadow     | (8046e140)     nt!MmSectionExtendResource Exact matches: nt!KeServiceDescriptorTableShadow = <no type information>

31!gle 查看LastError值

32指定進制的形式0x/0n/0t/y 分別表示 16/10/8/2進制 ? 0x12345678+0n10 Evaluate expression: 305419906 = 12345682

33!sym noice/quiet symbol prompts開關

34.srcpath 設置源代碼的路徑

35dv查看本地變量

36!teb 顯示當前線程的執行塊(execution block)

37!peb 顯示當前進程的執行塊(execution block)

38ln[Address] 顯示當前地址上的對象類型

39!locks 顯示死鎖

40!handle可以獲取整個進程或者某一個handle的詳細信息首先運行以下!handle,可以看到當前進程的每個一個handle的類型,以及統計信息 0:002>!handle Handle 4  Type      key Handle c    Type     keyEvent ……. 然後找到一個key,查看詳細信息 0:001>!handle 4 f 就會列出這個handle的詳細信息。

41!htrace命令檢查操作句柄的歷史記錄 !htrace命令可以打印出指定的handle的最近幾次調用堆棧 0:001>!htrace 384

42!cs列出CriticalSection的詳細信息

43!threadpool能看到完成端口,線城池工作線程和timer回調佔線程池的情況

44.time 可以看到進程跑了多長時間

45 !dso 查看當前線程中有哪些對象,分析泄露時用到

46.dump保存進程的dump文件 Dump文件是進程的內存鏡像,可當在調試器中打開dump文件時,使用上面的命令檢查,看到的結果跟用調試檢查進程看到的一樣 .dump /ma c:/testdump.dmp 這個命令把當前進程的鏡像保存爲c:/testdump.dmp,其中/ms參數表示dump的文件應該包含進程的完整信息。在windbg中,通過file—open---open Crash dump菜單打開dump文件進行分析。打開文件後,運行調試命令看到的信息和狀態就是dump文件保存時進程的狀態。通過dump文件能夠方便的保存發生問題時進程的狀態,方便事後分析。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章