Cutter 反汇编视图断点管理:从 Add/remove breakpoint 到高级断点对话框的完整指南
【免费下载链接】cutterFree and Open Source Reverse Engineering Platform powered by rizin项目地址: https://gitcode.com/gh_mirrors/cu/cutter
导读
本文围绕 Cutter(基于 rizin 的开源逆向工程平台)反汇编视图中与断点管理相关的右键上下文菜单展开,完整讲解「Add/remove breakpoint」与「Advanced breakpoint」两个核心菜单项的触发方式、快捷键、适用场景及其背后的源码实现。读完本文,你将掌握在反汇编视图中快速切换软件断点、通过高级对话框配置硬件断点 / 条件断点 / 跟踪断点 / 断点命令的完整操作流程,并能从 Cutter 源码层面理解断点的创建、编辑与底层 rizin 交互链路。
一、菜单入口与操作概览
在 Cutter 的反汇编视图中,对任意一条指令单击右键即可弹出反汇编上下文菜单,其中包含一个名为Breakpoint的子菜单,用于集中管理断点。该子菜单包含两项:
| 菜单项 | 功能 | 默认快捷键 |
|---|---|---|
| Add/remove breakpoint | 在当前地址添加断点;若已存在断点则移除 | F2(亦绑定Ctrl+B) |
| Advanced breakpoint | 打开高级断点对话框,配置硬件、条件等高级断点 | Ctrl+F2 |
该子菜单由 DisassemblyContextMenu.cpp 中的addBreakpointMenu()方法构建:先通过addMenu(tr("Breakpoint"))创建子菜单,再将actionAddBreakpoint与actionAdvancedBreakpoint两个动作依次加入,两个动作分别通过快捷键标识Debug.toggleBreakpoint与Debug.advancedBreakpoint注册。
二、Add/remove breakpoint:在当前地址快速切换断点
2.1 描述与操作步骤
- 描述:在当前指令地址添加一个断点;如果该地址已经存在断点,则执行移除操作,即一个「切换(toggle)」语义。
- 操作步骤:在反汇编视图中右键点击一条指令,选择
Breakpoint -> Add/remove breakpoint。 - 快捷键:
F2(默认绑定;同时在 DefaultShortcuts.cpp 中额外绑定了Ctrl+B作为备选键位)。
2.2 底层实现:从菜单动作到 rizin
在 DisassemblyContextMenu.cpp 中,addBreakpointTriggered()直接调用Core()->toggleBreakpoint(offset),其中offset是右键点击时菜单记录的目标地址(由setOffset(RVA offset)传入)。
toggleBreakpoint在 Cutter.cpp 中的实现为:
void CutterCore::toggleBreakpoint(RVA addr) { CORE_LOCK(); rz_core_debug_breakpoint_toggle(core, addr); emit breakpointsChanged(addr); }可以看到 Cutter 将切换逻辑委托给 rizin 高层 APIrz_core_debug_breakpoint_toggle,并在操作完成后发出breakpointsChanged信号,驱动断点列表(BreakpointWidget)、反汇编视图等界面同步刷新。
2.3 菜单文本的动态切换
值得注意的一个细节是:菜单项文本并不是固定不变的。在aboutToShowSlot()(菜单即将显示时触发)中,Cutter 会查询当前地址是否存在断点,并据此动态改写动作文本(见 DisassemblyContextMenu.cpp):
const bool hasBreakpoint = Core()->breakpointIndexAt(offset) > -1; actionAddBreakpoint.setText(hasBreakpoint ? tr("Remove breakpoint") : tr("Add breakpoint")); actionAdvancedBreakpoint.setText(hasBreakpoint ? tr("Edit breakpoint") : tr("Advanced breakpoint"));也就是说:当目标地址已有断点时,右键菜单会显示「Remove breakpoint」;没有断点时才显示「Add breakpoint」。同理,高级断点菜单项在断点存在时变为「Edit breakpoint」。breakpointIndexAt在 Cutter.cpp 中通过rz_bp_get_index_at判断该地址在 rizin 断点列表中的索引是否存在。
三、Advanced breakpoint:高级断点对话框
3.1 描述与操作步骤
- 描述:打开高级断点对话框。该对话框不仅支持在当前地址创建常规(软件)断点,还支持配置硬件断点、条件断点、断点命令、跟踪断点、启用状态等高级选项。
- 操作步骤:在反汇编视图中右键点击一条指令,选择
Breakpoint -> Advanced breakpoint。 - 快捷键:
Ctrl+F2(默认绑定,见 DefaultShortcuts.cpp)。
3.2 底层实现:新建还是编辑由断点状态决定
advancedBreakpointTriggered()的实现(见 DisassemblyContextMenu.cpp):
void DisassemblyContextMenu::advancedBreakpointTriggered() { const int index = Core()->breakpointIndexAt(offset); if (index >= 0) { BreakpointsDialog::editBreakpoint(Core()->getBreakpointAt(offset), parentForDialog()); } else { BreakpointsDialog::createNewBreakpoint(offset, parentForDialog()); } }即:如果目标地址已有断点,则基于现有断点信息打开编辑模式(editBreakpoint);否则以当前地址预填位置字段并打开新建模式(createNewBreakpoint)。两种模式复用同一个 BreakpointsDialog 对话框,其窗口标题分别为 "Edit breakpoint" 与 "New breakpoint"。
对话框确认后,createNewBreakpoint调用Core()->addBreakpoint(getDescription()),editBreakpoint调用Core()->updateBreakpoint(index, getDescription())(见 BreakpointsDialog.cpp)。
四、高级断点对话框字段详解
根据 BreakpointsDialog.cpp 与 BreakpointsDialog.ui 的源码,对话框可配置以下字段:
4.1 位置类型(Position Type)
| 类型 | 含义 | 说明 |
|---|---|---|
| Address | 地址 | 输入地址或创建断点时计算的表达式 |
| Named | 命名 | 以表达式形式存储断点位置 |
| Module offset | 模块偏移 | 相对于某加载模块的偏移量,需同时指定模块名 |
选择 Module offset 时会启用模块选择下拉框(moduleName),模块列表来源于Core()->getMemoryMap()的去重结果,并支持包含匹配的自动补全。位置输入框为空时,对话框的 OK 按钮会被禁用(refreshOkButton)。
4.2 断点类型与硬件权限
- 软件断点(Software):默认类型,通过修改指令流实现中断。
- 硬件断点(Hardware):选择后需指定访问权限与尺寸:
- 读(Read,
RZ_PERM_R) - 写(Write,
RZ_PERM_W) - 执行(Execute,
RZ_PERM_X) - 断点尺寸(size,默认值来自下拉框,最终通过
Core()->num()解析)
- 读(Read,
权限选择存在互斥约束(见configureCheckboxRestrictions):勾选读/写会取消执行;勾选执行会取消读/写;且三者中至少保留一项。在 Cutter.cpp 的addBreakpoint中,硬件断点会通过config.permission & ~(RZ_PERM_X)计算出 watchpoint 保护位,再调用rz_debug_bp_add创建断点。
4.3 条件、命令与行为选项
| 字段 | 作用 | 源码对应 |
|---|---|---|
| Condition | 条件表达式,命中条件满足时才触发断点 | breakpointCondition可编辑下拉框,写入 rizin 的cond字段 |
| Command | 断点命中时自动执行的命令 | breakpointCommand多行文本域,写入 rizin 的data字段 |
| Trace | 跟踪断点:命中时记录执行轨迹 | checkTrace,通过setBreakpointTrace设置trace属性 |
| Enabled | 断点是否启用 | checkEnabled,控制enabled属性 |
在addBreakpoint中,非空的条件与命令分别通过updateOwnedCharPtr(breakpoint->cond, ...)与updateOwnedCharPtr(breakpoint->data, ...)写入 rizin 的RzBreakpointItem结构;跟踪选项则在断点创建后调用setBreakpointTrace(index, config.trace)单独设置(见 Cutter.cpp)。
五、断点数据模型与底层 rizin 交互链路
5.1 BreakpointDescription 数据模型
高级对话框通过getDescription()将界面输入收集为BreakpointDescription结构(BreakpointsDialog.cpp),包含addr、index、size、positionExpression、type、permission、command、condition、hw、trace、enabled等字段;反向地,rizin 的rz_bp_item_t也会通过breakpointDescriptionFromRizin(Cutter.cpp)转换为该结构,供编辑对话框回填。
5.2 关键调用链总结
右键菜单点击 └─ DisassemblyContextMenu::addBreakpointTriggered / advancedBreakpointTriggered ├─ CutterCore::toggleBreakpoint(offset) │ └─ rz_core_debug_breakpoint_toggle(core, addr) // rizin └─ BreakpointsDialog::createNewBreakpoint / editBreakpoint ├─ CutterCore::addBreakpoint(desc) │ └─ rz_debug_bp_add(core->dbg, addr, size, hw, watchpoint, perm, module, delta) └─ CutterCore::updateBreakpoint(index, desc) └─ rz_bp_del + addBreakpoint(先删后建)其中updateBreakpoint采用「先按地址删除再重新创建」的方式(Cutter.cpp),源码注释指出这是为了规避rz_bp_del_index对非地址型(Named/Module)断点按索引删除的缺陷。
5.3 断点状态的查询与同步
无论是菜单文本动态切换、还是高级对话框的新建/编辑分流,都依赖CutterCore::breakpointIndexAt(addr)查询地址对应的断点索引,并配合getBreakpointAt(addr)获取完整的BreakpointDescription。所有增删改操作完成后都会发出breakpointsChanged信号,驱动断点停靠窗口(BreakpointWidget)与代码视图同步刷新,保证界面与 rizin 内部状态一致。
六、快捷键与自定义
两个断点菜单项的快捷键通过 Cutter 的 ShortcutManager 注册,默认定义位于 DefaultShortcuts.cpp:
{ "Debug.toggleBreakpoint", { { Qt::Key_F2, Qt::CTRL | Qt::Key_B }, QT_TRANSLATE_NOOP("DecompilerContextMenu", "Add/remove breakpoint"), "DecompilerContextMenu" } }, { "Debug.advancedBreakpoint", { { Qt::CTRL | Qt::Key_F2 }, QT_TRANSLATE_NOOP("DecompilerContextMenu", "Advanced breakpoint"), "DecompilerContextMenu" } },也就是说:
- Add/remove breakpoint:
F2或Ctrl+B - Advanced breakpoint:
Ctrl+F2
这些快捷键与反汇编视图共享同一套注册体系(上下文名为DecompilerContextMenu,反汇编与反编译菜单均复用该快捷键),并可在「设置 -> 快捷键」界面中由用户自定义。类似地,断点列表窗口自身还有独立的快捷键:Breakpoint.toggleBreakpoint(空格键)与Breakpoint.delBreakpoint(Delete 键),可在 DefaultShortcuts.cpp 中查看。
七、典型使用场景与小结
- 快速设断点:分析时对目标指令直接按
F2,即可在反汇编视图中实现断点的新增/移除切换,配合断点列表窗口的空格键切换,效率最高。 - 条件与命令断点:当需要在特定条件(如寄存器值、内存值)满足时才中断,或在命中时自动执行输出寄存器、dump 内存等命令时,使用
Ctrl+F2打开高级对话框配置 Condition 与 Command。 - 硬件断点/观察点:在调试需要监控内存读写(而非仅执行)的场景下,选择 Hardware 断点并勾选读/写权限,Cutter 会将其转换为 rizin 的 watchpoint 语义(
watchpointProt = permission & ~RZ_PERM_X)创建。 - 跟踪断点:需要记录程序执行轨迹时,勾选 Trace 选项,断点命中将写入执行轨迹数据。
通过「快速切换 + 高级对话框」的组合,Cutter 在反汇编视图这一个右键菜单入口内,覆盖了从最常用软件断点到硬件观察点、条件触发、命令注入、轨迹跟踪的完整断点能力,并且全部能力都能追溯到清晰的源码实现(DisassemblyContextMenu.cpp、BreakpointsDialog.cpp、Cutter.cpp),便于二次开发与深度定制。
相关参考文档:manage-breakpoints-context-menu.rst、debug-context-menu.rst。
【免费下载链接】cutterFree and Open Source Reverse Engineering Platform powered by rizin项目地址: https://gitcode.com/gh_mirrors/cu/cutter
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考