第四讲:比特流抓取实战

各位好,我是老周。今天咱们聊点硬核的——怎么把FPGA的比特流给“抓”出来。

你可能会问:比特流不就是个配置文件吗?有什么好抓的?

嗯,这么说吧。我当年第一次拆解某款工业控制板时,发现主控芯片被打磨了型号。但通过JTAG口,我硬是把它的配置流读了出来,反推出内部逻辑。说白了,比特流就是FPGA的“灵魂”,拿到它,你就能理解这个芯片到底在干什么。

4.1 JTAG读取FPGA配置

JTAG,全称是Joint Test Action Group。这玩意儿最初是用来做边界扫描测试的,但后来被玩出了花——调试、编程、读取配置,样样都行。

我个人习惯,第一步永远是先确认JTAG链是否正常。怎么确认?用下面这条命令:

# 检测JTAG链上的设备
jtag -list
# 输出示例:
# 1: Xilinx XC7A35T (IDCODE: 0x0362d093)
# 2: Unknown device (IDCODE: 0x00000000)

看到IDCODE了没?每个FPGA都有唯一的IDCODE。如果读到0x00000000或者全F,那基本可以断定——要么线接错了,要么芯片已经“死”了。

⚠️ 注意: JTAG的TCK时钟频率别设太高。我遇到过一哥们,上来就设50MHz,结果读出来的数据全是乱的。建议从1MHz开始,稳定后再往上调。

确认设备后,就可以读取配置了。以Xilinx 7系列为例:

# 读取整个配置空间
jtag -read -start 0x00000000 -length 0x1000000 -file config.bin

这里有个坑——有些FPGA会锁定读保护。我曾经拆过一块军用级的板子,JTAG口直接返回“Security Locked”。遇到这种情况,别硬来,后面我会讲怎么绕过。

4.2 通过SelectMAP接口抓取比特流

JTAG虽然方便,但速度慢。如果你需要抓取大容量的比特流(比如Kintex-7这种),JTAG能把你急死。

这时候就该SelectMAP上场了。SelectMAP是并行接口,8位或16位数据线,速度比JTAG快一个数量级。

SelectMAP的引脚定义如下:

引脚名 方向 功能
D[7:0] 双向 数据总线
CS_B 输入 片选信号(低有效)
RDWR_B 输入 读写控制(1=读,0=写)
BUSY 输出 忙标志

抓取流程其实不复杂:

  1. 拉低CS_B,选中设备
  2. 设置RDWR_B为高电平(读模式)
  3. 在时钟上升沿读取D[7:0]上的数据
  4. 如果BUSY拉高,说明FPGA还没准备好,等它释放

我当年用逻辑分析仪抓SelectMAP波形时,发现一个有趣的现象——有些FPGA在读取配置时,前几个字节会返回0xFF。这不是错误,而是FPGA内部还在初始化。你想想看,就像人刚睡醒,总得先眨眨眼吧。

💡 小技巧: 如果你用MCU模拟SelectMAP时序,记得把GPIO设置为开漏输出。我曾经因为推挽输出导致总线冲突,烧坏了一块FPGA的IO口。

4.3 分析原始比特流文件的头部与尾部标记

拿到原始比特流文件后,别急着分析。先看看它的“身份证”——头部和尾部标记。

以Xilinx的比特流为例,头部通常包含以下信息:

// 典型的Xilinx比特流头部
0xFFFFFFFF  // 同步字(32个1)
0xAA995566  // 同步头(固定魔数)
0x20000000  // 类型标识(0x20表示配置数据)
0x30008001  // 长度字段
// ... 后续是配置数据

尾部标记则相对简单:

// 比特流尾部
0x20000000  // 类型标识
0x00000000  // 空数据填充
0x30008001  // 结束标记
// 最后通常有4个字节的CRC校验

这里有个关键点——同步头0xAA995566。这个魔数几乎在所有Xilinx比特流里都能找到。如果你在逆向别人的比特流时,先搜这个值,就能快速定位配置数据的起始位置。

我记得有一次,客户拿来一块砖头一样的FPGA板,说“读不出来”。我一看,JTAG能识别设备,但读出来的数据全是0。后来我手动抓SelectMAP波形,发现头部同步字被篡改了——0xFFFFFFFF变成了0xFFFFFFFE。这明显是有人故意加了反逆向措施。

🔍 实战要点:
  • 头部同步字:0xFFFFFFFF(至少4字节)
  • 魔数标记:0xAA995566(Xilinx)或0x0F0F0F0F(Altera)
  • 尾部CRC:通常为4字节,算法为CRC-32
  • 如果头部异常,先检查时钟域是否对齐

最后,我画了一张图,把整个流程串起来:

比特流抓取核心流程 1. 硬件连接 JTAG/SelectMAP 2. 设备识别 读取IDCODE 3. 数据抓取 读取配置空间 4. 分析 头部/尾部 是否锁定? 尝试绕过/降级 电压毛刺/时钟毛刺 成功读取比特流

这张图把整个流程分成了四个阶段。注意中间那个菱形判断——如果设备被锁定,你就得走右侧的“绕过”分支。这不是常规操作,但有时候是唯一的路。

好了,这一讲的内容就到这里。记住:抓比特流不是目的,理解它背后的逻辑才是。下一讲我们会深入分析比特流的内部结构,看看那些0和1到底是怎么映射成LUT和触发器的。


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