Windbg調試命令詳解(4)

5. 內存命令

這一節裏面,我們學習如何查看內存信息。內存是存儲數據、代碼的地方,通過內存查看命令可以分析很多問題。相關命令可以分爲:內存查看命令和內存統計命令。內存統計命令用來分析內存的使用狀況。

5.1 查看內存

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

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

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

內存類型 

基本類型

  • 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值

如果讀者對此感覺不明白,特別是組合模式究竟是何種情形?看下例應能清楚。下例將同一個ASCII字符串,分別以ASCII字符串、Unicode字符串以及組合模式等共五種方式顯示:

read-mem

此係列命令還有一些可加利用的開關選項,介紹如下:

/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 

數組形式內存

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

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

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

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

查看鏈表內存

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

  • dl  開始地址

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

  • dl  b  尾地址

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

5.2 內存信息

系統的內核空間很大的,想知道這麼廣大的內存空間裏面都有些什麼東西嗎?想要知道一個內存地址,到底是被一個內核棧使用着,亦或被堆管理器使用着嗎?我們這一節就領大家看看內存的地理概況。首先看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

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

5.3 其他命令

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

  • !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個字節被申請提交。

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