第二章:比特流结构解析

各位同学,今天我们来聊聊比特流结构。说实话,搞FPGA逆向分析,比特流就是你绕不开的第一道坎。我刚开始接触这玩意儿的时候,看着那一串串十六进制数据,脑袋都是懵的。后来慢慢摸清了门道,才发现——嗯,其实它是有规律可循的。

2.1 Xilinx比特流格式

Xilinx的比特流,说白了就是一个二进制文件。它由三大部分组成:头部、配置数据和尾部。我个人习惯把头部再细分成两个区域——固定头部和可变头部。

固定头部通常包含同步字。Xilinx的同步字是固定的32位数据:0xAA995566。你想想看,这个值是不是很眼熟?对,它就是用来告诉FPGA:「嘿,数据来了,准备接收!」

可变头部则包含了一些元信息,比如器件型号、设计名称、日期等等。我在项目中遇到过一种情况:客户拿来的比特流头部被篡改了,导致加载失败。后来我通过比对正常比特流的头部结构,才定位到问题所在。

关键点:Xilinx比特流头部的前32字节是固定结构,包含同步字、长度信息和一些保留位。从第33字节开始,才是真正的配置数据。

2.2 Altera比特流格式

Altera(现在叫Intel FPGA)的比特流格式跟Xilinx不太一样。它的同步字是0xFFFFFFFF,后面跟着一个32位的长度字段。我记得第一次分析Altera比特流时,差点被这个全F的同步字给骗了——还以为全是无效数据。

Altera的比特流头部相对简单一些。它没有Xilinx那么复杂的可变头部,而是直接把配置参数编码在数据流中。说白了,就是「边解析边配置」的模式。

厂商 同步字 头部长度 配置方式
Xilinx 0xAA995566 可变(通常32-128字节) 先头部后数据
Altera 0xFFFFFFFF 固定(4字节) 边解析边配置

2.3 比特流头部解析实战

解析头部,我建议你从同步字入手。找到同步字后,往前推32字节,就是头部区域。为什么是32字节?因为Xilinx的固定头部就是32字节,这是官方文档里写的。

我曾经写过一个Python脚本,专门用来解析Xilinx比特流头部。核心逻辑是这样的:

def parse_xilinx_header(bitstream):
    # 查找同步字
    sync_word = b'\xAA\x99\x55\x66'
    idx = bitstream.find(sync_word)
    if idx == -1:
        print("找不到同步字,可能不是Xilinx比特流")
        return None
    
    # 提取头部
    header = bitstream[idx-32:idx]
    
    # 解析头部字段
    device_id = header[8:12]  # 器件ID
    design_name = header[16:32]  # 设计名称
    
    return {
        'device_id': device_id.hex(),
        'design_name': design_name.decode('ascii', errors='ignore')
    }

小技巧:解析头部时,别忘了检查字节序。Xilinx默认是大端序,但有些工具生成的是小端序。我吃过这个亏,浪费了整整一个下午。

2.4 配置数据段识别

配置数据段,就是比特流的主体部分。它包含了FPGA内部所有可编程逻辑的配置信息。怎么识别它?很简单——头部之后、CRC之前的所有数据,都是配置数据段。

但这里有个坑:配置数据段内部是有结构的。Xilinx把它分成了多个「帧」(Frame),每个帧对应FPGA内部的一个配置单元。Altera则用「块」(Block)来组织数据。

我个人习惯用「帧对齐」的方法来识别配置数据段。具体做法是:

  1. 找到头部结束位置
  2. 从该位置开始,每32字节为一帧
  3. 检查帧头标志(Xilinx是0x3000开头)
  4. 如果连续3帧都符合帧头格式,就确认是配置数据段

注意:有些加密比特流会在配置数据段中插入「假帧」来混淆分析。我曾经遇到过一种情况:比特流中每隔10帧就插入一个全0的假帧,导致帧对齐失败。解决办法是——跳过全0帧,继续对齐。

2.5 同步字与CRC校验

同步字的作用,我前面已经提到了。但CRC校验这块,我得好好说说。Xilinx和Altera都使用CRC来验证比特流的完整性,但算法不同。

Xilinx用的是CRC-32,多项式是0x04C11DB7。Altera用的是CRC-16,多项式是0x8005。你想想看,为什么厂商要选不同的CRC算法?说白了,就是不想让你轻易复用对方的工具链。

CRC校验值通常放在比特流的尾部。Xilinx的CRC值占4字节,Altera的占2字节。我在项目中遇到过一种情况:比特流的CRC校验失败,但FPGA依然能正常加载。后来发现,是FPGA的配置模式被改成了「忽略CRC」模式。嗯,这算是一个安全漏洞。

核心要点:CRC校验是比特流完整性的最后一道防线。如果你在逆向分析时发现CRC校验失败,不要急着放弃——先检查一下配置模式寄存器,看看CRC校验是否被关闭了。

2.6 知识体系总览

为了让你更直观地理解比特流结构,我画了一张图。这张图展示了Xilinx和Altera比特流的整体框架,以及各个部分之间的关系。

比特流结构总览 Xilinx 比特流 固定头部 (32字节) 同步字: 0xAA995566 可变头部 (0-96字节) 器件ID、设计名称、日期 配置数据段 由多个帧(Frame)组成 每帧32字节,帧头0x3000 CRC校验 (4字节) CRC-32, 多项式: 0x04C11DB7 Altera 比特流 同步字 (4字节) 0xFFFFFFFF 长度字段 (4字节) 配置数据总长度 配置数据段 由多个块(Block)组成 边解析边配置模式 CRC校验 (2字节) CRC-16, 多项式: 0x8005 注:实际比特流结构可能因器件型号和工具版本略有差异

这张图把Xilinx和Altera的比特流结构放在一起对比,你可以清楚地看到它们的异同。我个人觉得,理解这张图是掌握比特流解析的关键一步。

实战建议:拿到一个未知比特流,先别急着分析。用十六进制编辑器打开,找到同步字,然后对照这张图,一步步定位各个部分。多练几次,你就能一眼看出比特流的结构了。

专注资料整理