- 逆向工程
- 调试器
- 开发工具
- 应用安全
【免费下载链接】x64dbg
An open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.
内存断点(Memory Breakpoint)是逆向工程中监视数据读写与代码执行的关键手段,与普通断点(INT3)和硬件断点(DRx 寄存器)不同,它通过 Windows 的 GUARD_PAGE 页保护机制,可以在不改写指令、不消耗硬件断点寄存器的情况下,监视一整个内存区域的所有访问行为。本指南以 x64dbg 的SetMemoryBPX/membp/bpm命令为主线,完整讲解其语法、参数语义、默认值与底层实现原理,并顺带覆盖内存断点的启用、禁用、删除与范围设置等配套命令,帮助你直接在调试会话中高效使用这一能力。
命令速览:三个等价别名
SetMemoryBPX命令在 x64dbg 的命令系统中注册了三个完全等价的别名,输入任何一个效果相同:
| 全名 | 别名 1 | 别名 2 |
|---|---|---|
SetMemoryBPX | membp | bpm |
命令注册点位于 src/dbg/x64dbg.cpp:
dbgcmdnew("SetMemoryBPX,membp,bpm", cbDebugSetMemoryBpx, true); //SetMemoryBPX该命令的核心行为一句话概括:在指定地址所在的内存区域(memory region)上设置一个 GUARD_PAGE 内存断点,监视对该区域的内存访问。区域范围不是由用户手工指定,而是由 x64dbg 根据地址自动推导出的整个内存块。
参数详解:地址、恢复标志与断点类型
SetMemoryBPX的完整语法为:
SetMemoryBPX <arg1> [arg2] [arg3]arg1:要监视的内存区域内的地址(必填)
arg1可以是该内存区域内任意一个地址(包括区域中间地址),x64dbg 会自动定位其所属的整个内存区域并对其整体设置断点。地址支持 x64dbg 的完整表达式语法(寄存器、符号、算术表达式等),例如eax、401000、[rsp+8]等。源码中通过valfromstring统一解析:
duint addr; if(!valfromstring(argv[1], &addr)) // 支持表达式求值 return false;随后调用MemFindBaseAddr(addr, &size, true)反查该地址所属内存区域的内存基址与大小(见 src/dbg/commands/cmd-breakpoint-control.cpp)。
arg2:命中后是否恢复断点(可选)
arg2为1或0,表示断点命中后是否恢复(restore,即继续监视)该内存断点:
1:命中后恢复断点,断点保持有效,可反复触发;0:命中后不恢复(等价于一次性/单发断点 singleshoot),断点触发一次后自动失效。
参数省略时默认值为0(即默认是单发行为)。这一默认行为在源码中有明确体现:
bool restore = false; // 默认不恢复 bool singleshoot = false; if(!restore) singleshoot = true; // 默认即为单发(singleshoot)arg3:断点类型(可选)
arg3指定监视的内存访问类型,支持四个取值,默认值为a:
| 取值 | 含义 | 对应 TitanEngine 内部枚举 |
|---|---|---|
a | 读 + 写 + 执行(默认) | UE_MEMORY |
r | 读 | UE_MEMORY_READ |
w | 写 | UE_MEMORY_WRITE |
x | 执行 | UE_MEMORY_EXECUTE |
源码中的类型映射逻辑位于cbDebugSetMemoryBpx(见 src/dbg/commands/cmd-breakpoint-control.cpp),无效类型会提示 "Invalid type (argument ignored)" 并被忽略。
参数省略的智能推断规则
这是本命令最灵活也最需要注意的一点:当arg2的值不是1或0时,它会被自动当作arg3(断点类型)处理。官方文档对此的表述是:"bpm eax,r"与"bpm eax,0,r"完全等价。
源码中的解析逻辑印证了这一规则(见 cmd-breakpoint-control.cpp):
if(argc > 2) { if(*argv[2] == '1') restore = true; else if(*argv[2] == '0') restore = false; else strcpy_s(arg3, argv[2]); // 非 1/0 则视为类型参数 }因此三种参数形态都是合法的:bpm eax、bpm eax,r、bpm eax,1,w。
实战示例
以下示例覆盖最常见的用法场景:
// 监视 eax 寄存器指向的整个内存区域的读写执行 bpm eax // 只监视该区域的读访问(省略 restore,等价于 bpm 401000,0,r) bpm 401000,r // 监视写访问,且命中后恢复(可反复触发) bpm 401000,1,w // 监视执行,命中一次后自动失效(单发) bpm 401000,0,x // 使用符号地址 bpm kernel32.VirtualAlloc,x // 使用表达式 bpm [rsp+8],w命令成功执行后,日志窗口会输出类似Memory breakpoint at 0000000140001000[00001000] set!的提示(%p[%p]分别打印区域基址与大小),并自动刷新 GUI 视图。若目标区域已经存在内存断点,命令会提示 "Memory breakpoint already set!";若断点存在但处于禁用状态,则会自动将其重新启用(详见下文"重复设置保护")。
底层实现原理:从命令到 GUARD_PAGE
要理解这条命令,需要看它背后的完整调用链。
第一步:命令分发
命令SetMemoryBPX/membp/bpm统一由回调函数cbDebugSetMemoryBpx处理(注册见 src/dbg/x64dbg.cpp)。
第二步:解析与建点
解析完地址、恢复标志与类型后,x64dbg 依次完成三件事(见 cmd-breakpoint-control.cpp):
MemFindBaseAddr(addr, &size, true)—— 反查地址所属内存区域,得到base与size,从而把断点作用域扩展为整个内存块;BpNew(base, true, singleshoot, 0, BPMEMORY, type, 0, size)—— 在 x64dbg 内部断点数据库中登记一个类型为BPMEMORY的断点;SetMemoryBPXEx(base, size, type, restore, cbMemoryBreakpoint)—— 调用 TitanEngine 底层 API,真正通过VirtualProtect等手段为目标内存页设置PAGE_GUARD保护标志(GUARD_PAGE),并注册命中回调。
第三步:命中回调
当被监视区域发生对应类型的访问时,CPU 会抛出 guard page 异常,调试器捕获后通过回调cbMemoryBreakpoint进入断点处理流程(见 src/dbg/debugger.cpp):
void cbMemoryBreakpoint(const void* ExceptionAddress) { lastExceptionInfo = GetDebugData()->u.Exception; cbGenericBreakpoint(BPMEMORY, ExceptionAddress); }cbGenericBreakpoint会统一处理断点条件判断、命中计数、日志输出以及 singleshoot 断点的自动清除等逻辑。这也意味着:为内存断点设置的命令、条件、日志等联动行为,走的是与普通断点同一套通用处理框架。
restore 与 singleshoot 的关系
源码中restore与singleshoot是互斥的:restore=1时断点命中后继续保留监视;restore=0时断点标记为单发,命中后自动失效。这一状态会同时写入内部断点记录和 TitanEngine 的UE_SINGLESHOOT标志位中(见 src/dbg/breakpoint.cpp)。
内存断点的配套管理命令
内存断点的完整生命周期管理还需要以下配套命令(均可在 docs/commands/breakpoint-control 索引中找到):
删除:DeleteMemoryBPX/membpc/bpmc
按断点名称或(基)地址删除指定内存断点;省略参数时删除全部内存断点(见 DeleteMemoryBPX 文档)。源码实现中,删除时若断点未记录 size,会先通过MemFindBaseAddr反查区域大小,再依次调用BpDelete与RemoveMemoryBPX完成登记数据与页保护的双重清理(见 cmd-breakpoint-control.cpp)。
// 按地址删除 membpc 401000 // 删除全部内存断点 membpc启用:EnableMemoryBreakpoint/membpe/bpme
启用之前被禁用的内存断点;省略参数时启用全部。内部先调用SetMemoryBPXEx重新挂上页保护,再通过BpEnable更新状态(见 cmd-breakpoint-control.cpp)。
membpe 401000 // 启用指定断点 membpe // 启用全部内存断点禁用:DisableMemoryBreakpoint/membpd/bpmd
禁用(挂起)内存断点,页保护被移除但断点记录保留;省略参数时禁用全部。内部调用RemoveMemoryBPX移除保护、BpEnable(false)标记禁用(见 cmd-breakpoint-control.cpp)。
bpmd 401000查看:bplist
所有内存断点可通过 bplist 命令统一列出,方便核对地址、类型与启用状态。
按范围设置:SetMemoryRangeBPX/memrangebp/bpmrange
SetMemoryBPX自动推导整个内存区域,若希望精确控制监视范围,可使用其姊妹命令SetMemoryRangeBPX(详见 SetMemoryRangeBPX 文档),语法为:
SetMemoryRangeBPX <start> <size> [type]| 参数 | 说明 |
|---|---|
start | 内存范围起始地址 |
size | 内存范围大小 |
type | 同SetMemoryBPX的arg3(a/r/w/x,默认a);追加ss后缀表示单发断点 |
该命令额外支持ss后缀实现单发语义,例如bpmrange 401000 1000 wss表示"监视0x401000起0x1000字节的写访问,命中一次后自动失效"。若省略ss,也可事后通过 SetMemoryBreakpointSingleshoot 命令将断点切换为单发。两条命令的差异对照如下:
| 维度 | SetMemoryBPX | SetMemoryRangeBPX |
|---|---|---|
| 范围来源 | 自动取地址所在整个内存区域 | 手工指定 start + size |
| 单发开关 | 通过arg2=0(默认) | 通过 type 追加ss后缀 |
| 命中后恢复 | 通过arg2=1 | 不追加ss即可 |
源码实现上,两条命令共用同一套建点与页保护流程:cbDebugSetMemoryRangeBpx解析 start/size/type 后同样调用BpNew与SetMemoryBPXEx(见 cmd-breakpoint-control.cpp)。
注意事项与常见问题
- 断点作用域是"整个内存区域":
SetMemoryBPX不区分页内偏移,传入区域中任意地址都会监视整个内存块。若只想监视一小段字节,请改用SetMemoryRangeBPX。 - 默认是单发行为:省略
arg2时断点命中一次即失效(singleshoot=true)。需要反复触发的场景务必显式传1,例如bpm 401000,1,w。 - 参数位置易混淆:
bpm addr,1,w与bpm addr,w都合法,但bpm addr,w,1中多余的1会被忽略(类型参数只取首字符)。牢记"非 1/0 的第二个参数会被当作类型"这一规则即可。 - 不设置结果变量:与
SetBPX等命令类似,SetMemoryBPX、SetMemoryRangeBPX、DeleteMemoryBPX、EnableMemoryBreakpoint、DisableMemoryBreakpoint均不写任何脚本结果变量,脚本中请通过bplist或断点查询 API 验证结果。 - 与硬件断点的取舍:硬件断点仅 4 个且依赖寄存器,普通断点会改写指令字节;内存断点以页保护实现,不消耗硬件资源,适合监视大块数据区,但需要注意其异常处理路径带来的开销,在性能敏感的大循环场景应谨慎使用。
- 联动条件与日志:内存断点同样支持条件、日志、命令等扩展配置,相关命令参见 docs/commands/conditional-breakpoint-control 目录下的
SetMemoryBreakpointCondition、SetMemoryBreakpointLog、SetMemoryBreakpointCommand等文档。
仓库中 src/tests/membp 目录保存了内存断点相关的测试工程与用例,可作为理解该功能预期行为的补充参考资料。
- 逆向工程
- 调试器
- 开发工具
- 应用安全
【免费下载链接】x64dbg
An open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.
相关推荐
x64dbg 内存范围断点 SetMemoryRangeBPX(bpmrange)完全指南:GUARD_PAGE 精确范围监控与实战
x64dbg 内存范围断点 SetMemoryRangeBPX(bpmrange)完全指南:GUARD_PAGE 精确范围监控与实战 导读 SetMemoryR
逆向工程调试器开发工具应用安全x64dbg 内存断点命令条件(SetMemoryBreakpointCommandCondition)完全指南
x64dbg 内存断点命令条件(SetMemoryBreakpointCommandCondition)完全指南 本文基于 x64dbg 官方命令参考文档,深入
逆向工程调试器开发工具应用安全x64dbg 内存断点命中计数查询命令 GetMemoryBreakpointHitCount 完整指南
x64dbg 内存断点命中计数查询命令 GetMemoryBreakpointHitCount 完整指南 导读 GetMemoryBreakpointHitCo
逆向工程调试器开发工具应用安全
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考