x64dbg Fill 命令完全指南:使用 memset 填充被调试进程内存

发布时间:2026/9/19 10:35:10
x64dbg Fill 命令完全指南:使用 memset 填充被调试进程内存 x64dbg Fill 命令完全指南使用 memset 填充被调试进程内存【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg本指南讲解 x64dbg 调试器中Fill别名memset命令的完整用法如何把被调试进程指定地址的内存填充为指定字节以及省略长度参数时“填充整页剩余空间”的底层实现原理。通过阅读本文你将掌握Fill的参数规则、默认行为、返回值约定并结合 cmd-memory-operations.cpp 与 memory.cpp 的源码理解其分页写入、补丁追踪等内部机制能够在逆向分析与漏洞利用练习中安全、精确地批量改写目标进程内存。Fill是 x64dbg 命令体系中内存操作Memory Operations一类的成员与alloc、free、memcpy、getpagerights、setpagerights、savedata、minidump等命令共同构成对调试目标内存的读写控制能力见 docs/commands/memory-operations/index.rst。它对应的文档为 docs/commands/memory-operations/Fill.md本文将以该文档为主线展开。命令概览将内存设置为指定字节Fill的功能定义非常简洁——将被调试进程debuggee从指定地址开始的连续内存设置为一个指定的字节值。这等价于 C 标准库中的memset因此命令同时注册了memset作为别名。从命令注册源码可见其别名机制x64dbg.cpp 中通过dbgcmdnew(Fill,memset, cbDebugMemset, true)将Fill与memset两个命令名同时绑定到回调函数cbDebugMemset两者完全等价可按习惯任选其一Fillmemset该命令由 cmd-memory-operations.h 声明、cmd-memory-operations.cpp 实现属于命令调试侧debugger 侧回调与 GUI 命令入口解耦。参数详解命令语法为Fill arg1 arg2 [arg3]参数含义是否必填说明arg1起始内存地址必填要开始写入字节的内存地址arg2填充字节值必填用于填充内存的字节值0x00 ~ 0xFFarg3填充大小可选要设置的字节数省略时填充到当前内存页剩余部分arg1起始地址指定开始填充的绝对内存地址。该参数通过valfromstring解析cmd-memory-operations.cpp因此支持 x64dbg 表达式语法直接十六进制地址如0x401000、401000寄存器值如eax、rip带表达式的地址如rsp8、[401000]arg2填充值要写入的字节。虽然命令行可以传入任意数值但底层实现只取最低一个字节BYTE fi value 0xFF;cmd-memory-operations.cpp因此实际生效范围恒为0x00~0xFF。例如传入0x1234实际写入的是0x34。常用场景0x00清零0x90NOP 填充常用于绕过校验或填充对齐0xCCINT3 断点字节用于在未初始化区域触发异常类似 MSVC 调试堆的填充模式0xFF全置位arg3填充大小可选填充的字节数。省略时行为由 cmd-memory-operations.cpp 决定调用MemFindBaseAddr(addr, size, true)找到addr所在内存块的基址base与整块大小size计算diff addr - base起始地址相对基址的偏移保持地址不变addr base diff将待填充大小修正为size - diff。也就是说默认情况下Fill会从arg1所在页/内存块的当前位置一直填充到该块末尾。文档原文the rest of the page当前页的剩余部分描述的正是这一行为一旦省略arg3你就不需要关心具体大小x64dbg 会自动把从该地址到所在分配块结尾的所有内存填满。如果MemFindBaseAddr返回 0地址无效例如进程未运行或地址不在任何已分配区域内命令会输出Invalid address specified并返回失败。参数校验源码中首先通过IsArgumentsLessThan(argc, 3)强制要求至少 3 个 token命令名 两个必填参数否则直接返回falsecmd-memory-operations.cpp。随后对arg1、arg2执行valfromstring解析任何一个解析失败都会中止命令。执行过程与结果命令执行成功后会向日志输出一行摘要格式如下cmd-memory-operations.cppMemory addr (size: SIZE) set to VALUE其中SIZE以 8 位十六进制显示VALUE以 2 位十六进制显示例如Memory 0137C000 (size: 00001000) set to 90若写入失败则输出Memset failed。结果变量根据原文档的说明Fill命令不会设置任何结果变量This command does not set any result variables。与之形成对比的是同类的alloc命令会设置$res与$lastalloc、memcpy会设置$result见 cmd-memory-operations.cpp脚本中若需基于Fill的结果做判断只能通过后续读取内存如dump命令或find自行验证而不能依赖结果变量。底层实现分页写入与补丁追踪Fill的内部核心是静态辅助函数FillDebugMemorycmd-memory-operations.cpp其设计值得深入了解static bool FillDebugMemory(duint addr, duint size, uint8_t value) { if(size 0) return true; constexpr duint patchTrackThreshold 0x100; const bool trackPatches size patchTrackThreshold; std::vectoruint8_t buffer(std::minduint(size, PAGE_SIZE), value); for(duint offset 0; offset size; offset buffer.size()) { const auto chunkSize std::minduint(duint(buffer.size()), size - offset); const bool ok trackPatches ? MemPatch(addr offset, buffer.data(), chunkSize) : MemWrite(addr offset, buffer.data(), chunkSize); if(!ok) return false; } return true; }按页分块写入写入不是一次性的而是构造一个最多PAGE_SIZEx64dbg 中为 4096 字节即 Windows 标准内存页大小大小的缓冲区循环分块写入每次写入不超过一页。这样做的原因在于底层MemWrite的实现在 memory.cpp它按页边界拆解写入第一块只写到当前页末尾sizeLeftInFirstPage PAGE_SIZE - (BaseAddress (PAGE_SIZE - 1))此后每块正好一页并通过MemoryWriteSafePage保证单次写入不跨页边界。分页处理既能避免跨页写入带来的部分成功/部分失败问题也便于对每次写入进行错误检查——任一块失败即整体返回失败。大填充 vs 小填充MemWrite 与 MemPatch 的分流FillDebugMemory依据size 0x100256 字节这一阈值选择不同的写入路径size 0x100≤ 256 字节走MemPatchmemory.cpp。MemPatch会先MemRead读取该区域的旧数据再MemWrite写入新数据随后调用PatchSet逐字节记录旧值 - 新值的变更。这意味着小范围填充会进入补丁patch追踪系统变更可被 x64dbg 的补丁管理功能捕获、保存到数据库或导出适合对指令字节做精确修改如改写几个字节的跳转、NOP 填充等。size 0x100大范围直接走MemWrite不记录补丁历史避免大块数据写入产生大量补丁记录导致性能与内存开销适合整页清零、大缓冲区初始化等批量操作。这一分流体现了 x64dbg 对精确补丁与批量覆写两类使用场景的刻意区分。地址规范性与写入安全无论走哪条路径底层都受 memory.cpp 的保护机制约束MemWrite首先调用MemIsCanonicalAddress检查地址是否为规范地址memory.cpp64 位下要求最高 16 位全为 0 或全为 1即 48 位线性地址范围非规范地址直接拒绝写入MemPatch在写之前必须能成功MemRead旧数据否则直接失败——读不到的页一定写不了写入失败时设置ERROR_PARTIAL_COPY作为SetLastError结果memory.cpp。典型使用场景与示例1. 精确改写指定大小的区域配合补丁追踪Fill 0x401000 0x90 16将0x401000起始的 16 个字节全部填为0x90NOP由于大小小于 256 字节会走MemPatch路径并被补丁系统记录。2. 清零一个缓冲区Fill 0x600000 0 0x1000将0x600000起始的 4096 字节清零。注意arg2传0或0x00均可。3. 填充整页剩余空间省略 arg3Fill 0x401000 0xCC省略arg3时x64dbg 自动把从0x401000到其所在内存块末尾的所有字节填为0xCCINT3。这在快速废掉一块未使用区域时非常高效。4. 使用别名 memsetmemset 0x401000 0x90 16效果与Fill完全相同。5. 结合寄存器与表达式Fill eip 0x90 4 Fill rsp8 0 0x20arg1支持 x64dbg 表达式可直接使用寄存器。注意事项运行状态Fill是内存写入操作需要在进程暂停被调试时执行进程运行中执行无法保证写入效果可写性目标页必须可写。MemPatch要求先能读到旧数据若目标处于只读或NoAccess保护状态写入会失败并提示Memset failed对不可写页可先用setpagerights调整页权限参见 setpagerights值截断arg2只取低 8 位任何超过0xFF的输入都会被截断无结果变量Fill不设置任何结果变量脚本中如需确认写入成功可配合dump/find或再次读取内存验证大范围填充不追踪补丁超过 256 字节的填充不会记录补丁若需要将批量改写纳入补丁管理请分多次小范围执行或使用 GUI 的内存编辑功能。相关资源官方命令文档docs/commands/memory-operations/Fill.md命令实现cmd-memory-operations.cpp命令声明cmd-memory-operations.h命令注册x64dbg.cpp底层内存读写MemWrite/MemPatch/MemRead位于 memory.cpp同类内存操作命令docs/commands/memory-operations/index.rst【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考