地址和地址范围语法

可通过多种方式在调试器中指定地址。

地址通常是虚拟地址,除非文档明确指出另一种地址。 在用户模式下,调试器根据当前进程的页面目录解释虚拟地址。 在内核模式下,调试器根据进程上下文指定的进程的页目录解释虚拟地址。 还可以直接设置用户模式地址上下文。 有关用户模式地址上下文的详细信息,请参阅 .context(设置用户模式地址上下文)

在 MASM 表达式中,可以使用 poi 运算符取消引用任何指针。 例如,如果地址 0x0000008e'ed57b108 处的指针指向地址位置 0x805287637256,则以下两个命令是等效的。

0:000> dd 805287637256
0:000> dd poi(000000bb`7ee23108)

显示内存地址示例

若要查看使用 poi 的示例,请确定线程环境块 (TEB) 的 CurrentLocale 偏移量。 使用 dx 命令显示 @$teb,这是一个 伪寄存器的示例,该寄存器包含常见地址,例如当前程序计数器位置。

0:000> dx @$teb
@$teb                 : 0x1483181000 [Type: _TEB *]

...

    [+0x108] CurrentLocale    : 0x409 [Type: unsigned long]

CurrentLocale 从 TEB 开始是 +0x108。 接下来确定该位置的内存地址。

0:000> ? @$teb + 0x108
Evaluate expression: 613867303176 = 0000008e`ed57b108

使用 poi 取消引用该地址,以查看它是否包含 0x409 的 CurrentLocale 值。

0:000> ? poi(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409

在 C++ 调试器表达式中,指针的行为类似于 C++ 中的指针。 但是,数字被解释为整数。 如果必须服从实际数字,可能需要先进行强制转换,如以下示例所示。

若要尝试此操作,请使用 .expr 将表达式计算器设置为 C++ 。

0:000> .expr /s C++
Current expression evaluator: C++ - C++ source expressions

将表达式计算器设置为 C++ 后,可以使用 long 进行强制转换。

0:000> d *((long*)0x00000014`83181108 ) 
00000000`00000409  ???????? ???????? ???????? ????????

有关强制转换数值的详细信息,请参阅 C++ 数字和运算符

如果表达式计算器设置为 c++,则可以用 @@masm()包装 poi 指针,使 MASM 表达式计算器只计算表达式的这一部分。

0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions

0:000> ? @@masm(poi(00000078`267d7108))
Evaluate expression: 1033 = 00000000`00000409

有关两个表达式计算器的详细信息,请参阅计算表达式

还可以通过指定原始源文件名称和行号来指明应用程序中的地址。 有关如何指定此信息的详细信息,请参阅源行语法

地址范围

可以按一对地址或一个地址和对象计数指定地址范围。

若要按一对地址指定范围,请指定起始地址和结束地址。 例如,以下示例从地址 0x00001000 开始,范围为 8 个字节。

0x00001000  0x00001007

若要按地址和对象计数指定地址范围,请指定地址参数、字母 L(大写或小写)和值参数。 该地址指定起始地址。 该值指定要检查或显示的对象数。 对象的大小取决于命令。 例如,如果对象大小为 1 字节,则以下示例是从地址 0x00001000 开始的 8 个字节范围。

0x00001000  L8

但是,如果对象大小是双字(32 位或 4 个字节),则以下两个范围分别提供 8 字节范围。

0x00001000  0x00001007
0x00001000  L2

L 大小范围说明符

还有两种方法可以指定值(L大小范围说明符):

  • L?大小(带有问号)表示与 L大小相同,但 L 除外? 大小会删除调试器的自动范围限制。 通常,范围限制为 256 MB,因为更大的范围会出现排版错误。 如果要指定大于 256 MB 的范围,则必须使用 L? 大小 语法。

  • L- 大小(带连字符)指定长度大小范围,以给定地址结尾。 例如,80000000 L20 指定从 0x80000000 到 0x8000001F 的范围,800000000 L-20 指定从 0x7FFFFFE0 到 0x7FFFFFFF 的范围。

一些要求地址范围的命令接受单个地址作为参数。 在这种情况下,该命令使用一些默认对象计数来计算范围的大小。 通常,将地址范围作为最终参数的命令允许使用此语法。 有关每个命令的确切语法和默认范围大小,请参阅每个命令的参考主题。

搜索内存范围示例

首先,我们将使用 MASM 表达式计算器确定 rip 指令指针寄存器的地址。

0:000> ? @rip 
Evaluate expression: 140720561719153 = 00007ffc`0f180771

然后,我们将使用 s (Search Memory) 命令从 00007ffc'0f180771 开始搜索 100000。 我们使用 L100000指定搜索范围。

0:000> s -a 00007ffc`0f180771 L100000 "ntdll"  
00007ffc`0f1d48fa  6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00  ntdll\ldrinit.c.
00007ffc`0f1d49c2  6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00  ntdll\ldrmap.c..
00007ffc`0f1d4ab2  6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63  ntdll\ldrredirec
00007ffc`0f1d4ad2  6e 74 64 6c 6c 5c 6c 64-72 73 6e 61 70 2e 63 00  ntdll\ldrsnap.c.
...

我们还可以使用两个内存地址来指定与此相同的范围。

0:000> s -a 0x00007ffc`0f180771 0x00007ffc`0f280771 "ntdll"  
00007ffc`0f1d48fa  6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00  ntdll\ldrinit.c.
00007ffc`0f1d49c2  6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00  ntdll\ldrmap.c..
00007ffc`0f1d4ab2  6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63  ntdll\ldrredirec
00007ffc`0f1d4ad2  6e 74 64 6c 6c 5c 6c 64-72 73 6e 61 70 2e 63 00  ntdll\ldrsnap.c.
...

最后,可以使用 L 长度参数在内存范围内向后搜索。

0:000> s -a 00007ffc`0f1d4ad2 L-100000 "ntdll"  
00007ffc`0f1d48fa  6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00  ntdll\ldrinit.c.
00007ffc`0f1d49c2  6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00  ntdll\ldrmap.c..
00007ffc`0f1d4ab2  6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63  ntdll\ldrredirec

取消汇编内存示例

此示例使用 u (unassemble) 命令和 L 参数取消汇编三个字节的代码。

0:000> u 00007ffc`0f1d48fa L3
ntdll!`string'+0xa:
00007ffc`0f1d48fa 6e              outs    dx,byte ptr [rsi]
00007ffc`0f1d48fb 7464            je      ntdll!`string'+0x21 (00007ffc`0f1d4961)
00007ffc`0f1d48fd 6c              ins     byte ptr [rdi],dx

或者指定三个字节范围的内存以取消汇编,如下所示。

0:000> u 00007ffc`0f1d48fa 00007ffc`0f1d48fd
ntdll!`string'+0xa:
00007ffc`0f1d48fa 6e              outs    dx,byte ptr [rsi]
00007ffc`0f1d48fb 7464            je      ntdll!`string'+0x21 (00007ffc`0f1d4961)
00007ffc`0f1d48fd 6c              ins     byte ptr [rdi],dx

地址模式和 Segment 支持

在基于 x86 的平台上,CDB 和 KD 支持以下寻址模式。 这些模式由前缀区分。

Prefix 名称 地址类型
% flat 32 位地址(也指向 32 位段的 16 位选择器)和 64 位系统上的 64 位地址。
& 虚拟 86 实际模式地址。 仅限基于 x86。
# plain 实际模式地址。 仅限基于 x86。

普通模式和虚拟 86 模式之间的区别是,普通 16 位地址使用段值作为选择器并查找段描述符。 但虚拟 86 地址不使用选择器,而是直接映射到较低的 1 MB。

如果通过非当前默认模式的寻址模式访问内存,则可以使用地址模式前缀覆盖当前地址模式。

地址参数

地址参数指定变量和函数的位置。 下表介绍了可在 CDB 和 KD 中使用的各种地址的语法和含义。

语法 含义

offset

虚拟内存空间中的绝对地址,其类型与当前执行模式相对应。 例如,如果当前执行模式为 16 位,则偏移量为 16 位。 如果执行模式为 32 位分段,则偏移量为 32 位分段。

&[[ segment:]] 偏移量

真实地址。 基于 x86 和基于 x64。

%segment:[[ offset]]

分段的 32 位或 64 位地址。 基于 x86 和基于 x64。

%[[ offset]]

虚拟内存空间中的绝对地址(32 位或 64 位)。 基于 x86 和基于 x64。

name[[ +| ]] offset

平坦 32 位或 64 位地址。 name 可以是任何符号。 offset 指定偏移量。 此偏移量可以是其前缀指示的任何地址模式。 没有前缀指定默认模式地址。 可以将偏移量指定为正值 (+) 或负值 (−)。

使用 dg (显示选择器)命令查看段描述符信息。

另请参阅

若要显示有关内存的信息,请使用 !address 命令。

若要搜索内存,请使用 s(搜索内存)命令。

若要显示内存的内容,请使用 d、da、db、dc、dd、dD、df、dp、dq、du、dw (显示内存) 命令。

有关如何使用内存窗口查看和编辑内存的信息,请参阅使用内存窗口