
上周帮同事抢修一台老设备的配置文件打开一看头 16 个字节全被写成了乱码整个文件直接拒绝加载。用 hexedit 跳回偏移 0对照正常文件的签名手工补了几个字节文件当场活过来。这事让我想起一个挺尴尬的现象很多人天天和文件、镜像、固件打交道却从来没认真用过十六进制编辑器遇到文件头坏了字符串写死了签名对不上这类问题就束手无策。hexedit 就是专门解决这类问题的小工具——一个在终端里跑、能打开比内存还大的文件、能直接改字节的十六进制编辑器。它适合后端工程师、嵌入式开发者、逆向初学者、做数据恢复的人也适合任何需要看文件最底层长什么样的人。下面我把这几年用它的完整经验摊开讲从界面布局到按键手感从五个真实场景到参数换算尽量让你看完就能直接上手干活。1. hexedit 到底解决什么问题先搞清楚它的定位1.1 十六进制编辑器存在的意义普通文本编辑器处理的是字符它会把文件按编码规则翻译成人能读的文字而十六进制编辑器处理的是字节它展示的是文件在磁盘上真实的每一个 8 位数据。这个区别看着小实际差得很远。一个文本文件里写着的123在磁盘上是三个字节31 32 33而一个二进制文件里的123可能是某个整数0x00000123的低位表示。当文件头、签名、长度字段、校验值被破坏时文本编辑器根本不知道该怎么办因为它连这些字节该不该显示成字符都不确定。十六进制编辑器要做的就是绕过所有解释层把原始字节铺开给你看同时允许你直接覆盖其中任意一个。这件事在三个场景下绕不过去一是文件格式损坏需要手工修复比如图片头、压缩包签名、数据库页头二是二进制程序里存在硬编码常量需要替换比如写死的 IP、端口、路径、版本号三是需要验证某个工具的输出到底对不对比如加密算法的中间结果、协议报文的内存布局。hexedit 在这类工具里的位置比较特殊。它不是功能最全的那个也不是界面最好看的那个但它是随手就能用、几乎到处都装得上、还能开超大文件的那个。很多时候你只是要改三个字节不想为一个临时需求去装一个几十兆的图形化工具这时候 hexedit 就是最优解。1.2 hexedit 的定位与同类工具对比选工具这件事很多人是靠习惯我建议按场景选。下面这张表是我自己整理的实际使用对照不是从文档抄的。工具交互方式打开大文件/设备适合的场景主要短板hexedit终端全屏交互支持分块读取临时改几个字节、看设备、远程服务器无图形界面按键需熟悉xxd / hexdump命令行只读支持快速查看、管道处理、脚本化不能交互编辑vim 的%!xxd复用 vim一般受内存限制顺手改一下已有 vim 环境容易在转换过程中出错ghex / bless图形界面受内存限制桌面环境下精细比对服务器上基本用不了商业十六进制编辑器图形界面支持模板解析、结构化编辑需要授权跨平台部署麻烦从这张表能看出来hexedit 的核心竞争力其实就两条分块读取带来的大文件能力以及终端环境下的可用性。你在 SSH 里连着一台没有图形界面的服务器需要改一块磁盘镜像或者一个几百兆的固件图形化工具全部出局剩下的选择并不多。还有一个细节值得说hexedit 的依赖非常干净它不依赖 ncurses终端控制那一套是自己实现的。这意味着它在精简的嵌入式 rootfs、裁剪过的容器镜像里也能跑起来交叉编译的麻烦程度也低。我见过有人在路由器固件里塞一个静态编译的 hexedit用来现场改配置分区这个用法确实很实用。2. 装好就能用安装、启动与界面布局拆解2.1 各发行版安装方式与版本差异安装本身没什么难度但有个坑必须先说清楚不同来源的 hexedit 不一定是同一个项目。你在包管理器里搜 hexedit可能会搜到好几个结果有的是 Pascal Rigaux 那一支有的是基于它改的衍生版本按键绑定和界面细节会有差别。常见的安装方式如下# Debian / Ubuntu 系 sudo apt update sudo apt install hexedit # RHEL / CentOS / Fedora 系 sudo dnf install hexedit # Arch 系官方仓库不一定收录可能要走 AUR # 安装前先确认包名和项目来源装完之后建议先做两件事。第一件是hexedit --help确认支持哪些命令行参数第二件是进去之后按F1把内置帮助翻一遍。这个习惯看着琐碎但我踩过坑——有一次在一台机器上按了半天CtrlS想保存结果那个版本的CtrlS是搜索键保存是另一个键白白浪费了十几分钟。以具体版本的内置帮助为准比记任何博客都靠谱。如果发行版仓库里的版本太老功能上有缺失也可以拿源码自己编译。它依赖很少标准的gcc加make基本就够了这也是我前面说的依赖干净带来的好处。2.2 三栏界面与地址、HEX、ASCII 的对应关系hexedit 的主界面是经典的三栏结构这个结构从 DOS 时代的PCTOOLS一直沿用到现在几乎所有十六进制编辑器都是这个样子。00000000 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 .PNG........IHDR 00000010 00 00 01 00 00 00 01 00 08 06 00 00 00 1F 15 C4 ................ 00000020 89 00 00 00 00 49 45 4E 44 AE 42 60 82 .....IEND.B.三栏分别是最左边是地址列。它表示的是文件偏移量不是行号。默认是 8 位十六进制也就是能表示到0xFFFFFFFF查看超过 4GB 的文件时地址列会自动变宽。很多人第一次用会把它当成行号然后在脑子里做乘法其实没必要光标的当前偏移在界面上基本都会显示。中间是 HEX 区。每个字节用两位十六进制表示一行通常排 16 个字节中间会做分组方便肉眼定位第几个字节。你在这里输入的就是十六进制数字。最右边是 ASCII 区。它把同样的 16 个字节按字符解释一遍不可打印的字节统一显示成点号。这一栏的作用是给你上下文让你能看出这段区域到底是代码、是字符串还是随机数据。理解这三栏的对应关系是后面所有操作的基础。举个例子你在 ASCII 区看到IHDR这四个字符那么它在 HEX 区的对应就是49 48 44 52在地址列的对应就是这几个字节所在的行。三栏其实描述的是同一段数据的三种视角光标移动时三栏会同步跟随。2.3 启动参数与常见打开姿势hexedit 的参数不多但每一个都有明确的用途值得单独过一遍。# 最普通的用法打开一个文件 hexedit /path/to/file.img # 以扇区模式打开适合直接操作磁盘或分区设备 hexedit -s /dev/sdX # 或 hexedit --sector /dev/sdX # 启动时最大化显示区域 hexedit -m /path/to/file # 查看帮助 hexedit --help关于-s需要多说两句。这个模式会把显示和访问的粒度按 512 字节的扇区来组织主要面向磁盘和分区设备。为什么需要它因为块设备对读写有对齐要求有些设备只接受扇区对齐的读写操作普通编辑器按字节随机访问的方式在这种设备上可能直接报错。用了-s之后它按扇区的节奏来读兼容性会好很多。还有一个特别容易被忽略的点打开设备文件要格外谨慎。用 hexedit 打开/dev/sdX看到的是那块盘的原始数据包括分区表和文件系统元数据改错一个字节可能就让整个分区认不出来了。我的习惯是凡是对设备类的对象动手先用dd把需要改的区域备份出来确认方案无误再操作。3. 按键与编辑模型先把操作手感摸清楚3.1 移动、跳转与三种寻址方式hexedit 用的是终端全屏交互所有操作都靠键盘。移动键位和常见的编辑器基本一致但有几个组合键很有用值得单独记住。方向键左右逐字节移动在 HEX 区和 ASCII 区都有效。方向键上下一次移动一行也就是 16 个字节。PageUp / PageDown翻页移动。Home / End跳到当前行的行首和行尾。CtrlHome / CtrlEnd直接跳到文件的起始和末尾。这里有个实操经验在文件里大范围移动不要靠方向键硬顶。一个几百兆的镜像你按着方向键走按到手抽筋也到不了目标位置。正确的做法是用搜索或者跳转功能直接定位到目标偏移这也是后面几节反复会用到的技巧。寻址这件事在十六进制编辑里有三种表达方式一定要能在脑子里自由换算十六进制偏移0x1A0。十进制偏移416。扇区号比如第 1 个扇区从 0 开始计数对应偏移 512。这三种表达在文档、工具输出、你自己的备注里会混着出现换算能力直接决定了你的效率。后面的第 5 节会专门讲换算方法。3.2 HEX 区与 ASCII 区的编辑差异Tab 键是 hexedit 里最重要的一个键它在 HEX 区和 ASCII 区之间切换编辑模式。这两个模式看着是在改同一段数据但输入方式完全不同。在HEX 区你输入的是十六进制数字。每按下一个合法的十六进制字符0-9、a-f它会填到当前字节的高四位或低四位上。比如光标停在某个字节上你依次按4、8这个字节就变成了0x48。这种输入方式非常适合精确改写已知数值因为你心里清楚目标字节应该是多少直接敲进去就行。在ASCII 区你输入的是字符工具会自动把它转成对应的字节写进去。比如你想把某个字符串里的abc改成xyz在 ASCII 区直接敲x、y、z三个键就行不用自己查 ASCII 表。这种输入方式适合改字符串常量、路径、版本号这类人类可读的内容。除了覆盖式的输入hexedit 还支持删除和插入操作也就是说它可以改变文件的长度。这是个很强的能力但也意味着风险。对块设备做插入或删除基本是没有意义的因为设备的长度是固定的插入字节会破坏后面的所有结构。修改文件长度之前一定要先想清楚目标文件格式是否允许长度变化。比如一个 PNG 文件你在中间插入一个字节后面所有的 chunk 都会错位文件直接废掉但如果你只是覆盖某个字节文件结构不受影响。3.3 搜索、撤销与保存退出搜索是 hexedit 里最常用的功能之一。它通常支持两种搜索方式按十六进制串搜索和按 ASCII 字符串搜索。你要找PNG这个签名可以搜 ASCII 的PNG也可以搜 HEX 的50 4E 47两种写法都能命中。搜索的起点是当前光标位置方向默认向后。如果要找的位置在当前光标之前记得先用CtrlHome跳回文件开头再搜。这个细节很关键我在第一次用的时候就吃过亏——明明文件里存在那个字符串就是搜不到原因是光标停在了字符串后面。另一个必须知道的功能是撤销。hexedit 的修改策略是改动先在内存里标记保存时才落盘。它支持把当前的修改全部撤销对应的按键通常标为 undo all changes。这个功能在两种情况下能救命一是你输入了一半发现位置搞错了二是在保存之前意识到整个思路不对。不过要注意撤销针对的是未保存的修改一旦保存落盘就得靠备份恢复了。保存和退出的关系也要理清楚保存把内存里的修改写回文件。保存并退出一步到位。直接退出如果文件有未保存的修改一般会给出提示让你选择是否保存。不要习惯性地一路确认那个提示是在帮你。养成一个习惯改动之前先cp一份备份。这不是多余的步骤而是在你手抖改错一位之后唯一能让你睡个好觉的东西。备份文件放在和原文件不同的目录或者干脆加上时间戳防止自己覆盖。4. 五个真实场景的完整实操4.1 场景一手工修复被破坏的文件头这是十六进制编辑器最经典的用法。文件头是格式识别的依据很多程序在加载文件时会先校验开头几个字节一旦对不上就直接拒绝打开哪怕后面的数据都是完好的。以 PNG 为例它的文件头签名是固定的 8 个字节89 50 4E 47 0D 0A 1A 0A拆开看50 4E 47就是 ASCII 的PNG前后的字节各有用途其中那几个特殊值是为了防止文件被当作纯文本传输时被误处理属于格式设计里很巧妙的一手。修复步骤用 hexedit 打开损坏的文件。CtrlHome跳到文件开头确保光标在偏移 0。按Tab切到 HEX 区如果当前不在的话。依次输入89、50、4E、47、0D、0A、1A、0A。保存退出然后用文件识别工具或者图片查看器验证一下。修好文件头之后如果文件还是打不开问题可能不止这一处。这时候要接着检查紧随其后的数据块。PNG 的第一个数据块是 IHDR它的结构是4 字节长度 4 字节类型 13 字节数据 4 字节校验其中长度字段应该是00 00 00 0D也就是 13类型字段是49 48 44 52。如果这几个字节对不上说明文件被破坏的范围比想象中大。注意修改文件头之前务必确认你手上的正确版本是真的正确。我见过有人拿一个同样损坏的样本去对照结果把一个好文件也改坏了。找参照样本时优先用同类工具刚刚生成的文件或者格式规范里明确给出的固定值。4.2 场景二定位并替换二进制里的字符串常量这个场景在排查问题和做适配时特别常见程序里某个地址、端口、路径是编译期写死的现在要改成新的值但源码不在手边。这时候十六进制编辑器就是最快的办法。第一步是定位。不要凭感觉在文件里翻用strings配合偏移输出几秒钟就能找到候选位置# -a 表示扫描整个文件-t x 表示以十六进制输出偏移 strings -a -t x ./app | grep -i 192.168输出大概长这样4a1c0 192.168.1.100 4a280 http://192.168.1.100:8080/api后面的十六进制数字就是偏移。拿这个偏移去 hexedit 里跳转定位就能直接看到那段字符串的真实字节。第二步是判断能不能直接替换。这里有个铁律新字符串的长度不能超过原字符串否则会覆盖后面的数据。如果新值比原值短用\0补位也就是在 ASCII 区删掉多余字符或者用 HEX 区把多余字节填成00。如果新值比原值长那就只能放弃这种直接替换的做法得从更上层去解决。举个例子把192.168.1.100改成10.0.0.5。原值 13 个字符新值 8 个字符短了 5 个字节。正确做法是把前 8 个字节替换成10.0.0.5后面 5 个字节全部填00。如果周围本来就是00填充那更省事。还有一种做法是用dd完成同样的替换适合需要脚本化的场合# 在偏移 0x4a1c0 处写入新字符串并把后面的字节清零 printf 10.0.0.5\x00\x00\x00\x00\x00 | dd of./app bs1 seek$((0x4a1c0)) convnotruncconvnotrunc这个参数不能省否则dd会截断文件后果很严重。4.3 场景三磁盘镜像与引导扇区的签名核对处理磁盘镜像时-s模式用起来会舒服很多。原因前面提过按扇区访问更贴合设备的读写模型而且地址换算也会直观不少。以最常见的情况为例磁盘的第一个扇区MBR最后两个字节应该是55 AA这是引导扇区有效性的标志。如果这个标志丢了有些工具会认为这块盘没有有效的分区表。# 用扇区模式打开镜像 hexedit -s ./disk.img打开之后跳转到偏移 510对应的就是第 0 个扇区的倒数第二个字节。如果那里不是55 AA就可以手工补上。这里涉及一个偏移换算值得把过程写清楚第 0 个扇区的地址范围是偏移 0 到 511最后两个字节自然就是 510 和 511。再比如要检查第一个分区的内容分区表里记录的第一个分区的起始 LBA 假设是 2048那么它对应的偏移就是2048 × 512 1048576 0x100000这个换算在磁盘这块是每天都在用的务必熟。为了省事我习惯用 shell 直接算# 扇区号转偏移 echo $((2048 * 512)) # 十六进制输出 printf 0x%X\n $((2048 * 512))注意对真实的块设备做修改风险等级和改普通文件完全不同。一旦破坏了分区表或者文件系统超级块整个分区的数据可能都读不出来。动手之前先把设备的前几兆内容dd到文件里备份确认没问题再操作。4.4 场景四给可执行文件或固件打补丁这个场景主要出现在调试和逆向分析里。手边没有源码、也没法重新编译但需要验证某个逻辑分支的作用这时候直接在二进制上动手是最快的。最典型的一种操作是把条件跳转改成无条件跳转。以常见的 x86 指令为例74 xx是相等则跳转75 xx是不等则跳转EB xx是无条件跳转。如果你想把某个条件判断短路掉把第一个字节改成EB就行后面的偏移量保持不变。具体步骤先确定要改的指令在文件里的偏移。这一步通常要靠反汇编工具。用 hexedit 打开文件跳转到该偏移。在 HEX 区把目标字节改掉。保存退出跑一遍验证。另一种常见操作是填充空指令。如果你想让某条指令失效但又不改变文件长度就用空指令覆盖它。不同架构的空指令不一样x86 上单字节的90就是标准的 NOPARM 上则是一条完整的 32 位指令小端存储时字节序列是00 00 A0 E1。这里要注意字节序的问题。同一个 32 位数值在文件里的排列顺序可能和小端、大端有关搞错了就会把数据改成完全不同的东西。判断方法在第 5 节会详细讲。提示给可执行文件打补丁之前先记下原始字节的数值。这样一来就算改错了也能手工改回去不用重新找原始文件。4.5 场景五和 dd、xxd、cmp 组合使用hexedit 是交互式工具不适合批量和脚本化的场合。真正高效的用法是让它和命令行工具配合各干各擅长的事情。看局部用 xxd# 看偏移 0x100 开始的 64 个字节 xxd -s 0x100 -l 64 ./firmware.bin这个命令不进入交互界面输出直接进终端适合快速确认某个位置的内容。比对两个文件的差异用 cmp# -l 输出每个差异字节的偏移八进制和两侧的值 cmp -l ./a.bin ./b.bin | head -20拿到差异偏移之后再用 hexedit 打开确认上下文判断哪个是正常的。这个流程我用了很多次尤其是在确认固件刷写是否成功的时候。精确写入用 ddprintf \x89\x50\x4E\x47\x0D\x0A\x1A\x0A | dd of./broken.png bs1 seek0 convnotrunc这条命令等价于在 hexedit 里跳到偏移 0 手工敲 8 个字节但速度快得多也适合写进脚本。提取一段数据也用 dddd if./disk.img of./header.bin bs512 count1这条命令把镜像的第一个扇区抠出来方便单独分析。分析清楚之后再决定怎么处理比直接在原文件上乱改安全得多。把这四个工具串起来的工作流大概是用xxd快速定位用cmp找差异用hexedit做精细修改并检查上下文用dd做批量或脚本化的操作。分工明确效率比只用其中一个高出一大截。5. 参数换算与进阶技巧5.1 偏移量的三种表达与相互换算十六进制编辑里最容易出错的地方不是操作而是换算。同一个位置可能有三种不同的写法出现在你面前脑子里必须能立刻转换。表达方式示例常见出处换算方法十六进制偏移0x1A0反汇编器、调试器基准形式十进制偏移416部分脚本输出0x1A0 416扇区号第 1 个扇区分区表、磁盘工具偏移 ÷ 512反向换算同样重要。拿到一个扇区号要算偏移直接乘 512拿到一个偏移要算扇区号直接整除 512。心里记几个常用值会快很多1 KB 0x4004 KB 0x10001 MB 0x1000001 个扇区 0x2002048 扇区 0x100000这几个数字建议直接背下来因为它们出现的频率实在太高了。我在排查问题时看到0x100000基本能立刻反应过来这是 1MB看到 2048 就知道是常见分区起始位置。5.2 判断字节序并正确解读多字节数值字节序是另一个高频出错点。同一个 32 位整数0x12345678在不同字节序下文件里的排列完全相反字节序文件中的字节序列常见平台小端78 56 34 12x86、ARM默认大端12 34 56 78网络协议、部分嵌入式架构判断方法很实用找到一个你已知确切数值的字段看它在文件里怎么排。比如某个文件格式规定长度字段是 4 字节大端你看到00 00 00 0D立刻就能确认这是大端值就是 13。反过来如果看到0D 00 00 00那就是小端。还有一个更省事的办法用工具读。用xxd加上合适的参数或者干脆用od按 16 位、32 位分组输出能直接看出数值# 按 32 位十六进制分组注意这里展示的是本机字节序 od -A x -t x4 ./data.bin | head网络协议相关的文件基本都是大端这是历史决定的本地可执行文件和内存 dump 基本是小端跟着 CPU 走。记住这两个规律大部分情况都能猜对再用上面的方法验证。5.3 用外部工具交叉验证修改结果改完字节不等于是改对了。我在早期经常犯一个错误改完之后直接拿去用结果程序报的错和之前完全一样排除了半天才发现是改错了位置。正确的流程是改完之后立刻用另一种方式验证。常用的验证手段有这么几个# 1. 用 xxd 查看目标区域确认字节确实变了 xxd -s 0x4a1c0 -l 32 ./app # 2. 用 strings 确认字符串内容 strings -a -t x ./app | grep -i 10.0.0.5 # 3. 用 cmp 确认只有预期的位置发生了变化 cmp -l ./app.bak ./app # 4. 用专用的校验工具验证文件完整性 # 比如图片用 identify、压缩包用 unzip -t第 3 条特别有价值。如果你只打算改一个字节cmp应该只输出一行差异如果输出了十几行说明中间出了别的问题得回头检查。这个习惯帮我抓出过好几次手抖多改了一位的低级错误。6. 常见问题与避坑速查6.1 保存失败与权限问题最常见的一种情况是改完按保存工具提示写不进去。原因通常是文件权限不够或者文件被别的进程占用了。排查顺序确认当前用户对文件有写权限必要时用sudo重新打开。确认文件所在的文件系统没有挂载成只读。确认目标不是块设备或者需要特殊权限的设备节点。确认文件没有被其他进程以独占方式打开。还有一种情况是文件本身是符号链接你改的其实是链接指向的目标这个不算错误但要心里有数。如果希望改链接本身得用别的方式处理。6.2 终端显示乱码与按键失灵hexedit 是终端程序它对终端类型的依赖比较强。如果你通过某些特殊方式登录终端类型识别不对就可能出现界面花屏、按键没反应、颜色错乱这些现象。对付这类问题的通用手段有这么几个先按重绘键刷新一下屏幕很多时候只是显示没跟上。检查TERM环境变量的值设置成常见的xterm-256color通常能解决大部分问题。如果界面被中断程序打乱了退出重进是最干脆的办法。有些组合键会被终端本身或者窗口管理器拦截遇到这种情况换个键位或者换一种实现方式。6.3 误操作之后的补救步骤真改错了处理的优先级是这样的如果有备份直接用备份恢复这是最快的路径代价最小。如果没备份但还没保存用撤销功能把内存里的修改全部回退。如果已经保存且没有备份看看有没有别的副本比如应用的缓存、同步目录的历史版本、文件系统快照。如果副本也没有靠记忆或者同类文件反推把改动逐字节改回去。这是最麻烦的情况也是为什么我反复强调备份。顺便说一个容易被忽略的点编辑设备文件之前更要备份。dd出来的几兆数据在关键时候比什么都管用。6.4 问题速查表现象可能原因排查方向保存提示失败权限不足、文件系统只读检查权限和挂载状态搜索不到明明存在的内容光标位置在目标之后跳回文件开头再搜界面花屏、按键无响应终端类型不匹配检查TERM变量重绘屏幕改完之后程序行为没变化改错位置、有缓存、有校验用xxd和cmp交叉验证文件长度变了导致打不开误触了插入或删除用备份恢复注意编辑模式多字节数值读出来不对字节序判断错误找一个已知字段验证字节序打开大文件卡顿一次性加载的预期错误确认工具是否分块读取避免全量搜索7. 我踩过的坑和几条实操心得第一条心得改之前先算清楚目标位置。我早期的习惯是打开文件就开始翻凭眼睛找目标效率很低还容易看错行。后来改成先在命令行用strings、xxd、grep把偏移确定下来再进 hexedit 直接跳过去同样的事情耗时能压缩到原来的三分之一。第二条心得改动的字节数要严格控制。十六进制编辑是就地修改多敲一个字符就可能把后面的数据顶掉。我现在的习惯是每次动手前在心里默数一遍目标字节数改完立刻用cmp确认差异行数对得上才继续下一步。第三条心得不要迷信看起来对。一个文件的某个字段看起来应该是某个值不代表它真的应该是那个值。格式规范、同类样本、运行时行为这三样至少要对照一个才有资格下结论。我见过有人凭感觉改文件头结果把一个能恢复的文件彻底弄坏了。第四条心得备份的粒度要跟着风险走。改一个普通文本文件cp一份就够改磁盘镜像至少把涉及的区域整段抠出来改动块设备尽量让上层有快照或者镜像可用。备份的成本是一分钟恢复的成本可能是几个小时。最后分享一个小技巧如果你需要反复检查同一批文件的相同位置与其每次都进 hexedit不如写个一行的 shell 把它变成可重复的命令for f in ./samples/*.bin; do printf %s: $f xxd -s 0x0 -l 8 $f | head -1 done一次跑完输出排成一列谁的文件头不对一眼就能看出来然后再用 hexedit 逐个处理。这种机器扫一遍、人只处理异常的节奏比从头到尾手工核对要稳得多也更不容易漏。