Windbg 內存命令 《第四篇》


  內存是存儲數據、代碼的地方,通過內存查看命令可以分析很多問題。相關命令可以分為:內存查看命令和內存統計命令。內存統計命令用來分析內存的使用狀況。

一、查看內存

  有非常豐富的內存查看命令,它們被容易為d*格式,如下所示:

  • d[類型] [地址范圍]

  d代表Display,類型包括:字符、字符串、雙字等。具體來說,d*命令共有這幾種:d、da、db、dc、dd、dD、df、dp、dq、du、dw、dW、dyb、dyd、ds、dS。

  1、內存類型

  基本類型

  • dw = 雙字節WORD格式;
  • dd = 4字節DWORD格式 ;
  • dq = 8字節格式;
  • df = 4字節單精度浮點數格式;
  • dD =8字節雙精度浮點數格式;
  • dp = 指針大小格式,32位系統下4字節,64位系統下為8字節;

  基本字符串

  • da = ASCII字符串格式;
  • du = UNICODE字符串格式;
  • db =字節 + ASCII字符串;
  • dW = 雙字節WORD + ASCII字符串;
  • dc = 4字節DWORD + ASCII字符串;

  高級字符串:

  • ds = ANSI_STRING類型字符串格式;
  • dS = UNICODE_STRING類型字符串格式;

  二進制 + 基本類型

  • byb = 二進制 + 字節;
  • byd = 二進制 + DWORD值;

  /c 列數:指定列數。默認情況下,列數 等於16除以列長,如dd命令的默認列數即為4列(=16/4)。例:

  • dd  /c  8

  此命令每列顯示8個DWORD數,即32字節內容。

  /p:此選項用來顯示物理內存信息,只能用於內核模式中。不使用此命令時,都將顯示虛擬內存信息。如:

  • d  /p  [地址范圍]

  L 長度: 默認情況下,d命令只顯示固定長度的內存,一般為128或64字節。L可指定長度,如下面的命令將顯示地址0×80000000開始處的0×100個字節內容:

  • db  0×80000000  L100 

  2、數組形式內存

  難能可貴的是,d*命令還能夠以數組形式顯示一段內存信息,包括:dda, ddp、 ddu、dds、dpa、dpp、dpu、dps、dqa、dqp、dqu、dqs。

  何謂“以數組形式顯示”呢?這一組命令能夠將指定地址處的內容,作為一系列指針,進而顯示指針所指處內容。聽上去有點拗口吧,讀者這樣想會清楚些:前一組命令顯示address值,本節這一組命令顯示*address值。

  程序代碼中如有類似“char *array[10]”的數組變量,可使用這些命令顯示數組內容。下面會有例子。這一系列命令實則由第一組命令演化而來,可分為三組:

  • 4字節DWORD為單位的dd*系列數組指令;
  • 指針長度為單位的dp*系列數組指令;
  • 8字節為單位的dq*系列數組指令。

  3、查看鏈表內存

  最后,d*命令的另一個變體是以鏈表形式顯示內存內容。命令如下:

  • dl  開始地址

  默認情況下,以正向從頭到尾遍歷鏈表;也可反向(由尾向頭)遍歷,指定b開關選項:

  • dl  b  尾地址

  應注意的是,命令dl是Display List的縮寫,這里的鏈表不能是用戶自定義的鏈表,而專指符合LIST_ENTRY或SINGLE_LIST_ENTRY格式的鏈表。

二、內存信息

  系統的內核空間很大的,想知道這么廣大的內存空間里面都有些什么東西嗎?想要知道一個內存地址,到底是被一個內核棧使用着,亦或被堆管理器使用着嗎?我們這一節就領大家看看內存的地理概況。首先看Address命令:

  • !address  [地址]

  顯示進程或系統的內存狀態、信息,!address是最好的工具。不加任何參數,在用戶模式下此命令將以內存塊為單位,列出從地址0開始到0×80000000(略小於)的全部地址空間信息;內核模式下,將列出從地址0×80000000開始到0xFFFFFFFF(略小於)的全部地址空間信息;如指定地址值,則將顯示此地址所在內存塊的內存信息(此命令在Vista以后系統中,不能在內核模式下正常使用,此Bug應會在Windbg的以后版本中被修正)。下面分別截取了用戶與內核空間中的內存信息片段:

0:009> !address                            

        BaseAddress      EndAddress+1        RegionSize     Type       State                 Protect             Usage
------------------------------------------------------------------------------------------------------------------------
+        0`00000000        0`00010000        0`00010000             MEM_FREE    PAGE_NOACCESS                      Free       
+        0`00010000        0`00020000        0`00010000 MEM_MAPPED  MEM_COMMIT  PAGE_READWRITE                     Heap64     [ID: 1; Handle: 0000000000010000; Type: Segment]
+        0`00020000        0`00021000        0`00001000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE                       
+        0`00021000        0`00030000        0`0000f000             MEM_FREE    PAGE_NOACCESS                      Free       
+        0`00030000        0`00031000        0`00001000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE                       
// 省略很多...

  上圖截取了兩段用戶區內存,第一段從0開始,長度0×10000,狀態為釋放(FREE),表明這一段地址空間不可用;第二段從0×10000開始,長度0×1000,屬於私有內存,狀態為已提交,保護模式為可讀寫,此內存塊被用於環境塊。

  下面給大家解釋一下內存塊中的幾個值:

  內存類型:即Type值,共有四種:第一種是什么都不是,即尚未被使用的;第二種是MEM_IMAGE,即地址映射於一個可執行鏡像文件片段,如DLL文件;第三種是MEM_ MAPPED,即地址映射於不可執行的鏡像文件片段,如頁文件;第四種是MEM_PRIVATE,即私有有內存,這里的私有是針對進程而言的,私有內存無法在多個進程間共享;

  保護模式:即Protect值,上例中見識了兩種保護模式,NOACCESS和READWRITE。從字面即很容易理解其意思,前者是不能做任何訪問的,因為空閑內存是無效內存;后者則可讀可寫,但不能執行,說明是保存數據的地方。所有可用的保護包括:PAGE_NOACCESS(不可訪問),PAGE_READONLY(只讀),PAGE_READWRITE(讀寫),PAGE_EXECUTE(可執行), PAGE_EXECUTE_READ(執行並可讀),PAGE_EXECUTE_READWRITE(執行並可讀寫),PAGE_WRITECOPY(寫時拷貝),PAGE_EXECUTE_WRITECOPY(執行,並寫時拷貝), PAGE_GUARD(保護)。

  內存狀態:即State值,共三種:MEM_FREE,即空閑內存;MEM_RESERVED,即保留內存,保留內存尚不能被實際使用,但其地址空間已被預留,尚需一個提交動作。最后是MEM_COMMIT,即內存已被提交,正在被使用。

  內存用途:即Usage值,有這樣一些值和用途。RegionUsageIsVAD:表示此地址區域已被分配;RegionUsageFree:代表此地址區域已被釋放,既沒有保留也沒有被提交,將來可以申請使用;

  • RegionUsageImage:代表此地址區域被映射到二進制文件的鏡像;Region UsageStack:代表此地址區域用於線程棧;RegionUsageTeb:代表此地址區域用於保存目標進程的所有線程的TEB結構;
  • RegionUsageHeap:代表此地址區域用於堆內存;RegionUsage Pdb:代表此地址區域用於保存目標進程的PEB結構;RegionUsageProcessParameters:代表此內存塊用於保存目標進程的啟動參數;
  • RegionUsageEnviromentBlock:代表此地址區域用於保存目標進程的環境塊。

  用戶環境下可使用下面的命令顯示內存統計信息,包括內存用途、內存類型、內存狀態。

  • !address  -summary
0:009> !address  -summary

--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free                                    101        0`7a5ba000 (   1.912 Gb)           95.60%
Image                                   294        0`022b8000 (  34.719 Mb)  38.49%    1.70%
                                 7        0`0113a000 (  17.227 Mb)  19.10%    0.84%
Stack32                                  51        0`01100000 (  17.000 Mb)  18.84%    0.83%
Heap32                                   26        0`006e0000 (   6.875 Mb)   7.62%    0.34%
MappedFile                               12        0`0069e000 (   6.617 Mb)   7.34%    0.32%
Stack64                                  51        0`00440000 (   4.250 Mb)   4.71%    0.21%
Other                                     8        0`001c1000 (   1.754 Mb)   1.94%    0.09%
Heap64                                    9        0`00190000 (   1.563 Mb)   1.73%    0.08%
TEB64                                    17        0`00022000 ( 136.000 kb)   0.15%    0.01%
TEB32                                    17        0`00011000 (  68.000 kb)   0.07%    0.00%
PEB64                                     1        0`00001000 (   4.000 kb)   0.00%    0.00%
PEB32                                     1        0`00001000 (   4.000 kb)   0.00%    0.00%

--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_PRIVATE                             181        0`02f11000 (  47.066 Mb)  52.17%    2.30%
MEM_IMAGE                               295        0`022b9000 (  34.723 Mb)  38.49%    1.70%
MEM_MAPPED                               18        0`0086c000 (   8.422 Mb)   9.34%    0.41%

--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_FREE                                101        0`7a5ba000 (   1.912 Gb)           95.60%
MEM_RESERVE                              94        0`02f5d000 (  47.363 Mb)  52.50%    2.31%
MEM_COMMIT                              400        0`02ad9000 (  42.848 Mb)  47.50%    2.09%

--- Protect Summary (for commit) - RgnCount ----------- Total Size -------- %ofBusy %ofTotal
PAGE_EXECUTE_READ                        56        0`01414000 (  20.078 Mb)  22.26%    0.98%
PAGE_READONLY                           129        0`0117a000 (  17.477 Mb)  19.37%    0.85%
PAGE_READWRITE                          153        0`004b5000 (   4.707 Mb)   5.22%    0.23%
PAGE_WRITECOPY                           26        0`0004c000 ( 304.000 kb)   0.33%    0.01%
PAGE_READWRITE|PAGE_GUARD                34        0`00048000 ( 288.000 kb)   0.31%    0.01%
PAGE_EXECUTE_READWRITE                    2        0`00002000 (   8.000 kb)   0.01%    0.00%

--- Largest Region by Usage ----------- Base Address -------- Region Size ----------
Free                                      0`030b0000        0`6cf40000 (   1.702 Gb)
Image                                     0`75d71000        0`00879000 (   8.473 Mb)
                                 0`7f0e0000        0`00f00000 (  15.000 Mb)
Stack32                                   0`00cd0000        0`000fd000 (1012.000 kb)
Heap32                                    0`02f13000        0`0019d000 (   1.613 Mb)
MappedFile                                0`01a90000        0`002cf000 (   2.809 Mb)
Stack64                                   0`00160000        0`00039000 ( 228.000 kb)
Other                                     0`006b0000        0`00181000 (   1.504 Mb)
Heap64                                    0`02b90000        0`000bf000 ( 764.000 kb)
TEB64                                     0`7ef76000        0`00002000 (   8.000 kb)
TEB32                                     0`7ef78000        0`00001000 (   4.000 kb)
PEB64                                     0`7efdf000        0`00001000 (   4.000 kb)
PEB32                                     0`7efde000        0`00001000 (   4.000 kb)

  上圖分別以內存使用、內存類型、內存狀態顯示用戶空間內存統計信息。

  和!address命令類似的,用戶模式下還有下面兩個命令可用:

  • !vprot  [地址]
  • !vadump  [-v]

  命令!vprot顯示指定內存塊的信息,側重於內存保護信息;命令!vadump顯示整個內存空間信息,dump者傾瀉也,開啟-v選項將顯示詳細(Verbose)信息。

  上面講過,用戶環境下使用“!address  –summary”可顯示用戶空間的內存統計信息;現在再看兩個內核命令,在內核環境下顯示內存的統計信息:

  • !memusage

  此命令從物理內存角度顯示內存統計信息。無數個頁表信息將被打印出來,可以說是“最內存”的信息。此命令會查看所有的頁幀,所以運行時會非常地耗時。

  • !vm

  此命令從虛擬內存的角度顯示內存統計信息,不僅能從全局角度顯示虛擬內存的使用情況,還能以進程為單位顯示內存使用情況。

三、其他命令

  內核模式下,查看文件緩存信息,命令格式如下:

  • !filecache

  此命令在用戶內核模式下,顯示文件緩存和頁表狀態。每一行信息表示一個虛擬地址控制塊 (VACB)。虛擬地址控制塊可能對應着一個命名文件,也可能對應着一個元數據塊。如果對應着一個命名文件,則此文件名稱將被顯示,否則顯示元數據名稱。

  實驗:查看文件緩存

很多軟件都使用文件緩存的方式保存數據,比如Office Word。直接查看WORD文檔,由於其
內部格式不透明,故而不便分析。但如果使用WORD打開一個txt文本文檔,它就會以文本文檔
的方式來處理之,並且依舊使用文件緩存的方式。

讀者用WORD打開一個TXT文檔(比如:測試.txt)。
運行內核調試器並執行!filecache命令,在打印信息中查找“測試.txt”。

  用戶模式下查看堆信息,命令格式如下:

  • !heap

  下面的清單顯示了某個進程中共有4個堆:

0:004> !heap -a
Index   Address  Name      Debugging options enabled
  1:   00150000
    Segment at 00150000 to 00250000 (00031000 bytes committed)

  2:   00250000
    Segment at 00250000 to 00260000 (00006000 bytes committed)

  3:   00260000
    Segment at 00260000 to 00270000 (00003000 bytes committed)

  4:   00390000
    Segment at 00390000 to 003a0000 (00008000 bytes committed)
    Segment at 01370000 to 01470000 (0007b000 bytes committed)

  堆資源是屬於進程的,每個進程都會創建若干個堆,如C運行時堆、進程默認堆等。以第一個堆為例,地址范圍是[0x150000,0x250000],已經有0×31000個字節被申請提交。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM