C军

不玩博客了!

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

  内存是存储数据、代码的地方,通过内存查看命令可以分析很多问题。相关命令可以分为:内存查看命令和内存统计命令。内存统计命令用来分析内存的使用状况。

一、查看内存

  有非常丰富的内存查看命令,它们被容易为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个字节被申请提交。

posted on 2014-05-15 18:22  逆心  阅读(10836)  评论(7编辑  收藏  举报