2. 固件头部解析
任务说明
给定一份固件二进制文件,其头部结构包含魔数、版本号、硬件平台标识、加载地址和固件长度。编写Python脚本解析该头部,提取并校验这些关键信息。本案例使用构造的示例固件文件验证解析逻辑,不涉及真实设备固件。
固件头部结构定义
偏移量 大小 字段 说明
0x00 4字节 魔数 'FWIM' (0x464D4957)
0x04 2字节 版本号主版本 uint16 LE
0x06 2字节 版本号次版本 uint16 LE
0x08 2字节 硬件平台ID uint16 LE (1=STM32F4, 2=STM32H7, 3=ESP32)
0x0A 2字节 保留字段 置0
0x0C 4字节 加载地址 uint32 LE
0x10 4字节 固件长度 uint32 LE
0x14 4字节 头部CRC32 对偏移0x00~0x13的28字节计算
头部总长24字节(0x18)。CRC32使用标准IEEE 802.3多项式,初始值0xFFFFFFFF,结果按小端序存储。
完整实现代码
import struct
import zlib
import sys
HEADER_SIZE = 24
MAGIC = b'FWIM'
PLATFORM_NAMES = {1: 'STM32F4', 2: 'STM32H7', 3: 'ESP32'}
def parse_firmware_header(filepath):
with open(filepath, 'rb') as f:
data = f.read(HEADER_SIZE)
if len(data) < HEADER_SIZE:
raise ValueError(f'文件过小,不足头部长度 {HEADER_SIZE} 字节')
magic = data[0:4]
if magic != MAGIC:
raise ValueError(f'魔数错误: 期望 {MAGIC!r}, 实际 {magic!r}')
ver_major, ver_minor = struct.unpack_from('<HH', data, 4)
platform_id, reserved = struct.unpack_from('<HH', data, 8)
load_addr, fw_len = struct.unpack_from('<II', data, 12)
crc_stored = struct.unpack_from('<I', data, 20)[0]
# 校验CRC
crc_calc = zlib.crc32(data[:20]) & 0xFFFFFFFF
if crc_calc != crc_stored:
raise ValueError(f'CRC校验失败: 存储 0x{crc_stored:08X}, 计算 0x{crc_calc:08X}')
platform = PLATFORM_NAMES.get(platform_id, f'未知平台(0x{platform_id:04X})')
return {
'magic': magic.decode('ascii'),
'version': f'{ver_major}.{ver_minor}',
'platform_id': platform_id,
'platform_name': platform,
'load_address': hex(load_addr),
'firmware_length': fw_len,
'crc32': hex(crc_stored),
}
def create_test_firmware(filepath):
"""生成一个带合法头部的测试固件文件(头部+4字节填充数据)"""
ver_major, ver_minor = 2, 5
platform_id = 1
reserved = 0
load_addr = 0x08010000
fw_len = 4 # 仅测试数据长度
header_without_crc = struct.pack('<4sHHHHII', MAGIC, ver_major, ver_minor,
platform_id, reserved, load_addr, fw_len)
crc = zlib.crc32(header_without_crc) & 0xFFFFFFFF
header = header_without_crc + struct.pack('<I', crc)
with open(filepath, 'wb') as f:
f.write(header)
f.write(b'\x00\x01\x02\x03') # 模拟固件内容
if __name__ == '__main__':
if len(sys.argv) > 1:
fw_path = sys.argv[1]
else:
fw_path = 'test_fw.bin'
create_test_firmware(fw_path)
print(f'已生成测试固件: {fw_path}')
info = parse_firmware_header(fw_path)
print('固件头部解析结果:')
for k, v in info.items():
print(f' {k}: {v}')
运行与验证
- 环境依赖:Python 3.6+,无需第三方库(zlib和struct为标准库)。
- 运行方式:
python fw_header_parser.py(自动生成测试固件并解析);或python fw_header_parser.py your_firmware.bin解析指定文件。 - 通过条件:程序输出以下内容且无异常退出,即解析成功:
已生成测试固件: test_fw.bin
固件头部解析结果:
magic: FWIM
version: 2.5
platform_id: 1
platform_name: STM32F4
load_address: 0x8010000
firmware_length: 4
crc32: 0x...
其中crc32为实际计算值。若手动修改头部任一字节(如版本号),程序应报CRC校验失败或魔数错误,说明校验逻辑生效。
关键说明
- 解析器按小端序读取所有多字节字段,与常见ARM嵌入式固件约定一致。
- CRC32覆盖头部前20字节(不含CRC字段本身),存储值位于偏移0x14。
- 若需解析真实固件,仅需将
create_test_firmware替换为实际固件文件路径,并确认头部偏移与字段定义匹配。