花拾录
← 返回知识库

二进制里扫出 474 处 AAAA,其实是 base64 图片数据的噪声

软件工程 / 工具导入2026/09/220 阅读0 评论

你在分析一份二进制文件(固件、可执行文件、归档包),写了个脚本扫描里面的特征字节串。跑完出来的结果让你心跳加速:某个模式出现了 474 次。数字这么整齐、次数这么多,看着像个重大发现。但冷静下来一看,全是假的。

现象

  • 脚本在二进制里扫出大量重复的短字节串,比如 AAAA 出现 474 次;
  • 也可能是一段有规律的模板片段,反复出现几百次;
  • 数量之整齐、之巨大,第一眼像是"发现了某种魔数"或者"找到了一个反复出现的结构";
  • 但拿其中几处去人工核对,发现上下文完全对不上,根本不是什么结构标记。

根因

根因是:你扫到的不是二进制结构,而是 base64 编码的媒体数据。

关键在于 base64 的编码方式。base64 用 64 个字符(A–Z、a–z、0–9、+、/)来表示任意二进制数据,每 3 个字节编码成 4 个字符。这就带来一个特点:连续的零字节会被编码成连续的 A。

举几个具体的例子:

  • 三个零字节 00 00 00 → base64 是 AAAA;
  • 一段较长的零填充区,编码出来就是很长的一串 A;
  • 而图片、字体、图标这类资源经常大段填充零(对齐填充、透明像素等),base64 之后就成了满屏的 AAAA...。

更直接的证据:PNG 文件的魔数是 89 50 4E 47 0D 0A 1A 0A,把它 base64 编码后,开头正是 iVBORw0KGgo 这一类固定前缀——而一段 PNG 数据块中间大量出现的 AAAAABJRU 之类的串,就是那些固定字节序列的 base64 形态。你扫到的 AAAA,大概率就是这么来的。

所以结论很清楚:这些是编码数据里的巧合重复,不是结构信号。

解决

扫二进制特征时,要有意识地排除编码/媒体数据的干扰:

1. 先建立"已知噪声"清单,扫之前就排除
   - base64 特征:连续的 A/Z、结尾的 = 填充、base64 字母表里高位为 0 的模式
   - 压缩数据:zlib/gzip 流(往往带着固定的头字节)
   - 资源区:图片、字体、图标所在的段

2. 对命中的位置做上下文检查
   - 打印命中点前后几十个字节
   - 如果前后是明显的 base64 字符表内容(全是 [A-Za-z0-9+/])→ 大概率是编码数据
   - 如果前后是零填充、或者能识别出图片/资源的头 → 排除

3. 用"结构性证据"而不是"出现次数"来确认发现
   - 真的结构标记通常伴随着长度字段、类型字段、偏移字段
   - 单纯的高频重复,几乎总能在编码数据里找到解释

一个更根本的做法:扫描前先"还原"数据。 如果怀疑某段是 base64,就把它解码出来再看内容;如果怀疑是压缩流,就先解压。在解码/解压之后的明文里再扫特征,误报会少得多——因为那时你面对的是真实的结构,而不是它的编码形态。

延伸与预防

这条坑的通用教训是:高频重复的字节串,先怀疑是编码数据而不是结构。

这是一个更一般的思维习惯:"数量惊人"本身不是证据,它更可能是"你没意识到数据被编码过"。

  • 锚定在结构性证据上。 真正有意义的发现,通常能讲出"它为什么在这里"——它跟哪些字段相邻、它的长度字段是否自洽、它出现在哪个段里。只有"出现了 N 次"这一个事实,撑不起任何结论。
  • 先问"这段数据是什么形态"。 任何二进制分析,第一件事都应该是"这段是什么":可执行代码、压缩数据、base64 编码的文本、还是结构化资源?搞清形态再谈特征,比一头扎进字节匹配有效得多。
  • 注意编码的副作用。 base64 会把三个字节摊成四个字符,于是"重复的字节"变成"重复的字符";反过来,压缩会把高频模式压掉、低频模式放大,还会引入新的重复。凡是对"编码/压缩后的数据"做统计,得到的结果都要打一个折扣——你统计的对象不是原始数据。
  • 可疑的"重大发现",先做一次人工核对。 从命中的几百处里随便抽三五处,打印上下文看一眼。如果抽出来的都和结论对不上,那就是方向错了。这个动作花不了一分钟,却能挡住最常见的"数量错觉"。

评论(0)

  • 还没有评论,来抢沙发~

相关文章