x64dbg 中 vmovdqu/vmovups/vmovupd 命令详解:YMM/ZMM 寄存器与内存的数据搬运指南
【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg
本指南围绕 x64dbg 调试器的通用指令类命令vmovdqu/vmovups/vmovupd展开,讲解如何在调试会话中直接读写 YMM(AVX,32 字节)与 ZMM(AVX-512,64 字节)寄存器、如何在寄存器与内存地址之间搬运 256/512 位数据,并说明其与 XMM 级命令movdqu的差异。读完本文,你将掌握该命令的全部语法形态、参数取值规则、底层实现机制(含 AVX/AVX-512 上下文读写调用链)以及实测用例中的典型用法。
命令概述:一条命令,三种助记符
vmovdqu、vmovups、vmovupd在 x64dbg 的命令系统中是同一命令的三个别名,全部注册到同一个命令处理函数cbInstrVmovdqu。命令注册位置在 src/dbg/x64dbg.cpp:
dbgcmdnew("movdqu,movups,movupd", cbInstrMovdqu, true); //move from and to XMM register dbgcmdnew("vmovups,vmovupd,vmovdqu", cbInstrVmovdqu, true); //move from and to YMM/ZMM register对应地,movdqu/movups/movupd三个别名则统一由cbInstrMovdqu处理,负责 XMM(16 字节)寄存器。也就是说:前缀v决定命令操作的位宽层级,而后缀dqu/ups/upd只是对齐语法的三种历史写法,在本命令中行为完全一致,均可直接混用。
该命令的本质是"数据搬运":把源操作数(arg2)的值赋给目标操作数(arg1),功能上等价于汇编指令vmovdqu在调试器内部的执行模型。源与目标操作数可以是 YMM/ZMM 寄存器,也可以是内存地址;当操作数为内存时,仅支持[addr]这种方括号语法,addr是一个内存地址表达式。
| 命令别名 | 寄存器层级 | 操作数宽度 |
|---|---|---|
movdqu/movups/movupd | XMM | 16 字节 |
vmovdqu/vmovups/vmovupd | YMM | 32 字节 |
vmovdqu/vmovups/vmovupd | ZMM | 64 字节 |
注意:与其他多数命令不同,本命令的操作数大小是"按寄存器层级固定"的——YMM 固定 32 字节、ZMM 固定 64 字节,而不是随地址表达式推断。要访问 XMM 寄存器,请使用 movdqu 命令;要访问 ZMM 寄存器,则要求宿主机 CPU 与 x64dbg 版本均支持 AVX-512。
参数与返回值
arguments
arg1:目标操作数(destination operand)。可以是ymm0~ymm31、zmm0~zmm31这类寄存器名,也可以是[addr]形式的内存地址表达式。arg2:源操作数(source operand)。同样可以是 YMM/ZMM 寄存器或[addr]形式的内存地址表达式。
命令执行后,目标操作数会被设置为源操作数的值;若目标为内存地址,则内存中对应宽度(32 或 64 字节)的数据被改写。
result
本命令不会设置任何结果变量(如$result等),因此不能直接在后续脚本中读取其返回值来判断成败;判断是否成功需依赖命令返回的 true/false(例如通过脚本条件或插件 API 检查)。
支持的六种操作数组合
从源码实现 src/dbg/commands/cmd-general-purpose.cpp 可以看到,命令按"内存→寄存器、寄存器→内存、寄存器→寄存器"三种方向 × "YMM/ZMM 两种层级"共分六条分支路径处理:
1. 内存 → YMM 寄存器(读内存到寄存器)
vmovdqu ymm0, [addr]从地址addr读取 32 字节写入ymm0。源码对应分支(cmd-general-purpose.cpp):
- 校验寄存器编号
registerindex >= ArchValue(8, 32)(x86 下最多 ymm7,x64 下最多 ymm31); - 通过
valfromstring解析地址表达式; - 用
MemRead(address, &newValue, sizeof(newValue))读取 32 字节; - 调用
GetAVXContext(hActiveThread, &context)取得当前活动线程的 AVX 上下文,写入后以SetAVXContext回写,最后GuiUpdateAllViews()刷新反汇编/内存等视图。
2. YMM 寄存器 → 内存(写寄存器到内存)
vmovdqu [addr], ymm0将ymm0的 32 字节写入地址addr。源码分支(cmd-general-purpose.cpp)先校验MemIsValidReadPtr(address)保证目标地址可访问,再通过MemWrite(address, &context.YmmRegisters[registerindex], sizeof(ZmmRegister_t))写入。
3. YMM 寄存器 → YMM 寄存器(寄存器间复制)
vmovdqu ymm0, ymm1将ymm1的 32 字节复制到ymm0。源码分支(cmd-general-purpose.cpp)通过一次GetAVXContext+ 数组赋值context.YmmRegisters[registerindex[1]] = context.YmmRegisters[registerindex[0]]+SetAVXContext完成。
4. 内存 → ZMM 寄存器(读内存到寄存器,需 AVX-512)
vmovdqu zmm0, [addr]从地址addr读取 64 字节写入zmm0。源码分支(cmd-general-purpose.cpp)与 YMM 版本对称,区别在于使用ZmmRegister_t newValue(64 字节)与GetAVX512Context/SetAVX512Context读写 AVX-512 上下文。
5. ZMM 寄存器 → 内存(写寄存器到内存,需 AVX-512)
vmovdqu [addr], zmm0将zmm0的 64 字节写入地址addr。源码分支(cmd-general-purpose.cpp)。
6. ZMM 寄存器 → ZMM 寄存器(寄存器间复制,需 AVX-512)
vmovdqu zmm0, zmm1将zmm1的 64 字节复制到zmm0。源码分支(cmd-general-purpose.cpp)。
命令的完整用法提示(当语法不匹配时输出)为:
Usage: vmovdqu zmm0 (or ymm0), [address] / vmovdqu [address], zmm0 (or ymm0) / vmovdqu zmm0 (or ymm0), zmm1 (or ymm1)寄存器编号与架构相关的有效范围
寄存器编号的合法性随架构不同而变化,源码中统一使用ArchValue(8, 32)进行编译期选择(x86 取 8、x64 取 32):
- x86(32 位):仅支持
ymm0~ymm7、zmm0~zmm7(AVX/AVX-512 在该架构下最多 8 个向量寄存器); - x64(64 位):支持
ymm0~ymm31、zmm0~zmm31。
超出范围的寄存器名会被判定为InvalidSrc(源无效)或InvalidDest(目标无效),并输出对应错误信息:
Invalid src "%s" Invalid dest "%s"底层数据模型:XMM/YMM/ZMM 的嵌套结构
命令的位宽差异源于 x64dbg 的寄存器数据模型。在 src/dbg/TitanEngine/TitanEngine.h 中,XMM、YMM、ZMM 被定义为嵌套结构:
typedef struct DECLSPEC_ALIGN(16) _XmmRegister_t { ULONGLONG Low; LONGLONG High; } XmmRegister_t; // 16 字节 typedef struct { XmmRegister_t Low; // XMM/SSE part XmmRegister_t High; // AVX part } YmmRegister_t; // 32 字节 typedef struct { YmmRegister_t Low; // AVX part YmmRegister_t High; // AVX-512 part } ZmmRegister_t; // 64 字节即:YMM 的高 128 位是 XMM 的扩展(AVX 部分),ZMM 的高 256 位是 YMM 的扩展(AVX-512 部分)。这解释了为什么命令对 ZMM 的操作宽度是 64 字节、对 YMM 是 32 字节——它们正好对应上述结构体的大小。
上下文结构同样按架构区分:TITAN_ENGINE_CONTEXT_t在 x64 下包含YmmRegisters[16],x86 下为YmmRegisters[8];TITAN_ENGINE_CONTEXT_AVX512_t在 x64 下包含ZmmRegisters[32](外加 8 个Opmask掩码寄存器),x86 下为ZmmRegisters[8]。这些结构体是 TitanEngine 导出 APIGetAVXContext/SetAVXContext/GetAVX512Context/SetAVX512Context的载体,cbInstrVmovdqu正是通过这些 API 读写当前活动线程(hActiveThread)的扩展寄存器上下文。
内存操作的解析细节与失败处理
当操作数为内存时,命令要求严格的[addr]方括号语法,这与 x64dbg 中其他"宽操作数"命令的约定一致。解析流程为:
- 通过首尾字符检查确认方括号包裹;
- 剥离方括号后用
valfromstring解析地址表达式(支持 x64dbg 表达式语法,可包含寄存器、算术、函数调用等); - 读方向用
MemRead读取,若目标地址不可读则输出Failed to read (all) memory...并返回 false; - 写方向先用
MemIsValidReadPtr校验地址有效性,失败则进入InvalidDest;随后用MemWrite写入,失败则输出Failed to write to %p; - 每次成功操作后调用
GuiUpdateAllViews(),让反汇编、内存转储等 GUI 视图立即刷新,保证调试器界面所见即所得。
相关命令与测试佐证
与 movdqu(XMM 级)的分工
vmovdqu系列与 movdqu 系列的分工非常明确:movdqu只处理 16 字节的 XMM 寄存器(xmm0~xmm15,x64 下 x86 架构取 8),vmovdqu处理 32/64 字节的 YMM/ZMM。两条命令的实现位于同一文件 src/dbg/commands/cmd-general-purpose.cpp,函数声明集中在 cmd-general-purpose.h,便于对照阅读。
测试用例中的典型用法
仓库测试 src/tests/issue3803/plugin.cpp 展示了vmovdqu的真实使用场景——插件通过新桥接 API 写入_ZMM0后,用命令把寄存器值搬运到内存进行校验:
if(!_plugin_testassert(DbgValSetBuffer("_ZMM0", zmm.data(), zmm.size()), "DbgValSetBuffer failed for _ZMM0")) ... if(!_plugin_testassert(DbgCmdExecDirect("vmovdqu [$result], zmm0"), "vmovdqu [$result], zmm0 failed")) ... if(!_plugin_testassert(memcmp(written.data(), zmm.data(), sizeof(XMMREGISTER)) == 0, "ZMM0 low lane mismatch"))测试说明(src/tests/issue3803/README.md)特别强调:ZMM 校验通过vmovdqu检查低 128 位(low lane),这样即使宿主机没有 AVX-512 硬件、只保留 AVX 子集,测试依然可靠。这从侧面印证了两个关键事实:
vmovdqu [addr], zmm0写内存时实际写入的是 ZMM 寄存器的完整 64 字节(低 128 位即 XMM 部分必然包含其中);- 在不支持 AVX-512 的机器上,ZMM 上下文无法完整读写,因此该命令的 ZMM 形态(以及
movdqu的 XMM 形态)需要以兼容方式使用。
使用限制与注意事项
- AVX-512 硬件要求:访问 ZMM 寄存器要求宿主机 CPU 与 x64dbg 构建版本均支持 AVX-512;否则
GetAVX512Context会失败并输出Failed to read register context...。 - 操作数宽度固定:
vmovdqu的 YMM 形态总是 32 字节、ZMM 形态总是 64 字节,不会根据地址表达式自动推断宽度;需要更小粒度的搬运请使用movdqu(16 字节)。 - 仅支持
[addr]语法:内存操作数必须写成方括号形式,且addr需能被地址表达式解析器接受(如[401000]、[var:addr]、[rsp+0x10]等)。 - 不设置结果变量:无法通过
$result判断命令成败,需依赖命令返回值或后续内存/寄存器检查。 - 寄存器范围受限:x86 下仅
ymm0~ymm7/zmm0~zmm7,x64 下最多ymm31/zmm31,超出即报Invalid src/dest。
【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考