地址和地址范围语法

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

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

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

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

显示内存地址示例

若要查看使用 poi 的示例,请确定线程环境块的 CurrentLocale 的偏移量 (TEB) 。 使用 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

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

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

地址范围

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

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

0x00001000  0x00001007

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

0x00001000  L8

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

0x00001000  0x00001007
0x00001000  L2

L 大小范围说明符

可通过另外两种方法 (L大小 范围说明符) 指定值:

  • 我?带有 问号) 的大小 (与 L大小相同,但 L?大小 将删除调试器的自动范围限制。 通常,范围限制为 256 MB,因为较大的范围是版式错误。 如果要指定大于 256 MB 的范围,则必须使用 L?大小 语法。

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

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

搜索内存范围示例

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

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

然后,我们将使用 s (Search Memory) 命令从 00007ffc'0f180771 开始搜索 1000000。 我们使用 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- length 参数在内存范围内向后搜索。

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

地址模式和段支持

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

前缀 名称 地址类型
% 公寓 32 位地址 (16 位选择器,这些选择器指向 32 位段) 和 64 位系统上的 64 位地址。
& virtual 86 实模式地址。 仅基于 x86。
# plain 实模式地址。 仅基于 x86。

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

如果通过不是当前默认模式的寻址模式访问内存,则可以使用地址模式前缀来替代当前地址模式。

地址参数

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

语法 含义

offset

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

&[[ segment:]] offset

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

%segment:[[ offset]]

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

%[[ offset]]

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

name[[ +| ]] offset

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

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

另请参阅

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

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

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

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