Hexdump Widget 右键菜单完整指南:从每行字节数到二进制补丁写入
【免费下载链接】cutterFree and Open Source Reverse Engineering Platform powered by rizin项目地址: https://gitcode.com/gh_mirrors/cu/cutter
Hexdump 视图是 Cutter(基于 rizin 的自由开源逆向工程平台)中查看与修改二进制数据的主要入口。本文以 hexdump-widget-context-menu.rst 与其子文档 patching.rst 为骨架,系统梳理该组件右键菜单的全部功能,包括“Bytes per row”行宽控制、以及 Edit 菜单下从 ASCII 字符串到 Base64、随机字节、偏移复制、增减操作的完整补丁写入能力。阅读本文后,你将能熟练调整 Hexdump 的显示粒度,并掌握在不切换视图的情况下直接对二进制内容进行精准写入的操作方法。
概述:Hexdump Widget 及其右键菜单
Hexdump Widget 是 Cutter 中以十六进制形式展示内存与文件内容的可停靠窗口,其核心绘制与交互逻辑由 HexWidget.cpp 实现。右键点击任意字节会弹出上下文菜单,菜单内容在HexWidget::contextMenuEvent(HexWidget.cpp)中动态组装,包括:
- Item size / Item format:单个“item”(可编辑的最小单元)的大小(1/2/4/8 字节)与显示格式(Hexadecimal、Octal、Decimal、Signed decimal、Float);
- Bytes per row:每行显示字节数(即本主题文档的核心内容);
- Bytes as pairs:是否以字节对(16 位)方式分组显示;
- Edit 子菜单:全部二进制写入操作(见下文 Patching 一节);
- Edit with keyboard:键盘编辑模式开关;
- 复制、注释、标志、书签(Marks)等辅助操作。
菜单通过 QAction 构建(动作定义见 HexWidget.cpp),以下重点展开文档明确描述的两大部分:Bytes Per Row与Patching(Edit 子菜单)。
Bytes Per Row:控制每行字节数
右键菜单中的Bytes per row(源码中对应rowSizeMenu,见 HexWidget.cpp)用于选择 Hexdump 视图中每行应显示的字节数。该设置直接决定一屏内可见的地址范围与行宽,适合在“宽行概览”与“窄行精读”之间切换。
可用选项
文档列出如下选项,源码中通过QActionGroup(互斥单选)构造:
| 选项 | 说明 |
|---|---|
| 1 byte | 每行 1 字节,行最窄、行数最多,便于逐字节精读 |
| 2 bytes | 每行 2 字节 |
| 4 bytes | 每行 4 字节 |
| 8 bytes | 每行 8 字节 |
| 16 bytes | 每行 16 字节,传统 hexdump 风格 |
| 32 bytes | 每行 32 字节,行宽较大 |
| Power of 2 (Auto) | 自动模式:由控件根据可用宽度自动选择 2 的幂次行宽 |
源码实现
在 HexWidget.cpp 中:
- 固定选项通过循环
for (int i = 1; i <= maxLineWidthPreset; i *= 2)生成,即 1/2/4/8/16/32 六个 2 的幂选项,每个动作触发setFixedLineSize(i)将行宽固定为该值; - 最后一个
Power of 2动作触发setColumnMode(ColumnMode::PowerOf2),进入按容器宽度自动计算的动态行宽模式; - 所有选项共用同一个
QActionGroup(columnsActionGroup),保证同一时刻只有一项被选中。
因此文档中的“Power of 2 (Auto)”与固定值互斥:选择任意固定字节数会退出自动模式,反之选中 Auto 会忽略手动设定。若 Hexdump 区域大小发生改变(例如拖动停靠窗边界),自动模式会随之调整行宽,而固定模式保持设定值不变。
Edit 子菜单:Patching 补丁写入操作
右键菜单的Edit子菜单(源码中writeMenu,见 HexWidget.cpp)汇聚了 Cutter 的全部二进制写入操作。菜单项分成两组:actionsWriteString(字符串类)与actionsWriteOther(其他写入类)。所有写入都需要写入模式(I/O Modes)允许写操作(对应ioModesController.canWrite()检查,见 HexWidget.cpp)。
以下按文档顺序逐一说明。一个共同行为:如果当前有多字节选中,写入操作会从选区起点开始生效;未选中时则作用于光标当前位置。
Write String(写 ASCII 字符串)
- 菜单路径:
Edit -> Write string - 功能:在当前位置写入 ASCII 字符串。若已选中多字节,则从选区起点开始写入。
- 注意:本项不会自动追加 null 终止符,也不会写入宽字符串——需要这些特性请使用下面的其他菜单项。
- 源码对应:动作
actionWriteString触发wWriteString(HexWidget.cpp)。
Write Length and String(写长度前缀 + 字符串)
- 菜单路径:
Edit -> Write length and string - 功能:写入一个“长度前缀 + ASCII 字符串”。长度前缀的长度与具体格式由用户在弹出的输入框中指定(典型用法是构造类 Pascal/BSTR 风格的数据)。
- 注意:虽然在概念上类似 Windows BSTR,但本项不会在字符串末尾追加 null 终止的 WCHAR。
- 源码对应:动作
actionWriteLenString触发wWritePascalString(HexWidget.cpp)。
Write Wide String(写宽字符串)
- 菜单路径:
Edit -> Write wide string - 功能:在当前位置写入null 终止的宽字符串(每个字符占 2 字节,UTF-16 风格),自动带终止符。
- 源码对应:动作
actionWriteWideString触发wWriteWideString(HexWidget.cpp)。
Write Null-Terminated String(写 null 终止字符串)
- 菜单路径:
Edit -> Write zero terminated string - 功能:在当前位置写入null 终止的 ASCII 字符串,即自动在末尾追加
\x00。 - 源码对应:动作
actionWriteCString触发wWriteCString(HexWidget.cpp)。
Write Encoded/Decoded Base64 String(Base64 编码/解码写入)
- 菜单路径:
Edit -> Write De\Encoded Base64 string - 功能:弹出对话框后,可选择“编码(Encode)”或“解码(Decode)”:
- Encode:把输入的明文字符串按 Base64 编码后的字节写入当前位置;
- Decode:把输入的 Base64 文本解码为原始字节后写入。
- 对话框实现:
Base64EnDecodedWriteDialog(WriteCommandsDialogs.cpp),提供getMode()与getData()分别返回编码/解码模式与结果数据。 - 源码对应:动作
actionWrite64触发wWrite64(HexWidget.cpp)。
Write Zeroes(写零填充)
- 菜单路径:
Edit -> Write zeroes - 功能:在当前位置写入指定数量的 null 字节(
\x00)。 - 操作方式:在打开的对话框中输入要写入的 null 字节个数。
- 实现说明:底层
writeZeros(HexWidget.cpp)以 1024 字节为缓冲上限分块写入,对大段清零也保持高效。 - 源码对应:动作
actionWriteZeros触发wWriteZeros(HexWidget.cpp)。
Write Random Bytes(写随机字节)
- 菜单路径:
Edit -> Write random bytes - 功能:在当前位置写入指定数量的随机字节,常用于模糊测试、破坏性测试或制造随机填充数据。
- 操作方式:在对话框中指定要写入的字节数。
- 源码对应:动作
actionWriteRandom触发wWriteRandom(HexWidget.cpp)。
Duplicate Bytes From Offset(从指定偏移复制)
- 菜单路径:
Edit -> Duplicate from offset - 功能:从指定的源偏移处复制 N 个字节到当前位置。用户需指定源偏移与要复制的字节数;对话框内提供预览窗格展示将要复制的字节内容,避免复制错误数据。
- 对话框实现:
DuplicateFromOffsetDialog(WriteCommandsDialogs.cpp),其refresh()在偏移或长度输入变化时实时更新预览,getOffset()/getNBytes()返回用户输入。 - 源码对应:动作
actionDuplicateFromOffset触发wDuplFromOffset(HexWidget.cpp)。
Increment/Decrement Bytes(递增/递减数值)
- 菜单路径:
Edit -> Increment/Decrement - 功能:对当前位置的数值进行递增或递减。用户需要在对话框中指定三项:
- 操作宽度:Byte(1 字节)、Word(2 字节)、Dword(4 字节)或 Qword(8 字节);
- 运算值:要加上(或减去)的数值;
- 运算方向:Increment(加)或 Decrement(减)。
- 对话框实现:
IncrementDecrementDialog(WriteCommandsDialogs.cpp),提供getMode()(增/减)、getNBytes()(宽度)与getValue()(运算值)供调用方获取参数。 - 源码对应:动作
actionIncDec触发wIncreaseDecrease(HexWidget.cpp)。
写入操作速查表
| 菜单项(Edit 子菜单) | 写入内容 | 自动终止符 | 需要输入 | 源码入口 |
|---|---|---|---|---|
| Write string | ASCII 字符串 | 无 | 字符串 | wWriteString |
| Write length and string | 长度前缀 + ASCII 字符串 | 无(非 WCHAR) | 长度与字符串 | wWritePascalString |
| Write wide string | null 终止宽字符串 | 有(WCHAR) | 字符串 | wWriteWideString |
| Write zero terminated string | null 终止 ASCII 字符串 | 有(\x00) | 字符串 | wWriteCString |
| Write De\Encoded Base64 string | Base64 编码/解码结果 | — | 文本与模式 | wWrite64 |
| Write zeroes | N 个 null 字节 | — | 字节数 | wWriteZeros |
| Write random bytes | N 个随机字节 | — | 字节数 | wWriteRandom |
| Duplicate from offset | 源偏移处的 N 个字节 | — | 源偏移与字节数(带预览) | wDuplFromOffset |
| Increment/Decrement | 对 Byte/Word/Dword/Qword 做增减 | — | 宽度、值、方向 | wIncreaseDecrease |
操作前提与提示
- 写入模式:所有 Edit 下的写入操作均需当前 I/O 模式允许写入;只读打开文件或仅可读的映射区域会禁用对应菜单能力(检查逻辑见 HexWidget.cpp)。
- 选区行为:存在多字节选区时,写入一律从选区起点开始,长度不足时按操作所需字节数向后覆盖。
- 撤销:Cutter 的写入会进入 rizin 的 undo/redo 栈,可通过主界面的撤销/重做操作回退,便于反复尝试补丁。
- 菜单语言:以上菜单名取自源码中的
tr()翻译标记,在非英文界面下显示为对应语言,功能不变。
相关资源
- 主题文档:hexdump-widget-context-menu.rst 与 patching.rst
- 右键菜单与全部动作实现:HexWidget.cpp
- 写入对话框实现:WriteCommandsDialogs.cpp、Base64EnDecodedWriteDialog.ui、DuplicateFromOffsetDialog.ui、IncrementDecrementDialog.ui
- Hexdump 停靠窗口封装:HexdumpWidget.cpp
【免费下载链接】cutterFree and Open Source Reverse Engineering Platform powered by rizin项目地址: https://gitcode.com/gh_mirrors/cu/cutter
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考