跳转至

8.2 文件与目录——二进制文件分析

内容梗概

本节课以 BMP 图片为例,讲解如何分析一个二进制文件的格式。老师先说明了坚持训练二进制分析能力的原因(对应计算机/信息安全专业中"二进制安全"方向),随后详细拆解了 BMP 文件的三大组成部分:14 字节的文件头、40 字节的信息头和像素数据,并引入"魔术数字(magic number)"概念及其在安全分析中识别伪装文件的应用。课上还演示了用 VS Code 的 Hexdump 插件查看二进制文件,并现场编写 Python 程序、以纯手动方式(read + 字节倒序 + int 转换)解析 BMP 文件头,为下一节引入 struct 标准库做铺垫。

知识点详解

为什么执着于分析二进制(约 01:27 - 02:40)

  • 计算机/信息安全专业有一个大方向叫**二进制安全**(系统安全、软件安全均属此范畴)。
  • 能按格式、按数值把二进制文件的内容读出来并深入分析,是走这个方向必备的能力;提前练熟,后续专业课上手方便,还能直接用 Python 介入专业课操作。

用二进制方式打开文件(约 00:00 - 00:30)

  • open(filename, mode) 中 mode 加字母 b(Binary)即以二进制方式读取/写入,如 'rb'。

BMP 文件格式总览(约 02:40 - 06:30)

  • BMP 格式很简单,包含三个大部分:
  • 文件头:14 字节;
  • 信息头:包含图像格式信息,一般 40 字节;
  • 像素数据:上节课已分析过,大部分情况下每 3 个字节为一组表示一个像素。
  • 分析二进制数据的软件通常一行显示 16 字节(或 32 字节):偏移量 00 开始,第二行偏移为 10(十六进制的 10 = 十进制 16)。上学期的 WinHex 和本节课的 VS Code 插件都是这个模式。

文件头各字段(约 06:30 - 11:30)

  • 表格中偏移值后的 H 是类似 C 语言的记法,表示前面的字符是十六进制。
  • 偏移 0,2 字节:魔术数字 magic number,内容为 BM(十六进制 0x42、0x4D),是 bitmap(位图)的首字母,表示这是一个 BMP 文件。
  • magic number 指程序中"作者不解释就不知道什么意思"的魔数;BM 就是一种文件特征魔数。
  • 安全应用(约 08:33):安全分析人员不会凭文件后缀判断类型——勒索软件常把 exe 伪装成图片。正确做法是读文件开头的特征字节:号称 BMP 但开头不是 BM 而是 MZ(exe 的特征),就是冒牌货。这与本次作业直接相关。
  • 接下来 4 字节:整个 BMP 文件的大小。
  • 再 2 字节 + 2 字节:保留字段,暂时用不上。
  • 再 4 字节:位图数据(像素数据)开始的偏移,通常是 54(14 + 40)。
  • 信息头前 4 字节是信息头自身长度(一般 40),随后 4 字节图片宽度、4 字节图片高度等,课上未逐一展开。

用 VS Code Hexdump 插件查看二进制(约 12:00 - 15:45)

  • VS Code 直接打开二进制文件会提示"二进制数据无法打开",需在扩展中安装 Hexdump 插件(安装后无需重启)。
  • 对准文件标签页右键 → Show Hexdump,即可看到十六进制 dump 视图:
  • 左侧 offset 列显示行首偏移,上方显示列号,可定位任意字节的偏移(如第 8 行的 0x8B);
  • 中间是十六进制数据,右侧是对应的 ASCII 字符——可打印字符直接显示(如 0x42 → B),不可打印的显示为小点,逻辑与 8.1 节 bytes 字面值一致。

实读 BMP 文件验证(约 15:46 - 18:30)

  • 小端存储:低位字节先存,读多字节数值时要"倒过来"理解(上学期已讲过)。
  • 跳过 BM 两个字节,框取随后 4 字节读得文件大小 0001D4F6,用程序员计算器换算为十进制 120054,与文件右键属性中的大小完全一致。
  • 位图数据偏移字段为 0x36 = 54,即第三行第六列开始是像素数据;开头三字节 FF FF FF 表示白色(图片左下角是白色),全部对上。

手动写程序解析 BMP 文件头(约 18:30 - 23:50)

  • 新建 analyzer.py,用最直觉的方式解析哆啦A梦图片 cat.bmp:
  • with open('cat.bmp', 'rb') as f: 打开;
  • magic_number = f.read(2) 读出 2 字节的 bytes(显示为 b'BM');用 magic_number.decode() 转成字符串(这里预告了下一小节字符编码的内容:二进制转字符串要解码,字符串转二进制要编码);
  • size = f.read(4) 读 4 字节文件大小,然后**手动转换**:先 size[::-1] 把字节序倒过来(小端),再 .hex() 得到十六进制字符串,最后 int(..., base=16) 转成整数。
  • 老师评价:这样每读一个字段都要手动思考如何转换,非常非常费劲——由此引出下一节的 struct 标准库。

示例与演示

  1. 画图讲解 BMP 三段结构(文件头 14 字节 / 信息头 40 字节 / 像素数据),按一行 16 字节排布。
  2. 用 VS Code Hexdump 插件打开哆啦A梦 BMP,逐字段对照分析:BM 标识、文件大小 120054 字节(与文件属性核对一致)、位图数据偏移 0x36、首像素 FFFFFF(白色)。
  3. 现场编写 analyzer.py:以 'rb' 方式打开 BMP,read(2) 读 magic number 并 decode();read(4) 读文件大小后手动倒序、转 hex、int(x, 16) 转换,最终得到正确的文件大小数值。

重点与难点

  • magic number / 文件特征:判断文件真实类型要看文件头特征字节(如 BMP 的 BM、exe 的 MZ),不能相信后缀名——这是安全分析的基本套路,也是本次作业的核心。
  • 小端存储:多字节数值低位在前,解析时必须先颠倒字节序再换算,这是手动解析最容易出错的地方。
  • Hexdump 视图与 bytes 字面值的显示逻辑相同:可打印显示字符,不可打印显示点/十六进制。
  • 手动逐字段解析二进制文件繁琐易错,为 struct 库的引入提供了动机。

关联内容

  • 直接承接 8.1 节 bytes/十六进制表示的知识;呼应第 7 章用 BMP 做 ASCII 艺术时跳过的"BMP 格式解析"部分,本节补上。
  • 与上学期课程内容关联:WinHex 查看硬盘数据、小端存储概念、恶意代码伪装文件的安全话题。
  • 手动解析的痛点引出 8.3 节 struct 标准库;decode() 的提及预告 8.4 节"字符集与编码"。
  • 文件特征比对思想是 8.6 节作业"猫鼠游戏"(识别改过后缀的假文件)的理论基础。