news 2026/9/19 5:09:03

x64dbg 断点控制命令全解析:软件/硬件/内存/DLL/异常五类断点的用法与源码实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
x64dbg 断点控制命令全解析:软件/硬件/内存/DLL/异常五类断点的用法与源码实现

x64dbg 断点控制命令全解析:软件/硬件/内存/DLL/异常五类断点的用法与源码实现

【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg

x64dbg 的命令行断点控制系统覆盖软件断点(INT3/UD2)、硬件断点(调试寄存器)、内存断点(Guard Page)、DLL 加载断点与异常断点五大门类,并提供bpgotobplistSetBPXOptions等辅助命令。本文以 breakpoint-control 文档目录 为骨架,逐条讲解 25 个命令的参数、默认值、别名与典型用法,并结合 cmd-breakpoint-control.cpp 与 breakpoint.h 的源码说明其底层原理,帮助你完全掌握 x64dbg 的脚本化断点操作能力。

断点控制命令总览与命令注册机制

x64dbg 的断点控制命令统一在调试引擎启动时注册,注册入口位于 x64dbg.cpp,每个命令通过dbgcmdnew("命令名,别名1,别名2", 回调函数, 是否可在运行时执行)注册,例如:

dbgcmdnew("SetBPX,bp,bpx", cbDebugSetBPX, true); //软件断点 dbgcmdnew("SetHardwareBreakpoint,bph,bphws", cbDebugSetHardwareBreakpoint, true); dbgcmdnew("SetMemoryBPX,membp,bpm", cbDebugSetMemoryBpx, true); dbgcmdnew("LibrarianSetBreakpoint,bpdll", cbDebugBpDll, true); dbgcmdnew("SetExceptionBPX", cbDebugSetExceptionBPX, true); dbgcmdnew("bplist", cbDebugBplist, true); dbgcmdnew("SetBPXOptions,bptype", cbDebugSetBPXOptions, false);

全部命令按断点类型可分为五组,加上三个辅助命令:

类别命令(含别名)底层机制
软件断点SetBPX/bp/bpxDeleteBPX/bpc/bcEnableBPX/bpe/beDisableBPX/bpd/bd改写指令字节为 INT3/UD2
硬件断点SetHardwareBreakpoint/bph/bphwsDeleteHardwareBreakpoint/bphc/bphwcEnableHardwareBreakpoint/bphe/bphweDisableHardwareBreakpoint/bphd/bphwdx86 调试寄存器 DR0-DR3
内存断点SetMemoryBPX/membp/bpmSetMemoryRangeBPX/memrangebp/bpmrangeDeleteMemoryBPX/membpc/bpmcEnableMemoryBreakpoint/membpe/bpmeDisableMemoryBreakpoint/membpd/bpmdGuard Page 内存保护页
DLL 断点LibrarianSetBreakpoint/bpdllLibrarianRemoveBreakpoint/bcdllLibrarianEnableBreakpoint/bpedllLibrarianDisableBreakpoint/bpddllLdrLoadDll 回调拦截
异常断点SetExceptionBPXDeleteExceptionBPXEnableExceptionBPXDisableExceptionBPX调试事件筛选
辅助命令bpgotobplistSetBPXOptions/bptype断点跳转、列表与默认类型

在引擎内部,所有断点统一由 breakpoint.h 中的BREAKPOINT结构体描述,其type字段对应BP_TYPE枚举:

enum BP_TYPE { BPNORMAL = 0, //软件断点 BPHARDWARE = 1, //硬件断点 BPMEMORY = 2, //内存断点 BPDLL = 3, //DLL 断点 BPEXCEPTION = 4 //异常断点 };

结构体中的enabled(启用状态)、singleshoot(命中一次即删除)、oldbytes(软件断点被改写前的原始字节)、titantype(传给 TitanEngine 的底层类型标志)等字段,正是下文各命令所操作的核心状态。而 breakpoint.cpp 提供的BpNewBpGetBpDeleteBpEnableBpEnumAll等 API 则是所有断点命令共用的数据层接口。

软件断点:SetBPX 与 bpc/bpe/bpd

SetBPX(bp / bpx):设置软件断点

SetBPX用于在指定地址写入 INT3(short/long)或 UD2 指令,并可选地为断点命名,是最常用的下断命令。它的参数设计非常灵活:

  • arg1:断点地址,可以是表达式或API 名称(如kernel32.CreateFileW),这是对系统 API 下断的关键能力;
  • [arg2]:断点名称,含空格时需用引号包裹。该名称可被EnableBPXDisableBPXDeleteBPX当作别名使用,但主要用途是为命中断点提供一行可读信息。当 arg2 恰好等于一个合法的断点类型(arg3 的取值)时,它会被当作类型解析,arg2 被忽略
  • [arg3]:断点类型,可随机序组合以下关键字:
    • ss:single shot,命中一次后自动删除;
    • long:长 INT3,机器码CD03
    • ud2:UD2 指令,机器码0F0B
    • short:短 INT3,机器码CC(默认)。

类型参数支持ss与其它类型组合成一个字符串。例如文档给出的经典示例:

SetBPX 00401000,"entrypoint",ssud2

即在00401000处设置一个名为 "entrypoint"、命中一次即删除的 UD2 单次断点。当不指定类型、或只指定ss时,使用默认类型;默认类型为short(CC),可通过SetBPXOptions命令修改。

从源码看,cbDebugSetBPX 的实现流程为:先用valfromstring解析地址 → 判断 arg2 是否为合法类型(scmp(argname, "ss"/"long"/"ud2"))→ 用strstr从类型字符串中提取ss(置UE_SINGLESHOOT)与long/ud2/short(分别映射为UE_BREAKPOINT_TYPE_LONG_INT3/UE_BREAKPOINT_TYPE_UD2/UE_BREAKPOINT_TYPE_INT3)→ 读取并保存原字节 → 调用BpNew登记断点 → 调用 TitanEngine 的SetBPX真正改写内存。若地址上已有同名/同址断点,命令会提示 "Breakpoint already set!";若断点存在但处于禁用态,则会自动转为bpe启用。

DeleteBPX(bpc / bc):删除软件断点

DeleteBPX [arg1]删除用SetBPX设置的断点:

  • arg1可以是断点名称或地址
  • 不指定 arg1 时删除全部软件断点

其实现(cbDebugDeleteBPX)先尝试按名称查找(BpGet(0, BPNORMAL, name, &found)),失败再按地址解析;删除前会检查断点是否启用,若启用则调用DeleteBPX还原被改写的内存字节。

EnableBPX(bpe / be)与 DisableBPX(bpd / bd)

EnableBPX [arg1]DisableBPX [arg1]用于启用/禁用软件断点,参数语义与删除命令一致:传名称或地址操作单个断点,不传参数则操作全部("All breakpoints enabled/disabled")。启用时通过SetBPX重新写回断点字节,禁用时通过DeleteBPX移除断点字节但保留断点记录。需要注意的是,禁用/启用的语义与"删除"不同——被禁用的断点仍保留名称、条件等元信息,可在断点窗口看到灰色状态。

硬件断点:bph 系列与调试寄存器

SetHardwareBreakpoint(bph / bphws)

硬件断点使用 CPU 的调试寄存器(DR0-DR3),不修改内存中的任何字节,因此对自校验代码、压缩壳等场景特别有效。参数如下:

  • arg1:断点地址;
  • [arg2]:断点类型,r(read/write,读写均触发)、w(write,仅写入触发)、x(execute,仅执行触发),默认x
  • [arg3]:监视大小,12488 仅 x64 可用),默认1。地址必须按该大小对齐,否则报错 "Address not aligned"。

例如,监视 4 字节数据的写入:

bph 00401000,w,4

源码 cbDebugSetHardwareBreakpoint 展示了几个关键约束:

  • 类型通过switch(*argv[2])解析为UE_HARDWARE_READWRITE/UE_HARDWARE_WRITE/UE_HARDWARE_EXECUTE
  • 大小在_WIN64下才允许8UE_HARDWARE_SIZE_8);
  • 设断前调用GetUnusedHardwareBreakPointRegister寻找空闲调试寄存器,若已用满 4 个,会提示"You can only set 4 hardware breakpoints"——这是 x86 架构 DR0-DR3 的物理上限;
  • 通过TITANSETDRX/TITANSETTYPE/TITANSETSIZE组装titantype,再交给 TitanEngine 的SetHardwareBreakPoint写入调试寄存器。

DeleteHardwareBreakpoint(bphc / bphwc)、EnableHardwareBreakpoint(bphe / bphwe)、DisableHardwareBreakpoint(bphd / bphwd)

这三个命令与软件断点对应命令用法一致:arg1为名称或地址,不传则操作全部。一个值得注意的差异是EnableHardwareBreakpoint不带参数时的语义——文档明确为 "as many as possible hardware breakpoints will be enabled",即尽可能多地启用(受空闲调试寄存器数量限制);而删除/禁用不带参数时是全部操作。

内存断点:bpm 系列与 Guard Page

SetMemoryBPX(membp / bpm)

SetMemoryBPX通过设置 Guard Page 保护属性,对指定地址所在的内存区域整体(从区域基址开始)进行监视:

  • arg1:区域内的任意地址,命令会自动定位到该内存区域的基址;
  • [arg2]1/0,表示命中后是否恢复(继续保留)该断点。当该值既不是1也不是0时,它会被当作 arg3 处理,即bpm eax,r等价于bpm eax,0,r
  • [arg3]:监视类型,a(读+写+执行)、r(读)、w(写)、x(执行),默认a

源码 cbDebugSetMemoryBpx 的实现要点是:调用MemFindBaseAddr(addr, &size, true)自动求出区域基址与大小,然后通过BpNew(base, ..., BPMEMORY, type, 0, size)登记断点,最后调用SetMemoryBPXEx真正设置 Guard Page。从代码看,未指定 arg2 时restore默认为 0,即命中后不自动恢复(single-shot 语义);指定1则断点会一直保留,直到手动删除。监视类型解析为UE_MEMORY(a)/UE_MEMORY_READ(r)/UE_MEMORY_WRITE(w)/UE_MEMORY_EXECUTE(x)。

SetMemoryRangeBPX(memrangebp / bpmrange)

bpm的"整块区域"不同,bpmrange允许精确指定范围:

  • start:范围起始地址;
  • size:范围大小;
  • [type]:监视类型a/r/w/x默认a;在类型后追加ss表示 single-shot(只命中一次),等价于使用 SetMemoryBreakpointSingleshoot 命令设置单次语义。

例如:

memrangebp 00401000,100,rss

表示对00401000起始的 0x100 字节做只读监视,命中一次即失效。实现 cbDebugSetMemoryRangeBpx 通过strstr(argv[3], "ss")识别单次标志,并直接以start/size调用BpNewSetMemoryBPXEx,无需再计算区域基址。

DeleteMemoryBPX(membpc / bpmc)、EnableMemoryBreakpoint(membpe / bpme)、DisableMemoryBreakpoint(membpd / bpmd)

与前述类别一致:arg1为名称或(基)地址,不带参数则全部删除/启用/禁用。实现上,启用通过SetMemoryBPXEx重新设置 Guard Page(见 cbEnableAllMemoryBreakpoints),禁用通过RemoveMemoryBPX移除保护属性。

DLL 断点:bpdll 系列

DLL 断点用于在指定模块加载/卸载时自动中断,对跟踪插件加载顺序、监控模块注入非常实用。

LibrarianSetBreakpoint(bpdll)

  • arg1:要监视的 DLL 名称(不区分大小写);
  • [arg2]:触发时机,a表示加载与卸载都中断,l仅加载,u仅卸载,默认a
  • [arg3]:只要出现该参数即为 single-shot,命中一次后断点自动移除;不指定则持续生效。

例如:

bpdll user32.dll bpdll myplugin.dll,l,ss

第一个命令在user32.dll加载/卸载时都中断;第二个命令在myplugin.dll加载时中断一次即失效。从实现 cbDebugBpDll 看,命令会先剥离路径(strrchr(argv[1], '\\'))并转小写,再映射a/l/uUE_ON_LIB_ALL/UE_ON_LIB_LOAD/UE_ON_LIB_UNLOAD,依次调用BpNewDll登记和dbgsetdllbreakpoint挂接底层回调。

LibrarianRemoveBreakpoint(bcdll)、LibrarianEnableBreakpoint(bpedll)、LibrarianDisableBreakpoint(bpddll)

三个命令均以 DLL 名称为参数,不带参数则作用于全部 DLL 断点(bpedll/bpddll的文档原文如此,虽然描述文字沿用了 SetBreakpoint 的说法,但语义为启用/禁用 DLL 断点)。注意 DLL 断点的查找方式与其它类型不同——它按module匹配而非地址(见BpGetAny(BPDLL, argv[1], &bp))。

异常断点:SetExceptionBPX 系列

SetExceptionBPX

异常断点把指定异常变成断点事件:只要该异常断点处于激活状态,所有相同 chance(首次/二次机会)与代码的异常都会被捕获为断点事件,不再走默认的异常处理策略

  • arg1:异常名称或代码,如ACCESS_VIOLATION80000003(INT3 断点异常代码)等;
  • [arg2]:捕获时机(chance):
    • first1:仅首次机会异常(默认);
    • second2:仅二次机会异常;
    • all3:所有异常。

从实现 cbDebugSetExceptionBPX 看,地址解析支持valfromstring(数值)与ExceptionNameToCode(名称)两条路径;chance 被映射为ex_firstchance/ex_secondchance/ex_all并存入BpNew(ExceptionCode, true, false, 0, BPEXCEPTION, extype, "")。注意异常断点的"地址"字段实际存放的是异常代码,这是它与其它断点类型最本质的区别。

DeleteExceptionBPX / EnableExceptionBPX / DisableExceptionBPX

三者参数语义一致:arg1为名称、异常名或代码;不带参数则删除/启用/禁用全部异常断点。删除与查找时同样支持名称与ExceptionNameToCode两种匹配方式(cbDebugDeleteExceptionBPX)。

辅助命令:bpgoto、bplist、SetBPXOptions

bpgoto:命中断点后跳转

bpgoto arg1,arg2把断点配置成"到达 arg1 时,将程序流导向 arg2"。文档明确给出了它的等价展开——以下四条命令:

SetBreakpointCondition arg1, 0 SetBreakpointCommand arg1, "CIP=arg2" SetBreakpointCommandCondition arg1, 1 SetBreakpointFastResume arg1, 0

即:条件恒为假(不真正停止)、命中后执行CIP=arg2改写指令指针、命令条件恒真、不快速恢复(保证命令被执行)。源码 cbDebugSetBPGoto 正是通过cmddirectexec依次执行这四条命令实现的。这本质上是一种"断点即补丁"技巧,常用于跳过反调试代码或某段耗时逻辑。

bplist:列出全部断点

bplist无参数,输出所有断点的状态、类型、地址与可选名称。每行格式为:

STATE:TYPE:ADDRESS[:NAME]
  • STATE0表示禁用,1表示启用。注意文档说明:只有 single-shot 与普通断点可以被禁用(言下之意部分类型状态固定);
  • TYPEBP(普通软件断点,SetBPX设置)、SS(single-shot 断点)、HW(硬件断点)、GP(Guard Page,即内存断点);
  • ADDRESS:断点地址,x32/x64 调试器分别以 32/64 位宽度输出;
  • NAME:断点名称(若有)。

从 cbBreakpointList 的实现看,实际输出还额外支持DLLEX两种类型(对应 DLL 断点与异常断点),且 DLL 断点的行格式为STATE:TYPE:"模块名":"名称",异常断点的"地址"列输出的是异常代码。因此bplist也是脚本里枚举断点、做自动化断点管理的基础工具。

SetBPXOptions(bptype):设置默认断点类型

SetBPXOptions arg1修改SetBPX的默认类型,可选值:

  • short:CC(短 INT3,默认);
  • long:CD03(长 INT3);
  • ud2:0F0B(UD2)。

文档强调该默认类型同时影响普通断点与 single-shot 断点。实现 cbDebugSetBPXOptions 会把选择持久化到配置文件:BridgeSettingSetUint("Engine", "BreakpointType", setting_type)(0=short、1=long、2=ud2),下次启动依然生效。UD2 断点对反调试检测(如检测 CC 断点字节的完整性校验)有天然对抗优势,是逆向常用技巧。

实战:组合使用与脚本化建议

将上述命令串联即可完成复杂的调试自动化,例如:

bpx kernel32.CreateFileW,"CreateFile" //对 API 下带名断点 bph 00401234,w,4 //监视 4 字节写操作 bpm eax,r //对 eax 所在内存区域做读监视 bpdll plugin.dll,l,ss //插件加载时中断一次 SetExceptionBPX ACCESS_VIOLATION,first //捕获首违例异常 bplist //查看全部断点状态 bpgoto 00401337,00401400 //命中 00401337 时跳转 bptype ud2 //把默认软件断点类型改为 UD2

所有这些命令均可在命令栏、脚本文件(配合 script 命令)以及条件断点的命令回调中使用,断点命中后的条件、日志、命令执行等进阶能力则属于 conditional-breakpoint-control 章节的范畴(例如上文提到的 SetMemoryBreakpointSingleshoot)。掌握本节的 25 个命令与 BREAKPOINT 结构 的字段语义,即可对 x64dbg 的断点体系形成完整认知,写出精确、可复用的调试脚本。

小结

x64dbg 的断点控制命令在设计上高度一致——每个断点类别都配套"设置/删除/启用/禁用"四个命令,且都支持"不传参数即操作全部"的批量语义,这降低了记忆成本;而每种断点的底层机制(字节改写、调试寄存器、Guard Page、加载回调、异常筛选)又各有特性与限制,例如硬件断点上限 4 个、内存断点作用于整个区域、异常断点按代码而非地址登记等。结合 cmd-breakpoint-control.cpp 的源码逐条对照,可以更准确地预判每条命令在边界情况下的行为,让断点成为逆向与恶意软件分析中最可靠的控制手段。

【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 5:08:55

桌面Agent本地部署实战:19种方案选型与避坑指南

1. 这不是“又一个AI工具列表”,而是一份桌面Agent落地实操手记我从去年夏天开始系统性地搭建自己的本地AI工作流,从最初在MacBook Air上用Ollama跑Qwen2-0.5B卡顿到怀疑人生,到现在能用RX580显卡在Windows台式机上稳定调度DeepSeek-R1GLM-4.…

作者头像 李华
网站建设 2026/9/19 5:06:33

UE5集成Entt ECS:大规模实体性能优化实践

我最早动这个念头,是因为项目里一个玩法模块的实体数量冲到了8000以上。UE5原生Actor加Component的组合在编辑器里跑得很欢,一到打包版本就开始肉眼可见地掉帧,Profiler一拉,逻辑线程的Tick开销和数据碎片全堆在那里。后来把Entt接…

作者头像 李华
网站建设 2026/9/19 5:06:33

27B大模型真能塞进M.2?RK3588+后摩LQ50端侧推理实录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 5:06:25

基于CST的毫米波雷达ADAS仿真:从回波到RD图全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 5:06:05

列车通信网络TCN架构解析:从MVB/WTB到以太网化演进

在检修库待过的人都懂一个画面:一列车晚上入库时还好好的,第二天早上出库前,司机台报“网络通信故障”,整列车瘫痪在库里。调度催、检修急,仪表一个一个查下来,最后往往就是一个终端电阻氧化或者屏蔽层接地…

作者头像 李华