值
很多 命令 接受 表达式 和值作为参数。以下是所有支持的值格式列表。您可以在命令栏中输入这些格式来体验它们,或者使用计算器(Help -> Calculator 菜单)。
数字
默认情况下,所有数字都被解释为十六进制! 如果您想确保是十六进制,可以使用 x 或 0x 作为前缀。十进制数字可以在数字前加一个点来使用:.123=7B。
变量
变量可选地以 $ 开头,并且只能存储一个 DWORD(在 x64 上为 QWORD)。这意味着 myvar 和 $myvar 是等价的。更多信息请参阅变量部分。
寄存器
除了浮点寄存器(如:RAX、EAX、AL)之外,所有大小的寄存器都可以用作变量。
像 XMM0、YMM0、ZMM0、K0 或 ST(0) 这样的浮点寄存器不能用作变量,但可以通过字符串格式化中的浮点类型来记录。movdqu、vmovdqu、kmovd 命令也可用于访问浮点寄存器。
备注
大多数寄存器的变量名与它们的名称相同,但以下寄存器除外:
x87 控制字标志:这个寄存器的标志命名如下:
_x87CW_UM除了架构中的寄存器之外,x64dbg 还提供以下寄存器:
CAX、CBX、CCX、CDX、CSP、CBP、CSI、CDI、CIP。这些寄存器在 32 位平台上映射到 32 位寄存器,在 64 位平台上映射到 64 位寄存器。例如,CIP在 32 位平台上是EIP,在 64 位平台上是RIP。此功能旨在支持架构无关的代码。
标志
调试标志(解释为整数)可用作输入。标志以 _ 开头,后跟标志名称。有效的标志有:_cf、_pf、_af、_zf、_sf、_tf、_if、_df、_of、_rf、_vm、_ac、_vif、_vip 和 _id。
内存位置
您可以使用以下表达式之一来读取/写入内存位置:
[addr]从addr读取 DWORD/QWORD。n:[addr]从addr读取 n 个字节。seg:[addr]从addr处的段读取 DWORD/QWORD。byte:[addr]从addr读取一个 BYTE。word:[addr]从addr读取一个 WORD。dword:[addr]从addr读取一个 DWORD。qword:[addr]从addr读取一个 QWORD(仅限 x64)。n是要读取的字节数,在 x32 上不能大于 4,在 x64 上不能大于 8,否则会出错。seg可以是gs、es、cs、fs、ds、ss。只有fs和gs有实际效果。
解引用无效地址会导致错误,这对于条件断点或脚本编写来说可能会有问题。您可以使用 ReadByte(addr) 系列表达式函数来在出错时返回 0 而不是报错。
标签/符号
用户定义的标签和符号是有效的表达式(它们解析为所述标签/符号的地址)。
模块数据
DLL 导出
输入 GetProcAddress,它将自动解析为函数的实际地址。要明确指定从哪个模块加载 API,请使用:module.dll:api 或 module:api。类似地,您可以通过 module:ordinal 来解析序号。另一个宏允许您获取模块的加载基址。当 module 为空字符串时(例如 :myexport),将使用 CPU 中当前选中的模块。使用 . 代替 : 是等价的。
ntdll.dll:ZwContinue
ntdll:memcmp
ntdll.memcmp // 与上面相同
ntdll:1D // 序号 0x1D
:myexport // 当前模块中的导出 'myexport'
转发的导出会被解析到其最终地址。要防止这种行为,您可以使用 ? 代替 :。
kernel32:EnterCriticalSection // 解析为 ntdll:RtlEnterCriticalSection
kernel32?EnterCriticalSection // 解析为 kernel32 中的导出
已加载模块基址
如果您想访问已加载模块的基址,可以写:module、module:0、module:base、module:imagebase 或 module:header。
RVA/文件偏移
如果您想访问模块的 RVA,可以写 module + rva 或 module:$rva。如果您想将文件偏移转换为 VA,可以使用 module:#offset。当 module 为空字符串时(例如 :$123),将使用 CPU 中当前选中的模块。
// 文件偏移 0x400
ntdll.dll:#400
:#400
// RVA 0x1000
ntdll.dll:$1000 // RVA 0x1000
:$1000
模块入口点
要访问模块入口点,可以写 module:entry、module:oep 或 module:ep。请注意,当存在名为 entry、oep 或 ep 的导出时,将返回这些导出的地址。