第四章:比特流文件格式解析

说实话,搞FPGA逆向这么久,我觉得最基础也最关键的一步,就是搞懂比特流文件的结构。你想想看,如果你连文件里装的是什么都不知道,那后面的分析根本无从下手。今天我就带你把Xilinx、Intel、Lattice这三家的比特流格式挨个捋一遍。

4.1 Xilinx .bit文件结构

Xilinx的.bit文件,我个人觉得是最好解析的。它的结构非常规整,说白了就是一个文件头加上一堆配置数据。我在做第一个逆向项目时,就是拿.bit文件练的手。

4.1.1 文件头结构

每个.bit文件开头都有个固定魔数——0xFF 0xFF 0xFF 0xFF,然后是0xAA 0x99 0x55 0x66。嗯,这里要注意,不同版本的ISE/Vivado生成的魔数可能略有差异,但前四个0xFF基本不变。

// Xilinx .bit文件头结构
typedef struct {
    uint8_t sync_word[4];    // 0xFF 0xFF 0xFF 0xFF
    uint8_t magic[4];        // 0xAA 0x99 0x55 0x66
    uint16_t header_len;     // 文件头长度(大端)
    char design_name[216];   // 设计名称
    char part_name[216];     // 器件型号
    char date[216];          // 编译日期
    char time[216];          // 编译时间
    uint32_t data_len;       // 配置数据长度
} xilinx_bit_header;

我曾经遇到过一个坑:某个客户给的.bit文件死活解析不出来。后来发现是Vivado版本太新,文件头里多了几个字段。所以我的建议是,写解析器时一定要做版本兼容。

4.1.2 同步字与配置寄存器

文件头之后就是真正的配置数据了。这里有个关键概念——同步字。Xilinx FPGA在接收配置数据前,必须先收到一个32位的同步字:0xAA 0x99 0x55 0x66。为什么是这个值?其实它和文件头的魔数是一样的,用来告诉FPGA:「嘿,配置数据要来了,准备好!」

配置寄存器这块,我建议重点关注这几个:

寄存器名称 地址 功能说明
CRC 0x00 CRC校验寄存器
FAR 0x01 帧地址寄存器
FDRI 0x02 帧数据输入寄存器
CMD 0x04 命令寄存器
CTL0 0x05 控制寄存器0
MASK 0x06 掩码寄存器
STAT 0x07 状态寄存器
LOUT 0x08 菊花链输出寄存器
COR0 0x09 配置选项寄存器0

4.1.3 帧数据解析

帧数据是比特流的核心。每个帧包含了一列逻辑资源(CLB、DSP、BRAM等)的配置信息。Xilinx 7系列FPGA的帧结构大概是这样的:

// 帧数据包格式
typedef struct {
    uint8_t type;           // 包类型(0x01=读, 0x02=写)
    uint8_t opcode;         // 操作码
    uint16_t word_count;    // 数据字数
    uint32_t data[];        // 实际数据
} xilinx_packet;

我记得有一次逆向一个加密的比特流,发现帧数据被重新排列了。当时花了整整一周才找到规律——原来是用了一个自定义的地址映射表。所以如果你遇到帧数据对不上,别急着怀疑自己,先看看是不是有地址重映射。

4.2 Intel .pof/.sof文件格式

Intel(原Altera)的比特流格式和Xilinx差别很大。.sof是SRAM对象文件,用于JTAG直接下载;.pof是编程对象文件,用于配置器件存储。

4.2.1 .sof文件结构

.sof文件的结构相对简单,我直接上代码:

// .sof文件头
typedef struct {
    char magic[4];          // "SOF\x00"
    uint32_t version;       // 版本号
    uint32_t part_id;       // 器件ID
    uint32_t data_len;      // 配置数据长度
    uint32_t crc32;         // CRC32校验
} sof_header;

这里有个有意思的地方:Intel的.sof文件用的是小端序,而Xilinx的.bit文件是大端序。我第一次切换平台时就被这个坑过,读出来的数据全是反的。

4.2.2 .pof文件结构

.pof文件比.sof复杂得多,因为它要支持压缩和加密。基本结构如下:

// .pof文件结构
struct pof_header {
    uint32_t magic;         // 0x12345678
    uint32_t version;
    uint32_t num_blocks;    // 数据块数量
    uint32_t flags;         // 标志位(压缩/加密)
};

struct pof_block {
    uint32_t block_type;    // 0x01=配置数据, 0x02=加密数据
    uint32_t block_len;
    uint32_t block_crc;
    uint8_t data[];
};

我曾经在分析一个加密的.pof文件时,发现它的CRC校验值怎么也算不对。后来才意识到,Intel在计算CRC时会把文件头排除在外。这个细节在官方文档里写得很隐晦,我建议你直接看源码验证。

4.3 Lattice .bit文件格式

Lattice的.bit文件格式,说实话,是三家里最「随性」的。它的文件头没有固定长度,完全靠关键字来定位。

4.3.1 文件头解析

// Lattice .bit文件头(示例)
"LATTICE"           // 厂商标识
"BITSTREAM"         // 比特流标识
"DEVICE: LCMXO2-1200HC"  // 器件型号
"PACKAGE: TQFP144"       // 封装
"DATE: 2024/01/15"       // 日期
"TIME: 14:30:00"         // 时间
"LENGTH: 0x00012345"     // 数据长度

嗯,这里要注意,Lattice的.bit文件里,关键字和值之间是用冒号分隔的,而且每行结尾没有分号。我刚开始写解析器时,按Xilinx的习惯去解析,结果全乱了。

3.3.2 配置数据格式

Lattice的配置数据是按页组织的,每页包含多个帧。帧的大小取决于器件型号。以LCMXO2系列为例:

// Lattice配置数据包
struct lattice_page {
    uint16_t page_addr;     // 页地址
    uint16_t frame_count;   // 帧数量
    uint32_t frame_data[];  // 帧数据(每帧固定32位)
};

我个人觉得Lattice的格式最灵活,但也最不统一。不同系列的器件,帧大小、页数量都可能不同。我的建议是,解析时先读器件型号,再查对应的参数表。

4.4 CRC校验机制

CRC校验是比特流文件里最重要的安全机制之一。三家厂商用的CRC算法各不相同:

厂商 CRC算法 多项式 初始值
Xilinx CRC-32 0x04C11DB7 0xFFFFFFFF
Intel CRC-32 0x04C11DB7 0x00000000
Lattice CRC-16 0x8005 0x0000

我曾经在逆向一个Xilinx的比特流时,发现CRC校验总是失败。排查了半天,原来是配置数据里插入了几个空帧,导致CRC计算范围不对。所以我的经验是:CRC校验时,一定要搞清楚计算范围——是只算配置数据,还是连文件头也算进去。

核心要点:

  • Xilinx .bit:固定文件头 + 同步字 + 帧数据包,大端序
  • Intel .sof/.pof:小端序,.pof支持压缩加密
  • Lattice .bit:关键字驱动文件头,按页组织数据
  • CRC校验:三家算法不同,计算范围要注意

实用技巧:写解析器时,建议先用已知的比特流文件做测试。我一般会准备三个厂商的官方例程生成的比特流,确保解析器能正确读取。

警告:不要假设所有比特流文件都遵循标准格式。有些厂商会更新格式,或者加入自定义字段。解析时一定要做边界检查,防止缓冲区溢出。

比特流文件格式对比 Xilinx .bit 文件头(魔数+元数据) 同步字 0xAA995566 配置寄存器写入 帧数据包 (Type+Opcode+Data) CRC校验 Intel .sof/.pof 文件头(小端序) 配置数据块 压缩/加密数据 (.pof特有) CRC32校验 Lattice .bit 关键字文件头 页数据(Page) 帧数据 (每帧32位) CRC16校验 三家厂商比特流文件结构对比 注意:不同器件系列内部细节可能有所不同

好了,以上就是三家主流FPGA厂商的比特流文件格式解析。说实话,这些格式看起来复杂,但只要你掌握了文件头、配置数据和CRC校验这三个核心要素,剩下的就是细节问题了。我在实际项目中,一般会先写一个通用的解析框架,再针对不同厂商做适配。

公众号:蓝海资料掘金营,微信deep3321