简介:HexEdit是基于GitHub开源项目(strobejb/HexEdit)的十六进制编辑器源代码包,适合需要查看、搜索和编辑二进制文件的程序员、逆向工程学习者及软件调试人员。包内是完整的Windows桌面应用工程,压缩后共220个文件、约528KB,主体由51个C文件、48个C++文件、47个头文件组成,辅以Visual Studio工程文件(sln、vcxproj、filters)与bat构建脚本,另有bmp、ico、png图标位图及rc资源脚本,可直接编译还原项目。已有199人学习下载。通过阅读这套源码,可以掌握十六进制编辑器的界面搭建、文件字节级读写与数据搜索等核心实现思路,也能了解工具栏、位图等资源的组织方式,对想深入桌面开发或二进制分析工具的读者颇有参考价值。
1. 二进制文件查看这个需求,HexEdit 是怎么解决的
做嵌入式、逆向或者数据恢复的人,大概率都经历过同一个场景:拿到一个 .bin 文件,用文本编辑器打开全是乱码,用 Python 写脚本又觉得小题大做。二进制文件查看这件事,说到底是把字节流以一种人能读的方式呈现出来,而 HexEdit 就是 GitHub 上的一个开源十六进制编辑器,专门干这个。它的核心价值很直接——打开文件看到十六进制和 ASCII 双列视图,能定位、能查找、能修改,不需要折腾环境。适合手里攒了一堆 bin 文件、天天跟字节打交道的人,也适合刚入门想搞懂文件结构的新手。
2. 从字节流到 Hex 视图:界面三件套与字节序的底层逻辑
2.1 偏移量、十六进制列与 ASCII 列:界面三件套
打开 HexEdit 加载一个文件后,看到的界面通常分三块:最左边是偏移量(Offset),中间是十六进制字节,最右边是对应的 ASCII 字符。这三列各有各的用处,缺一个都会让排查效率打折扣。
偏移量那一列,我一般习惯叫它“文件里的坐标”。它告诉你在文件中的绝对位置。比如一个文件头畸形了,你定位到偏移 0x2C,看到的是文件头某个字段的值。排查问题的时候,工具给的报错信息里往往直接写“offset 44”,说明白点就是 0x2C,你在 HexEdit 里直接看那一行就能对上号。没有偏移量,你只能靠肉眼数格子,那效率就太低了。
十六进制列是真正的内容。每一个字节用两个十六进制字符表示,从 00 到 FF。比如一个字节的值是 255,这一列就显示成 FF。这列是核心,排查文件格式问题、改字节、对比数据,都是在跟这一列打交道。ASCII 列是个附产物,把字节转成可打印字符方便人眼扫。但这列有很强的误导性——遇到不可打印字符时显示成点号,遇到 UTF-8 编码的中文会变成一堆乱码。这是正常的,不是 HexEdit 显示坏了,不要慌。
2.2 为什么要用 HexEdit 而不是文本编辑器或脚本
有人会问,我直接用 VSCode 或者记事本打开 bin 文件不行吗?行,但会很痛苦。文本编辑器打开二进制文件时会先做编码猜测,把字节流按 UTF-8 或者 GBK 解码,结果就是满屏的乱码和替换字符。更麻烦的是,一些文本编辑器在大文件面前会直接卡死,因为它们按文本行组织内容,而 bin 文件里根本没有“行”的概念。
另一种常见做法是用 Python 写脚本读取,但临时看一眼文件头、找几个字节,写脚本的成本反而高于收益。我一般会先打开 HexEdit 扫一遍,确认结构后再决定要不要上脚本。真正需要脚本的时候,是你要批量处理几百个文件,而不是只看一个。十六进制编辑器这类工具存在的逻辑,就是让你在“低成本的快速查看”和“高成本的批量处理”之间有个中间选项。
2.3 字节序:Hex 视图里小端是常态
看 Hex 视图最容易被绕进去的是字节序问题。在 x86 平台上,多字节数值在内存里是按小端存放的,也就是低字节在前。举例来说,一个 32 位的数值 0x12345678,在文件里看到的字节序列是 78 56 34 12,而不是 12 34 56 78。我第一次用十六进制编辑器的时候,盯着这个看了半天,以为文件坏了,后来才知道是字节序的锅。
如果你在处理的是有固定格式的文件(比如设备固件、PE 文件、ELF 文件),格式文档里通常会说明字段是什么字节序。Intel 体系下常见的是小端,网络协议里常见的是大端。HexEdit 这类工具一般显示的是原始字节流,不会替你翻转,这反而是个优点——你看到的就是磁盘上真实的字节排列,不会被“美化”之后误导判断。遇到可疑的字段,先确认字节序,再解释数值。
3. 用 HexEdit 完成一次真实排查:魔数定位、查找替换与回写验证
3.1 从 GitHub 拉取代码并构建
HexEdit 在 GitHub 上开源,源码拉下来后自己构建一次,能顺带搞清楚依赖关系,后面换机器部署也顺手。这个项目基于 wxWidgets,跨平台支持是它的卖点之一,所以构建前的依赖安装和大多数 wxWidgets 项目类似。常见做法是先装好 wxWidgets 开发包,再走 CMake 配置流程。
# 以 Debian/Ubuntu 为例,安装构建依赖 sudo apt install build-essential cmake libwxgtk3.2-dev # 拉取 HexEdit 源码 git clone https://github.com/strobejb/HexEdit.git cd HexEdit # 走 CMake 构建流程 cmake -S . -B build cmake --build build -j4这段流程里,libwxgtk3.2-dev是 wxWidgets 的 GTK 版开发包,提供 GUI 库和头文件;cmake -S . -B build指定源码目录和构建目录,把生成文件隔离在 build 里,方便后面清理;-j4让编译并行跑 4 个任务,机器核数多的话可以调大。构建完成后,可执行文件一般在 build 目录下,名字跟项目名对应。如果机器的发行版没有 wxGTK 3.2 这个包名,用apt search wxgtk查一下实际版本就行。
3.2 定位文件类型:魔数从偏移 0 开始
拿到一个不认识的文件,第一步永远是看偏移 0 的字节,也就是文件开头的那几个字节。绝大多数文件格式都会在这放一个魔数(Magic Number),用于标识文件类型,这也是十六进制编辑器最常用的场景。
| 文件类型 | 偏移 0 开始的魔数(十六进制) | 对应 ASCII 可见字符 |
|---|---|---|
| PNG 图片 | 89 50 4E 47 | .PNG |
| GIF 图片 | 47 49 46 38 | GIF8 |
| ELF 可执行文件 | 7F 45 4C 46 | .ELF |
| PDF 文档 | 25 50 44 46 | |
| ZIP 压缩包 | 50 4B 03 04 | PK.. |
打开文件后直接看偏移量 0 那一行,对照上表就能判断文件实际类型。一个文件后缀是 .bin,但开头是 50 4B 03 04,那它其实是个 ZIP 压缩包,常见于一些固件包和安卓安装包的变体。这种判断在取证和固件分析里几乎每天都要做。魔数判断不需要任何工具链,HexEdit 打开就能看,这是最快的一条路径。
3.3 用查找功能定位关键字节序列
文件大了以后,靠肉眼翻页找字节不现实,要用查找功能。HexEdit 这类工具通常支持两种查找方式:直接填十六进制序列,或者填 ASCII 字符串。我的习惯是,只要目标内容可能包含非 ASCII 字符,一律用十六进制序列模式查找,避免编码带来的误判。
# 要搜索的十六进制序列示例:一条 x86 指令的字节码 E8 78 56 34 12把这个序列填进查找框,模式选“Hex”,结果会定位到文件里所有匹配的位置。这类序列常见于你要在二进制里定位某段代码或者某个结构体。查找的时候有个参数要注意:是否区分大小写对十六进制序列没有影响,因为 A-F 和 a-f 等价;但如果你用 ASCII 模式搜字符串,大小写匹配开关就很重要,默认通常是区分大小写,搜不到的时候先排查这个。
找一个无符号整数 0x12345678 也一样——在小端文件里,你要搜的字节序列是 78 56 34 12,不是 12 34 56 78。这个坑我在 2.3 里提过,在查找场景下尤其容易翻车。搜不到目标序列时,先倒过来试试另一个字节序,十有八九是这个问题。
3.4 编辑单字节与回写:改完怎么验证
定位到目标字节后,直接在十六进制列输入新值就能完成编辑。但改文件前,我强烈建议先复制一份原始文件,这个成本几乎为零,却能给你留条后路。修改完成后,用hexdump或cmp对比修改前后的内容,确认改动范围符合预期。
# 备份原始文件 cp firmware.bin firmware.bin.bak # 修改完成后,对比修改前后的差异 cmp -l firmware.bin.bak firmware.bin | head -20 # 如果只想快速看某一偏移位置的值 xxd -s 0x2C -l 16 firmware.bincmp -l会列出所有不同的字节位置和值,head -20防止改动点太多时刷屏;xxd -s 0x2C -l 16表示从偏移 0x2C 开始读 16 个字节。这两条命令组合起来,能精确确认你只改了该改的位置。注意cmp的输出是三列:偏移、原始值、新值,第三列才是你改完的结果。如果你发现自己改了 100 处而不是 1 处,说明 Hex 查找时的替换范围没设置对,赶紧恢复备份重来。
提示:HexEdit 的编辑发生在内存里,保存动作才是写盘。改完别急着关窗口,先确认文件确实已经回写,否则系统崩溃或者断电会丢掉全部修改。
4. 大文件与只读边界:HexEdit 的内存模型和选型对照
4.1 打开文件前先看大小:全量加载与分块处理的取舍
十六进制编辑器最大的一个限制,是打开大文件时的内存模型。HexEdit 这类工具面对几十 MB 的文件基本无压力,但文件涨到几百 MB 甚至 GB 级,情况就变了。这里要分清两种常见实现:全量加载和分块映射。
全量加载会把整个文件读进内存,好处是操作流畅、随机访问快,坏处是内存占用等于文件大小。你拿一个 2GB 的文件去开,机器内存不够就直接卡死。分块映射是另一种做法,只把需要看的部分读入内存,其他部分留在磁盘上,这样打开再大的文件也不容易崩,但随机跳转和查找的速度会慢一些。用 HexEdit 打开大文件前,先看一眼文件大小,跟机器内存对比一下再决定怎么开。
处理超大文件时,我的习惯是先查文件头部和尾部,确认整体结构没有异常,再决定要不要全量处理。很多场景下你只需要看某个偏移附近的内容,不需要把整个文件装进去。如果 HexEdit 打开文件时长时间无响应,多半是加载策略的问题,而不是文件坏了。判断方法很简单:任务管理器或者top里看内存占用,如果持续增长,那就在做全量加载,赶紧关掉。
4.2 只读模式什么时候开
排查问题、分析固件结构、取证时,我只查看不修改,这时候就开只读模式。只读模式的价值不只是防止手误,更重要的是让你养成“分析时不动数据”的习惯。一旦文件被误改,即使后面撤销,也可能因为操作链太长找不回来。
固件分析和取证场景尤其应该只读。设备固件里的任何字节变化都可能导致后面解析失败,你只是看一眼文件头,手滑按了一下键盘就写坏了,这种事情在工程现场并不少见。开只读模式是最便宜的后悔药。如果你只是要读取和分析文件,永远先试试能不能用只读模式完成;确认必须修改时,再切回读写模式并提前备份。
4.3 选型对照:HexEdit 和其他十六进制编辑器怎么选
十六进制编辑器不是只有 HexEdit 一家。现实中更常见的是 HxD(Windows 专用)、010 Editor(要付费)、wxHexEditor(同样跨平台)。它们各有侧重,选型的核心依据是平台和功能需求。
| 工具 | 跨平台 | 开源 | 大文件支持 | 脚本扩展 | 备注 |
|---|---|---|---|---|---|
| HexEdit | 是 | 是 | 一般到良好 | 弱 | 轻量,适合日常查看与简单修改 |
| HxD | 否(仅 Windows) | 否 | 优秀 | 弱 | 免费,Windows 下口碑好 |
| 010 Editor | 是 | 否 | 优秀 | 强(模板脚本) | 商业付费 |
| wxHexEditor | 是 | 是 | 优秀 | 弱 | 专为超大文件设计 |
如果你在 Windows 上用,HxD 的体验确实好,打开大文件快,查找也顺手。如果你的环境是 Linux 服务器,或者要在多平台间来回切,HexEdit 这种跨平台开源工具就省心——不用每台机器装不同软件,构建一次就能带着走。010 Editor 的模板脚本能自动解析复杂结构,但 License 费用摆在那,不是轻度用户的首选。我的经验是,日常查看和简单字节修改,HexEdit 够用;真要天天跟上百 MB 的二进制打交道,再考虑专门的工具链。
5. 避坑指南:二进制编辑最容易翻车的五个场景
5.1 改完文件打不开:字节数被删少了
现象:在 HexEdit 里删除了一段字节,保存后发现文件整体结构错乱,解析器直接报错,甚至文件完全打不开。
原因:这是个经典翻车点。删除字节时,如果只删了中间的长度,没有用相同数量的字节补位,那这个位置之后的全部内容都会向前移动,所有偏移全部错位。文件里各个字段的边界也就全乱了。二进制文件不是文本文件,删一个字节能让整个数据结构塌掉。
解决:删除操作前先确认目标长度。如果只需要“抹掉”一段数据,用 00 填充比直接删除安全得多。文件头结构固定、字段长度固定的场景,填充是首选。确需缩短文件长度,必须同步修改文件头里记录文件大小的字段,这种操作要严格按格式文档来,改完立即用解析器验证。
5.2 搜字符串搜不到:编码根本没有对齐
现象:在 HexEdit 里用 ASCII 模式搜一个字符串,比如搜 “HDR”,结果搜了半小时一个都匹配不上。
原因:很多二进制文件里的字符串不是 UTF-8 也不是 ASCII,而是 UTF-16。Windows 体系下的 PE 文件、很多设备的配置文件,字符串是每两个字节一个字符,英文的 A 存成 41 00。ASCII 模式搜 “HDR”,实际搜索目标是 48 44 52,而文件里存的是 48 00 44 00 52 00,当然搜不到。
解决:看清文件里字符串的实际编码。UTF-16LE 的话,搜十六进制序列 48 00 44 00 52 00。如果不确定编码,先定位一个已知字符串附近的字节,看两个字符字节之间是不是夹着 00,从而判断编码宽度。这个经验在处理固件字符串时几乎百发百中。
5.3 把 00 01 当 01 00:小端读反改错
现象:按文档说明修改一个 DWORD 字段,想把值改成 0x0001,于是把字节改成了 00 01,结果程序表现完全不对,数值变成了 256。
原因:文档里写的是逻辑值,磁盘上存的是原始字节序列。Intel 平台小端存储,0x0001 在文件里是 01 00。你按阅读顺序写入 00 01,实际解析出来就成了 256。字节序这个黑洞,改多字节字段时最容易踩。
解决:写多字节字段之前,先在文档里确认字节序。小端就是先写低字节,大端就是先写高字节。拿不准的时候,找文件里已知的正确字段对照一下,或者用 Python 跑一下struct.pack('<I', 1)看输出,确认字节排列再动手。
5.4 保存后文件变空白:直接编辑原文件惹的祸
现象:改完保存,再一打开文件变成 0 字节或者全是 00,原来的数据全没了,而且 HexEdit 里也撤销不回来。
原因:直接打开原文件编辑,保存过程出现异常(比如磁盘写入中断、文件被系统移走),原数据就毁了。更常见的是保存时 HexEdit 写入崩溃,文件被截断或覆盖。没做备份的情况下,没有任何后悔药。
解决:先复制一份再开始编辑,永远不要把 HexEdit 直接指向唯一的原始文件。我的习惯是工作目录里永远保留原始文件加 .bak 后缀,改的是副本。改完验证无误,再覆盖原文件。这步骤一分钟不到,但能救你一整天的活儿。
5.5 大文件卡死:拿小文件的心态开大文件
现象:打开一个 800MB 的 bin 文件,HexEdit 界面卡住,鼠标转圈,内存占用飙升,最后只能强杀进程。
原因:大文件默认全量加载到内存,机器物理内存不足时就开始换页,卡死是必然的。很多十六进制编辑器对超大文件没有自动切换分块模式的机制,或者切换条件非常隐蔽。
解决:打开大文件前,先用ls -lh看体积,超过物理内存三分之一就警惕。优先用只读模式打开,某些工具的只读模式会走内存映射。如果只查看局部内容,用dd切出一段再查看是更稳的路子。真需要全量编辑超大文件,换工具比硬撑更有效率。
6. 进阶:改完文件之后,怎么确定没改坏
改完一个二进制文件,最怕的不是改错一个字节,而是改错了却不知道。常用的格式解析器不会告诉你“这里字节被误改了”,它只在某个深层的字段校验失败时报错,你顺着报错去排查,可能发现是几小时前手滑改错了一个距离校验很远的位置。所以我现在改完文件,必做两件事:重新解析一次,以及做 hash 对比。
# 修改前记录原始哈希 sha256sum firmware.bin > firmware.bin.sha256 # 修改后对比哈希是否变化 sha256sum -c firmware.bin.sha256 # 如果文件较大,也可以只看差异字节数量 cmp -l firmware.bin firmware.bin.bak | wc -l第一段里,修改前把原始哈希记录到文件,改完后再用-c校验。如果校验失败,说明文件确实被改动过,这是预期的;如果没报差异而你确实改过内容,那才需要紧张。第二段里cmp -l的输出通过wc -l统计差异字节数,你可以快速知道这次改动的影响范围——改一个字节就应该是 1 行,多了就有猫腻。
更进一步,我会在改完后用对应格式的解析工具重新跑一遍。改的是 PNG,就用file命令再确认魔数和尺寸字段;改的是 ELF,就用readelf看结构是否还完整;改的是固件,就用厂商配套的烧录工具做一次校验。这一遍能拦住绝大多数“改错位置”的问题。
有一次我改一个设备固件的版本号,改完用 hexdump 看着是对的,结果刷进设备直接不启动。排查半天发现是版本号字段下面紧跟着一个校验和,改了版本号没同步改校验和,设备启动时校验失败直接拒绝加载。从那以后,我每次用 HexEdit 改完文件,都强制走一遍解析器验证加 hash 对比,确认改动符合预期才敢收工。希望帮到你。
本文还有配套的精品资源,点击获取