windbg学习笔记(3)

第一部分 事件处理

调试事件与异常

         windows定义了九种调试事件,其中异常是其中的一种调试事件(EXCEPTION_DEBUG_EVENT)。异常也存在包括win32异常,调试器异常,编译器异常(VC异常),托管异常(.net异常),其他异常(主动调用RaiseException抛出异常)。

二次机会

         对于每个异常,windows异常处理模块给与两次处理异常的机会,也就是说程序拥有两次处理机会,处理后调试器会向系统返回一直处理结果。如果最后一次无法处理完异常,windows本身会调用默认的异常处理(用户态下抛出默认提示框,内核下蓝屏)。

         对于第一次处理异常机会,调试器一般会放弃处理,让系统继续分发,交给自身的异常处理程序处理,对于第二次处理机会,调试器一般会断在产生异常的地方。(与原文表述不同)

GH和GN命令

         在调试器中断异常后,可以使用G命令(go)恢复程序运行,我们可以指定程序关于异常处理的结果,也就是如果GH(go handle)表示此异常得到处理,如果是GN(go not handle)表示异常为处理.

第二部分 控制调试目标

初始断点

         windows进程加载器在完成了进程在用户态下最基本的初始化后,系统的进程初始化函数主动触发中断指令(int 3),这种断点称之为初始断点

         我们使用kn命令来查看调用栈的情况,可以看到这个断点是调试器创建的。

         在调试选项的时候加入-g选项,以忽略初始断点,也就是不在将程序中断给用户。如果需要分析程序的入口函数,初始断点是非常有效的。

单步执行

         windbg提供两种单步执行的模式,一种是源码级单步和汇编级单步。

         和ollydbg一样,windbg也提供两种单步的方式,一种是单步步入,另外一种是单步步入。区别和ollydbg是一致的。前者windbg称为单步(step),后者称之为跟踪(trace)。

  • p:单步步入(进入函数)
  • t:单步步过(不进入函数,只是执行完毕)
  • 完整用法:p|t [r:是否显示寄存器信息] [=startaddress] [count] [“command”]

         关于步入操作,在CPU上都是通过置标志寄存器TF位来实现的,每当执行完一条程序(执行完TF为0),置TF位为1,在下条指令执行前检查TF情况,以此判断是否需要单步。

单步执行到指定位置

         pa或者ta用来执行到指定代码。

  • 完整用法:pa|ta [r] [=startaddress] [endaddress]

执行到下一个函数调用

         pc或者tc命令用来执行到下一个函数调用,count指定执行的函数的个数,这也就是为什么可以选择pc或者tc的原因(如果只是在下一个函数调用前中断,t命令或者p命令是相同的功能)。而count数可以指定执行的函数个数,这就可以判断在count个函数调用前的count个函数的执行方式。

  • 完整用法:pc|tc [r] [=startaddress] [count]

单步执行到下一个分支

         tb命令是单步执行到下一个分支,但是对于x86的机器只能用于内核调试,对于x64的可以用于内核和用户调试。

  • 完整命令:tb [r] [=startaddress] [count]
    • x86无法使用用户调试
    • x64可以使用

继续运行

         g命令是最常用的恢复运行的命令。其中a是硬件断点,不含a为软件断点。如果没有任何参数则执行到已存在断点处。

  • g[a] [=startaddress] [Breakaddress] [“breakcommand”]
  • gh:处理异常
  • gn:报告未处理异常
  • gu:返回上一个函数
  • gc:使用条件断点

跟踪监视

         跟踪是调试器的灵魂,wt命令是windbg跟踪的命令

总结

         总结如下:

第三部分 使用断点

软件断点

         windbg一共有三种设置软件断点的命令:bp,bm,bu,最常见的就是bp命令

         bp命令的格式如下:

  • bp [ID] [Options] [Address[Passes]] [“Command”]
    • ID:设置断点号,没有什么重要作用
    • Options:选项
      • /1:一次性断点,用完就从断点表中删去
      • /p或者/t:只在当前进程或者线程中才触发此断点
      • /c或者/C:中断给用户最大调用深度或者最小调用深度!!
    • Address:断点地址//可以是内存地址,也可以是符号函数地址(printf)
    • Passes:限制中断次数,如果Passes==0,则放行程序,不中断!

               bu命令:设置延迟断点,也就是说windbg可以允许当程序模块没有加载,便可以提前设置断点,当模块加载执行的时候,断在目标断点处。

         bm命令:批量设置断点,通常是设置模糊匹配断点或者成员函数断点,把MyClass 所有的成员函数都下断点: bu MyApp!MyClass:: ,或者把所有以CreateWindow开头的函数都下断点: bu user32!CreateWindow 。但是在设置批量断点的时候,调试器需要确认匹配的符号是代码还是数据,也就是说bm命令执行的前提是需要知道一个符号的类型。这就可能造成以下的问题。

         此问题的最佳解决方案是:首先设置一个空的符号目录(.sympath .),然后.reload,然后执行bm命令。

硬件断点

         ba命令用于设置硬件断点。

  • ba Access Size [ID] [Options] [Address[Passes]] [“Command”]
    • Access:表示设置硬件断点的类型
      • e:表示对指令进行读写时,触发断点,和软件中断类型,只是不修改指令
      • w:对指定地址进行写入操作触发断点
      • r:对指定地址进行读取操作触发断点
      • i:对指定的地址执行IO操作触发断点

条件断点

         条件断点利用之前的断点命令加上调价判断合并而来,语法如下:

  • bp|bm|ba|bu address ".if(Condition){Command} .else{gc}"
    mark

地址表达式

  • 模块名!函数符号:dbgee!WinMain
  • 内存地址:00401000:
  • 源代码调试:module!SourceCodeFile:Line
  • C++类方法:Class::ClassMethod

针对线程设置断点

  • ~ThreadId bp|bm|ba

管理断点

  • bl:列举所有断点
  • bc: 删除断点
  • bd:禁止断点
  • be:启用断点

第四部分 观察栈

显示栈回溯

  • k命令:基本的栈回溯
    • 显示结果的第二列是:是函数的返回地址,这是在父函数中的指令地址(也就是说调用栈上面函数的指令的下一条指令)。
  • kb命令:显示存放在栈上面的前三个参数
    • 需要注意的是这三个参数不一定是函数的参数,只是存放在栈上面三个值。
    • kb命令仅仅显示三个参数,而且顺序固定 ebp+8,ebp+c ebp+10,如果需要查看第四个,可以使用dd ebp+14。
  • kp命令:显示堆栈函数原型
    • 前提条件是:需要得到程序的私有符号,如果没有调试对象的私有符号,windbg不显示参数。
  • kv命令:显示栈指针省略(FPO)和函数调用约定
    • 和kb前面保持一致,增加了上述的新内容
  • kn:显示序号

观察栈变量

  • dv命令:观察栈变量:dv /i/t/V
    • 前提:拥有私有符号可以有效使用。

         【重点】如果没有私有符号,可以有两种方法获取栈变量,第一种方法是直接观察内存窗口,以及使用内存显示页面,根据EBP的布局来显示数据。第二种方法是更具汇编指令提供的内存指令,获取对内存的引用。借此获取栈变量信息。

  • .frame [栈帧号]:切换变量上下文
  • !for_each_local:循环遍历所有的变量
  • !for_each_frame:遍历所有栈帧

手工回溯栈

         由于一些原因,比如说溢出,异常,导致windbg对栈的判断是不准确的,所以此时不建议使用k命令来回溯栈,我们采用手工方式进行栈回溯。一般存在两种情况,第一种:EBP寄存器的数值是正确的,此时回溯栈相对容易,第二种:如果EBP的数值不可靠,我们使用!tab查看线程控制块和dds来分析栈。

EBP和ESP可靠

  • 第1步:确定当前函数名:ln eip

    1
    2
    0:000> ln eip
    (76f5d470) ntdll!LdrInitShimEngineDynamic+0x6af | (76f5ed00) ntdll!NtCurrentTeb
  • 第2歩:如果ESP和EBP没有异常的情况下,EBP就是就是当前函数的ChildEbp(子帧栈的基址寄存器),EBP+4就是当前函数的返回地址(在父函数内部)。,

1
2
3
4
0:000> r ebp //ChildEBP
ebp=0019fa30
0:000> dd ebp+4 l1 //函数返回地址
0019fa34 76f58c37
  • 第3步:得到一个函数信息:0060fa30 76f58c37 ntdll!LdrInitShimEngineDynamic+0x6af
  • 第4步:接下来利用第2步获得的返回地址,得到调用函数的函数名,ln 76f58c37

    1
    2
    ln 76f58c37
    (76f3a1a0) ntdll!RtlCaptureStackContext+0x1ea97 | (76f58f20) ntdll!LdrAppxHandleIntegrityFailure
  • 第5步:根据当前的EBP在内存里面的数值就是父函数的EBP,EBP+4是函数的返回地址,使用dd ebp来获取父函数的ChildPEB,使用dd xxxx+4获取父函数的返回地址(在外公函数里面)

    1
    2
    3
    4
    0:000> dd 0019fc90 l1 //这一步使用dd ebp是一样的,下一步却不行
    0019fc90 0019fcf0
    0:000> dd 0019fcf0+4 l1 //函数返回地址
    0019fcf4 76f137be
  • 第6步:利用返回地址得到外公函数符号

    1
    2
    0:000> ln 76f137be
    (76f13750) ntdll!LdrInitializeThunk+0x6e | (76f13ca0) ntdll!RtlCharToInteger
  • 第7步:重复4-6:直到堆栈数据为0,达到边界。

    1
    2
    3
    4
    0:000> dd 0019fd00 l1
    0019fd00 0019fd10
    0:000> dd 0019fd14 l1
    0019fd14 00000000

EBP和ESP不可靠

  • 第1步:使用!tab获取线程栈空间数据

    1
    2
    3
    4
    5
    6
    7
    0:000> !teb
    TEB at 0033a000
    ExceptionList: 0019fa20
    StackBase: 001a0000 //栈基址
    StackLimit: 0019d000 //栈顶
    SubSystemTib: 00000000
    FiberData: 00001e00
  • 第2步:使用dds命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    0:000> dds esp //查看栈顶附近内存
    0019fa04 f8f3a4be
    0019fa08 76eb69c4 ntdll!`string'
    0019fa0c 00337000
    0019fa10 00000010
    0019fa14 00f3a496
    0019fa18 0019fa04
    0019fa1c 76f001cf ntdll!LdrpPrepareModuleForExecution+0x61
    0019fa20 0019fc80
    0019fa24 76f26b20 ntdll!_except_handler4
    0019fa28 8e115e06
    0019fa2c 00000000
    0019fa30 0019fc90
    0019fa34 76f58c37 ntdll!LdrpInitializeProcess+0x1b42
    0019fa38 f8f3a21e
    0019fa3c 00000000
    0019fa40 00000000
    0019fa44 ffffffff
    0019fa48 005c005a
    0019fa4c 02571e7c
    0019fa50 0019fbb0
    0019fa54 00000000
    0019fa58 00000201
    0019fa5c 00000000
    0019fa60 0019fbac
    0019fa64 00000000
    0019fa68 02573040
    0019fa6c 76fc7ba0 ntdll!LdrpWorkQueue
    0019fa70 76fc7ba0 ntdll!LdrpWorkQueue
    0019fa74 00000000
    0019fa78 025777a0
    0019fa7c 00000008
    0019fa80 00000000
    0:000> dds ebp //查看栈低附近的内存
    0019fa30 0019fc90
    0019fa34 76f58c37 ntdll!LdrpInitializeProcess+0x1b42
    0019fa38 f8f3a21e
    0019fa3c 00000000
    0019fa40 00000000
    0019fa44 ffffffff
    0019fa48 005c005a
    0019fa4c 02571e7c
    0019fa50 0019fbb0
    0019fa54 00000000
    0019fa58 00000201
    0019fa5c 00000000
    0019fa60 0019fbac
    0019fa64 00000000
    0019fa68 02573040
    0019fa6c 76fc7ba0 ntdll!LdrpWorkQueue
    0019fa70 76fc7ba0 ntdll!LdrpWorkQueue
    0019fa74 00000000
    0019fa78 025777a0
    0019fa7c 00000008
    0019fa80 00000000
    0019fa84 00403000 base32+0x3000
    0019fa88 00001000
    0019fa8c 00000008
    0019fa90 00000000
    0019fa94 00403af4 base32+0x3af4
    0019fa98 00000002
    0019fa9c 00000000
    0019faa0 00000000
    0019faa4 00000000
    0019faa8 00000000
    0019faac 00000000

第五部分 分析内存

显示内存

  • d{a|b|c|d|D} [Options] [Range]

         大括号里面代表的是显示类型。

  • da:显示ASCII码,du:显示Unicode

    1
    2
    0:000> da
    0019fc84 " k.v..........."
  • db:显示字节和ASCII //最常用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    0:000> db
    0019fc94 da 38 f1 76 7e a2 f3 f8-24 fd 19 00 00 00 eb 76 .8.v~...$......v
    0019fca4 00 70 33 00 00 00 00 00-aa 24 f0 56 00 b0 fc 76 .p3......$.V...v
    0019fcb4 00 00 03 00 28 70 33 00-01 00 00 00 00 00 eb 76 ....(p3........v
    0019fcc4 00 00 00 00 24 fd 19 00-00 70 33 00 00 00 00 00 ....$....p3.....
    0019fcd4 00 a0 33 00 98 fc 19 00-00 00 00 00 ff ff ff ff ..3.............
    0019fce4 20 6b f2 76 8e a5 10 8e-00 00 00 00 00 fd 19 00 k.v............
    0019fcf4 be 37 f1 76 00 00 00 00-00 00 00 00 10 fd 19 00 .7.v............
    0019fd04 6c 37 f1 76 00 00 00 00-5e 1b 59 bb 00 00 00 00 l7.v....^.Y.....
  • dc:显示dword和ASCII编码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    0:000> dc
    0019fd14 00000000 0019fd24 76eb0000 00000000 ....$......v....
    0019fd24 0001003f 00000000 00000000 00000000 ?...............
    0019fd34 00000000 00000000 00000000 0000027f ................
    0019fd44 00000000 0000ffff 00000000 00000000 ................
    0019fd54 00000000 00000000 00000000 00000000 ................
    0019fd64 00000000 00000000 00000000 00000000 ................
    0019fd74 00000000 00000000 00000000 00000000 ................
    0019fd84 00000000 00000000 00000000 00000000 ................
  • dd:显示dword

    1
    2
    3
    4
    5
    6
    7
    8
    9
    0:000> dd
    0019fd94 00000000 00000000 00000000 00000000
    0019fda4 00000000 00000000 00000000 0000002b
    0019fdb4 00000053 0000002b 0000002b 00000000
    0019fdc4 00000000 00337000 00000000 00000000
    0019fdd4 00401df5 00000000 76f20d90 00000023
    0019fde4 00000202 0019fff0 0000002b 0000027f
    0019fdf4 00000000 00000000 00000000 00000000
    0019fe04 00000000 00001f80 0000ffff 00000000
  • dp:显示指针

    1
    2
    3
    4
    5
    6
    7
    8
    9
    0:000> dp
    0019fe14 00000000 00000000 00000000 00000000
    0019fe24 00000000 00000000 00000000 00000000
    0019fe34 00000000 00000000 00000000 00000000
    0019fe44 00000000 00000000 00000000 00000000
    0019fe54 00000000 00000000 00000000 00000000
    0019fe64 00000000 00000000 00000000 00000000
    0019fe74 00000000 00000000 00000000 00000000
    0019fe84 00000000 00000000 00000000 00000000
  • ds:显示String类型,dS:显示Unicode_String类型
             Range:表示需要显示内存的范围

  • dd startaddress endaddress(两个内存地址)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    0:000> dc 0019fd94 0019fe04
    0019fd94 00000000 00000000 00000000 00000000 ................
    0019fda4 00000000 00000000 00000000 0000002b ............+...
    0019fdb4 00000053 0000002b 0000002b 00000000 S...+...+.......
    0019fdc4 00000000 00337000 00000000 00000000 .....p3.........
    0019fdd4 00401df5 00000000 76f20d90 00000023 ..@........v#...
    0019fde4 00000202 0019fff0 0000002b 0000027f ........+.......
    0019fdf4 00000000 00000000 00000000 00000000 ................
    0019fe04 00000000 ....
  • dd startaddress L(内存对象个数16进制)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    0:000> dc 0019fd94 L1D
    0019fd94 00000000 00000000 00000000 00000000 ................
    0019fda4 00000000 00000000 00000000 0000002b ............+...
    0019fdb4 00000053 0000002b 0000002b 00000000 S...+...+.......
    0019fdc4 00000000 00337000 00000000 00000000 .....p3.........
    0019fdd4 00401df5 00000000 76f20d90 00000023 ..@........v#...
    0019fde4 00000202 0019fff0 0000002b 0000027f ........+.......
    0019fdf4 00000000 00000000 00000000 00000000 ................
    0019fe04 00000000
  • dd endaddress L-(内存对象个数16进制)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    0:000> dc 0019fe04 L-1D
    0019fd90 00000000 00000000 00000000 00000000 ................
    0019fda0 00000000 00000000 00000000 00000000 ................
    0019fdb0 0000002b 00000053 0000002b 0000002b +...S...+...+...
    0019fdc0 00000000 00000000 00337000 00000000 .........p3.....
    0019fdd0 00000000 00401df5 00000000 76f20d90 ......@........v
    0019fde0 00000023 00000202 0019fff0 0000002b #...........+...
    0019fdf0 0000027f 00000000 00000000 00000000 ................
    0019fe00 00000000

显示数据类型

         dt命令常用与显示数据类型,其第一种方法是显示一个数据结构:dt module!Typename,选项-b:显示所有子类型,-r0,不显示子类型,-r1:显示一层子类型

1
2
3
4
5
0:000> dt _UNICODE_STRING
ntdll!_UNICODE_STRING
+0x000 Length : Uint2B
+0x002 MaximumLength : Uint2B
+0x004 Buffer : Ptr32 Wchar

1
2
3
4
5
6
7
8
9
10
11
0:000> dt ntdll!*
ntdll!LIST_ENTRY64
ntdll!LIST_ENTRY64
ntdll!LIST_ENTRY32
ntdll!LIST_ENTRY32
ntdll!SE_WS_APPX_SIGNATURE_ORIGIN
ntdll!_PS_MITIGATION_OPTION
ntdll!_PS_MITIGATION_OPTIONS_MAP
ntdll!_PS_MITIGATION_OPTIONS_MAP
ntdll!_PS_MITIGATION_AUDIT_OPTIONS_MAP
..........
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0:000> dt -b _TEB
ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x000 ExceptionList : Ptr32
+0x004 StackBase : Ptr32
+0x008 StackLimit : Ptr32
+0x00c SubSystemTib : Ptr32
+0x010 FiberData : Ptr32
+0x010 Version : Uint4B
+0x014 ArbitraryUserPointer : Ptr32
+0x018 Self : Ptr32
+0x01c EnvironmentPointer : Ptr32
+0x020 ClientId : _CLIENT_ID
+0x000 UniqueProcess : Ptr32
+0x004 UniqueThread : Ptr32
+0x028 ActiveRpcHandle : Ptr32
+0x02c ThreadLocalStoragePointer : Ptr32

         第二种方法是指定特定内存地址上的数据结构,其他和第一种用法一致.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0:000> dt _PEB 7ffdd000
ntdll!_PEB
+0x000 InheritedAddressSpace : ??
+0x001 ReadImageFileExecOptions : ??
+0x002 BeingDebugged : ??
+0x003 BitField : ??
+0x003 ImageUsesLargePages : ??
+0x003 IsProtectedProcess : ??
+0x003 IsImageDynamicallyRelocated : ??
+0x003 SkipPatchingUser32Forwarders : ??
+0x003 IsPackagedProcess : ??
+0x003 IsAppContainer : ??
+0x003 IsProtectedProcessLight : ??
+0x003 IsLongPathAwareProcess : ??
+0x004 Mutant : ????

         第三种方法是显示类型的实例,包括变量和函数。

1
2
0:000> dt g_szGobal
Symbol g_szGobal not found.

搜索内存

         windbg使用s命令搜索内存。一共三个试用方式。

         第一种方法,搜索内存中指定的字符串。

  • s [-Flags(b|w|d|q|a|u)] [Range] [Pattern]
    ![](https://i.imgur.com/4VvAUdr.png)
    

         第二种方法:在指定的内存空间中搜索与指定对象相同类型的对象。

  • s [-v] Range ObjectAddress
    1
    2
    3
    4
    5
    0:011> s -v 0x12fc30 L1000 0x12fe4c //0x12fe4c是类的地址,
    *** ERROR: Symbol file could not be found. Defaulted to export symbols for IEXPLORE.EXE -
    *** ERROR: Symbol file could not be found. Defaulted to export symbols for odbc32.dll -
    *** ERROR: Module load completed but symbols could not be loaded for odbcint.dll
    *** ERROR: Symbol file could not be found. Defaulted to export symbols for

         

修改内存数据

         使用e命令来修改内存数据,可以修改字符型,也可以修改数据类型。

         具体用法如下:a:b表示以0结尾的ASCII,za表示不是以0结尾的ASCII,zu或者au保证在末尾加0,而a或者u不会。u,zu同理。

  • e{a|u|za|zu}address “String”
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    0:000> db
    76f5db9f eb 76 c7 44 24 68 00 00-00 01 66 89 44 24 70 85 .v.D$h....f.D$p.
    76f5dbaf f6 74 29 8b 15 30 03 fe-7f 8b c2 6a 20 83 e0 1f .t)..0.....j ...
    76f5dbbf 59 2b c8 d3 ce 33 f2 89-37 74 07 33 f6 e9 1c 01 Y+...3..7t.3....
    76f5dbcf 00 00 be 01 00 00 c0 e9-12 01 00 00 8d 54 24 10 .............T$.
    76f5dbdf 8d 4c 24 68 e8 ed 5d f7-ff 8b f0 85 f6 0f 88 e8 .L$h..].........
    76f5dbef 00 00 00 8d 44 24 18 ba-01 40 00 00 50 33 c9 e8 ....D$...@..P3..
    76f5dbff 59 ae f8 ff 8d 44 24 0c-50 6a 01 6a 00 8d 54 24 Y....D$.Pj.j..T$
    76f5dc0f 24 8d 4c 24 74 e8 a3 d9-f9 ff 80 7c 24 64 00 8b $.L$t......|$d..
    0:000> ea 76f5db9f "strui"
    0:000> db 76f5db9f
    76f5db9f 73 74 72 75 69 68 00 00-00 01 66 89 44 24 70 85 struih....f.D$p.
    76f5dbaf f6 74 29 8b 15 30 03 fe-7f 8b c2 6a 20 83 e0 1f .t)..0.....j ...
    76f5dbbf 59 2b c8 d3 ce 33 f2 89-37 74 07 33 f6 e9 1c 01 Y+...3..7t.3....
    76f5dbcf 00 00 be 01 00 00 c0 e9-12 01 00 00 8d 54 24 10 .............T$.
    76f5dbdf 8d 4c 24 68 e8 ed 5d f7-ff 8b f0 85 f6 0f 88 e8 .L$h..].........
    76f5dbef 00 00 00 8d 44 24 18 ba-01 40 00 00 50 33 c9 e8 ....D$...@..P3..
    76f5dbff 59 ae f8 ff 8d 44 24 0c-50 6a 01 6a 00 8d 54 24 Y....D$.Pj.j..T$
    76f5dc0f 24 8d 4c 24 74 e8 a3 d9-f9 ff 80 7c 24 64 00 8b $.L$t......|$d..

         也可以修改数值类型的内存

  • e{b|d|D|q|w} address “Value”
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    0:000> ew 76f5dc1f 41 41 41 41
    0:000> db 76f5dc1f
    76f5dc1f 41 00 41 00 41 00 41 00-a5 90 f9 ff 85 f6 79 39 A.A.A.A.......y9
    76f5dc2f a1 90 57 fc 76 a8 03 74-29 56 8d 44 24 6c 50 68 ..W.v..t)V.D$lPh
    76f5dc3f 44 f6 eb 76 6a 00 68 84-f6 eb 76 68 ee 0a 00 00 D..vj.h...vh....
    76f5dc4f 68 b0 68 eb 76 e8 f4 d1-ff ff 83 c4 1c a1 90 57 h.h.v..........W
    76f5dc5f fc 76 a8 10 74 75 cc eb-72 8b 44 24 0c 81 48 34 .v..tu..r.D$..H4
    76f5dc6f 00 01 00 00 8b 44 24 0c-8b 40 18 a3 b8 7b fc 76 .....D$..@...{.v
    76f5dc7f e8 71 5a f7 ff 8b f0 85-f6 79 2a a1 90 57 fc 76 .qZ......y*..W.v
    76f5dc8f a8 03 74 ce 56 68 6c f5-eb 76 6a 00 68 84 f6 eb ..t.Vhl..vj.h...

观察内存属性

         使用拓展命令!address来观察内存属性,如果指定内存地址,显示指定内存地址所在的块的信息,如果不指定,则显示所有的内存块的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
0:000> !address 76f5dc1f
PEB 00329000 in range 00328000 00336000
TEB 0032c000 in range 00328000 00336000
TEB 0032f000 in range 00328000 00336000
TEB 00332000 in range 00328000 00336000
TEB 00335000 in range 00328000 00336000
ProcessParametrs 025819d0 in range 02580000 02586000
Environment 02580b70 in range 02580000 02586000
76eb0000 : 76eb1000 - 00114000
Type 01000000 MEM_IMAGE
Protect 00000020 PAGE_EXECUTE_READ
State 00001000 MEM_COMMIT
Usage RegionUsageImage
FullPath ntdll.dll

         !pte命令显示指定地址的页表表项和页目录表项。

显示链表

         dt遍历链表(数据结构)和dl遍历链表(专门遍历链表)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0:000> dt ntdll!*List*
ntdll!LIST_ENTRY64
ntdll!LIST_ENTRY64
ntdll!LIST_ENTRY32
ntdll!LIST_ENTRY32
ntdll!_LIST_ENTRY
ntdll!_LIST_ENTRY
ntdll!_LIST_ENTRY
ntdll!_SINGLE_LIST_ENTRY
ntdll!_SINGLE_LIST_ENTRY
ntdll!_PP_LOOKASIDE_LIST
ntdll!_SLIST_HEADER
ntdll!_SINGLE_LIST_ENTRY
ntdll!_SLIST_HEADER
ntdll!_LOOKASIDE_LIST_EX
ntdll!_LOOKASIDE_LIST_EX
ntdll!_NPAGED_LOOKASIDE_LI

  • dl[b] startaddress counter size

         拓展命令!list也可以遍历链表,但是这个较为复杂不建议使用