地址和地址范围语法
可通过多种方式在调试器中指定地址。
地址通常是 虚拟地址,除非文档专门指明了另一种地址。 在用户模式下,调试器根据 当前进程的页面目录解释虚拟地址。 在内核模式下,调试器根据 进程上下文 指定的进程的页面目录解释虚拟地址。 还可以直接设置 用户模式地址上下文。 有关用户模式地址上下文的详细信息,请参阅 .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) 命令。
有关如何使用内存窗口查看和编辑内存的信息,请参阅 使用内存窗口。
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈