2、FPGA基础与开发流程回顾:FPGA内部结构(LUT、FF、BRAM、DSP)、典型开发流程(综合、实现、生成比特流)

好,咱们正式开始。这一章,我打算带大家快速过一遍FPGA的基础知识。你可能会问:“这些我都知道,为什么还要讲?”

嗯,我理解。但做逆向不一样。你得知道芯片里到底有什么,才能知道该从哪里下手。说白了,你得先懂“正着怎么设计”,才能“反着怎么破解”。

2.1 FPGA内部结构:四个核心元件

FPGA内部不是一堆乱七八糟的门电路。它是由几种固定的“积木块”拼起来的。我个人习惯把这四种元件称为FPGA的“四大金刚”:LUT、FF、BRAM、DSP

核心观点: 你看到的任何FPGA网表,最终都会被映射到这四种资源上。逆向分析,本质上就是猜出这些资源之间的连接关系。

2.1.1 LUT(查找表)—— 逻辑的灵魂

LUT,全称Look-Up Table。你可以把它想象成一个“真值表”。输入几个信号,输出一个结果。比如一个4输入的LUT,它内部其实就是一个16x1的RAM。你输入4位地址,它输出对应地址里存的那个bit。

我在项目中遇到过一种情况:网表里看到一个LUT被配置成了异或门。但通过分析它的真值表,我发现它其实是在做加法器的部分逻辑。你看,光看名字是猜不出来的,得看它“存了什么”。

避坑指南: 我曾经以为所有LUT都是4输入。后来碰到一个7系列FPGA,发现它有6输入LUT。这直接导致我分析连接关系时多算了一级。所以,先搞清楚你手里芯片的LUT规格,很重要。

2.1.2 FF(触发器)—— 时序的基石

FF,也就是Flip-Flop。它负责存储一个bit的状态,并在时钟沿到来时更新。FPGA里的FF通常带有复位端(Set/Reset)和使能端(Clock Enable)。

你想想看,一个寄存器是由多个FF组成的。在网表里,你看到一堆FF连在一起,基本就能猜到这是一个计数器或者移位寄存器。我习惯先找FF的时钟网络,这往往是整个设计的“心跳”。

2.1.3 BRAM(块RAM)—— 数据的仓库

BRAM是FPGA里的大容量存储。它不像LUT那样只能存几个bit,而是能存几Kb甚至几十Mb的数据。BRAM可以配置成单端口、双端口、甚至FIFO(先进先出队列)。

逆向时,BRAM是最难啃的骨头。因为它内部的数据是“黑盒”的。你只能看到它的地址线和数据线,但不知道里面存了什么。我通常的做法是:先通过分析读写逻辑,猜出它是在做查表、缓存还是FIFO。

资源类型 典型用途 逆向关注点
LUT 组合逻辑、译码器 真值表内容、输入输出连接
FF 寄存器、状态机 时钟域、复位方式、数据路径
BRAM 数据缓存、FIFO 端口配置、地址范围、读写时序
DSP 乘法、累加、滤波 操作模式、数据位宽、流水线级数

2.1.4 DSP(数字信号处理单元)—— 计算的引擎

DSP块,专门用来做乘法、加法、累加这些运算。它比用LUT搭出来的乘法器快得多,也省资源。在网表里,DSP块通常是一个独立的模块,有固定的输入输出端口。

我记得有一次逆向一个音频处理芯片,发现里面用了大量DSP块。通过分析它们的连接方式,我很快判断出这是一个FIR滤波器。因为DSP块被级联起来了,前一个的输出直接连到后一个的输入。这种结构太典型了。

2.2 典型开发流程:从代码到比特流

理解了内部结构,我们再看看这些结构是怎么被“造”出来的。FPGA的开发流程,说白了就是三步:综合、实现、生成比特流

注意: 逆向时,你拿到的往往是最后一步的产物(比特流)或者中间产物(网表)。所以,理解每一步做了什么,能帮你反向推导出原始设计。

2.2.1 综合(Synthesis)—— 把代码翻译成门电路

综合,就是把Verilog或VHDL代码,翻译成由LUT、FF、BRAM、DSP这些基本元件组成的网表。这一步,工具会做很多优化。比如,它会自动合并逻辑,去掉冗余的电路。

我刚开始做逆向时,总想把网表还原成原始的RTL代码。后来发现这几乎不可能。因为综合后的网表已经丢失了代码的结构信息。你只能看到“是什么”,看不到“为什么这么写”。

// 原始RTL代码
assign y = (a & b) | (c & d);

// 综合后的网表(示意)
LUT4 #(.INIT(16'hE888)) u_lut (.I0(a), .I1(b), .I2(c), .I3(d), .O(y));

你看,上面的LUT4的INIT值是0xE888。这个值就是真值表。通过分析这个值,我可以反推出它实现了什么逻辑。但原始代码里是“与或”还是“与非”,就看不出来了。

2.2.2 实现(Implementation)—— 把门电路放到芯片上

实现,包括翻译(Translate)、映射(Map)、布局布线(Place & Route)三个子步骤。这一步,工具会把综合出来的网表,分配到具体的LUT、FF位置上,并连接好它们之间的走线。

你想想看,这一步做完后,每个逻辑元件都有了具体的物理坐标。这对于逆向来说,是好事也是坏事。好事是,你可以通过物理位置推断出模块的划分(比如,同一个模块的元件通常挨在一起)。坏事是,你面对的不再是逻辑网表,而是一个巨大的、包含物理信息的布线表。

个人经验: 我习惯在实现后的网表里,先找“时钟树”。因为时钟信号会连到很多FF的时钟端。通过追踪时钟树,我能快速定位出整个设计的时序边界。

2.2.3 生成比特流(Bitstream Generation)—— 最终的配置文件

最后一步,就是把布局布线后的信息,打包成一个二进制文件——比特流。这个文件包含了所有LUT的INIT值、所有FF的初始状态、所有BRAM的初始化数据、以及所有开关矩阵的配置。

比特流是逆向的终极目标。因为它包含了芯片的全部配置信息。但它的格式通常是加密或混淆的。我见过一些芯片,比特流里直接包含了明文的配置数据,这简直是“开门揖盗”。但更多时候,你需要先破解比特流的格式,才能提取出有用的信息。

总结一下: 综合产生逻辑网表,实现产生物理网表,比特流是最终的配置文件。逆向时,你拿到的可能是其中任何一个阶段的产物。不同阶段,分析难度和侧重点完全不同。

2.3 本章知识体系:一张图看懂

为了让你更直观地理解,我画了一张图。它展示了FPGA内部结构、开发流程以及逆向切入点之间的关系。

FPGA基础与逆向切入点 FPGA内部结构 LUT(查找表) 组合逻辑、真值表 FF(触发器) 时序逻辑、状态存储 BRAM(块RAM) 数据缓存、FIFO DSP(数字处理单元) 乘法、累加、滤波 典型开发流程 综合(Synthesis) RTL → 逻辑网表 (LUT/FF/BRAM/DSP) 实现(Implementation) 映射 + 布局布线 (物理网表) 生成比特流 配置文件 (二进制/加密) 逆向切入点 逻辑网表分析 提取LUT真值表 追踪FF连接 物理网表分析 定位模块边界 分析时钟树 比特流逆向 格式解析 数据提取 图:FPGA内部结构、开发流程与逆向切入点对应关系

这张图从左到右,展示了“有什么”、“怎么造”、“怎么拆”的逻辑链条。你拿到一个网表,先看它用了哪些资源(LUT/FF/BRAM/DSP),再判断它处于开发流程的哪个阶段(综合后/实现后/比特流),最后选择对应的逆向方法。

嗯,这一章的内容就到这里。记住这四个元件和三步流程,后面我们所有的实战技巧,都是建立在这个基础之上的。

专注资料整理