二进制文件可视化
摘要
本文描述了在 'bine' 十六进制编辑器中增强的二进制文件可视化功能的开发,包括使用 Unicode 字符的彩色输出和一种将二进制文件解释为图像以进行大规模查看的方法。
暂无内容
查看缓存全文
缓存时间: 2026/08/25 16:57
# 可视化二进制文件
来源:https://movq.de/blog/postings/2026-08-05/0/POSTING-en.html
博客 (https://movq.de/blog/)-代码 (https://movq.de/git/)-桌面 (https://movq.de/desktop/)-联系 (https://movq.de/contact.html)
---
2026\-08\-05
这是我的十六进制编辑器`bine` (https://movq.de/blog/postings/2026-05-29/0/POSTING-en.html):
bine1.png: 截图:一个使用蓝灰配色的控制台应用程序,左侧是十六进制值,右侧是ASCII值的传统十六进制视图。(https://movq.de/blog/postings/2026-08-05/0/bine1.png)
基本上是全黑白的。前阵子,Vim的`xxd`增加了彩色输出功能(我使用的Vim Classic (https://vim-classic.org/) 不包含此功能):
xxd.png: 截图:'xxd'显示与'bine'相同的二进制文件,但ASCII值为绿色,NUL字节为白色,'0xFF'为蓝色,某些特殊字节(如换行符)为黄色,其余为红色。(https://movq.de/blog/postings/2026-08-05/0/xxd.png)
我想在`bine`中也加入这个功能,于是开始实现。早期的草稿如下:
bine2.png: 截图:'bine'添加了部分颜色:ASCII值带有蓝色背景。(https://movq.de/blog/postings/2026-08-05/0/bine2.png)
我认为这已经有所改进,因为更容易识别大部分是ASCII文本的区域。但这还不够理想。需要更多颜色,而且如果十六进制列紧挨在一起,而不是用空格隔开,效果可能会更好。
我的TUI框架`movwin`底层使用了ncurses(这是有意为之,因为我看重ncurses的特性稳定性)。框架本身用Python编写,ncurses则是一个C库。我已经注意到从Python调用ncurses可能开销很大(不知道这是否是普遍问题,还是仅仅发生在Python + ncurses组合上,或者仅仅是ncurses本身的问题,这无关紧要)。
没有颜色时,`bine`使用一次curses调用写入*整行十六进制内容*。有了颜色,就得*每行多次调用*。那开销太大了。
而且框架本身也不太适合以*快速*方式使用大量不同颜色。它有一个分层的调色板系统,所有这些都有成本。并且我必须维护至少两个版本的调色板,因为`movwin`默认支持深色和浅色主题。
最终,我想出了这个办法:
bine3.png: 截图:'bine',同样的文件,ASCII视图现在使用Unicode框线符中的'实心块'来表示某些字符。(https://movq.de/blog/postings/2026-08-05/0/bine3.png)
`bine`没有对十六进制列进行着色,而是使用了ASCII列中的特殊字符——这些字符通常不会出现在那里,因此没有冲突。NUL字节使用U\+2593 (`▓`),范围在`0x20 <= byte <= 0x7E`之外的字节使用U\+2591 (`░`),其余的是可打印ASCII字符,原样显示。
这虽然不能覆盖`xxd`的所有情况,但已经足够好了。你可以快速概览哪些是"纯文本",哪些不是,NUL字节很突出。
实现起来超级简单,运行时开销也小。
我还想为整个大文件提供类似的可视化功能。`bine`中微小的ASCII窗格只能显示有限内容。我想针对几兆字节,甚至可能几吉字节大小的文件实现这个功能。
我的可视化本质上是一张图像。那么……为什么不强制计算机将现有的二进制文件解释为图像?不做任何处理,只需将`0x00`到`0xFF`范围内的所有字节映射为像素。
便携式灰度图 (https://en.wikipedia.org/wiki/Netpbm#PGM_example) (Portable Graymap) 几乎就是这么做的。维基百科的例子展示了这种格式的ASCII版本,但也有二进制版本。
所以我需要做的基本上就是这样:
``
printf 'P5\n%s %s 255\n' "$width" "$height"
cat "$infile"
``
完成了。
我唯一实现的"逻辑"就是确定合适的宽度和高度。
生成的结果可以在任何图像查看器中显示(在Linux和BSD上)。
这是GORILLAS.BAS (https://en.wikipedia.org/wiki/Gorillas_(video_game)) EXE文件的可视化,未缩放:
gorilla.png: 'GORILLA.EXE'的可视化。(https://movq.de/blog/postings/2026-08-05/0/gorilla.png)
(是的,这就是整个游戏。你甚至可以将这张图转换回EXE文件。)
我们能看到什么?让我标注几个有趣的区域:
gorilla-annotated.png (https://movq.de/blog/postings/2026-08-05/0/gorilla-annotated.png)
1. 顶部是一个近乎"随机"的区域。非常暗的像素、非常亮的像素、灰色像素,应有尽有。这是*代码*。
2. 靠近中间,有一个非常规则的模式。我还没弄清楚那是什么,留待日后探索。(看起来有点像重定位表,但位置不对。不过这个文件是EXEPACK (https://moddingwiki.shikadi.net/wiki/Microsoft_EXEPACK) 文件,情况更复杂。走着瞧吧。)
3. 在末尾,有一段较长的"深灰色"区域。它相对均匀。这是*ASCII文本*:最高位从未设置,因此所有这些值都明显小于代码字节。(程序文件末尾通常有这样一个部分,存储字符串字面量。)
我认为很棒的一点是*完全没有任何预处理*。这一切只是利用了数据本身的特性。
作为一个更"直观"的例子,这里是一个包含两个文件(一个文本文件和一个图像)的tar包:
tarball.png: tar包的可视化。上半部分是较深的灰色,表示ASCII文本。下半部分对比度更高,有更多接近黑白色的像素,因此是某种'二进制'数据。(https://movq.de/blog/postings/2026-08-05/0/tarball.png)
另外,注意到文本区域的"图案"了吗?看起来像铺贴的墙纸?那是因为文本是重复的。
再看几个例子。这是ruff (https://docs.astral.sh/ruff/) 的缩小可视化:
ruff.png: 'ruff'的可视化,不同的灰度表示不同的数据类型。见下文解释。(https://movq.de/blog/postings/2026-08-05/0/ruff.png)
顶部黑色条带(主要包含NUL字节)的未缩放截取:
ruff-zoom.png (https://movq.de/blog/postings/2026-08-05/0/ruff-zoom.png)
大量整齐对齐的数据和表格。
`ruff`二进制文件大小为25 MB,生成的PGM文件(4096x6225像素)也是25 MB,所以我将其缩小了,因为我不想让这么大的文件永远留在博客里。但GIMP (https://gimp.org/) 和nsxiv (https://codeberg.org/nsxiv/nsxiv) 可以轻松处理PGM文件,完全没有性能或可用性问题。
这是一个690 MB `.iso`文件的可视化(当然经过了大幅缩小):
cd.png (https://movq.de/blog/postings/2026-08-05/0/cd.png)
创建PGM文件需要0.2秒,使用ImageMagick调整图像大小需要6秒。这显示了此方法的局限性:我尝试处理一个4 GB的文件,但ImageMagick需要太多内存。理论上,我认为可以通过先迭代调整图像大小(每次只将几行数据放入内存)然后压缩较小版本来解决。我还没写出这样的工具,而且ImageMagick似乎没有实现这个功能(或者我不知道怎么用——不过我还没搜过)。
尽管如此,根据我要找的数据类型,这已经是一个有用的工具了。我很少需要检查吉字节范围的大文件——如果需要,我可以轻松将其分成更小的部分。作为一个演示,这里是一个旧的8 GB磁盘映像:
8gbdisk-part00-small.png.webp (https://movq.de/blog/postings/2026-08-05/0/8gbdisk-part00-small.png.webp)8gbdisk-part01-small.png.webp (https://movq.de/blog/postings/2026-08-05/0/8gbdisk-part01-small.png.webp)8gbdisk-part02-small.png.webp (https://movq.de/blog/postings/2026-08-05/0/8gbdisk-part02-small.png.webp)8gbdisk-part03-small.png.webp (https://movq.de/blog/postings/2026-08-05/0/8gbdisk-part03-small.png.webp)8gbdisk-part04-small.png.webp (https://movq.de/blog/postings/2026-08-05/0/8gbdisk-part04-small.png.webp)8gbdisk-part05-small.png.webp (https://movq.de/blog/postings/2026-08-05/0/8gbdisk-part05-small.png.webp)8gbdisk-part06-small.png.webp (https://movq.de/blog/postings/2026-08-05/0/8gbdisk-part06-small.png.webp)8gbdisk-part07-small.png.webp (https://movq.de/blog/postings/2026-08-05/0/8gbdisk-part07-small.png.webp)8gbdisk-part08-small.png.webp (https://movq.de/blog/postings/2026-08-05/0/8gbdisk-part08-small.png.webp)8gbdisk-part09-small.png.webp (https://movq.de/blog/postings/2026-08-05/0/8gbdisk-part09-small.png.webp)8gbdisk-part10-small.png.webp (https://movq.de/blog/postings/2026-08-05/0/8gbdisk-part10-small.png.webp)8gbdisk-part11-small.png.webp (https://movq.de/blog/postings/2026-08-05/0/8gbdisk-part11-small.png.webp)8gbdisk-part12-small.png.webp (https://movq.de/blog/postings/2026-08-05/0/8gbdisk-part12-small.png.webp)8gbdisk-part13-small.png.webp (https://movq.de/blog/postings/2026-08-05/0/8gbdisk-part13-small.png.webp)
看起来还算有趣,但正如我所说,根据我要找的内容,它可能很有帮助。
我想我会保持现状。
相似文章
二进制文件的视觉分析
本文探讨用于视觉分析二进制文件的方法,这有助于逆向工程和网络安全等任务。
你的十六进制编辑器应该给字节上色
一篇博客文章主张,十六进制编辑器应为字节着色,以便让二进制数据中的模式更易被察觉和分析。
如何告知Windows我正在写入二进制文件?
本文解释了Windows在操作系统层面并没有内置二进制与文本模式的概念;这种区别是由运行时库(如C运行时)处理的。它澄清了Windows将所有文件视为字节,内容转换必须手动执行或通过库来完成。
字节码虚拟机在意外场景中的应用 (2024)
本文探讨了字节码虚拟机的出人意料的应用,特别是Linux内核中的eBPF以及编译后二进制文件中用于调试信息的DWARF表达式。
@charliermarsh: uv 二进制大小随时间变化
Charlie Marsh 分享了一张图表,展示了 Python 包管理器 uv 的二进制文件大小随时间的变化。