
1. 从TCHES 2026那篇IC逆向综述说起为什么这个方向突然又热了TCHESIACR Transactions on Cryptographic Hardware and Embedded Systems2026年那篇IC逆向综述我前后读了三遍。第一遍是扫标题和图表第二遍是抠方法论分类第三遍是拿着自己手头几个FPGA项目对照着看——哪些技术能直接迁移哪些只是学术上的漂亮框架。读完之后最大的感受是IC逆向这个领域正在经历一次方法论层面的重构而推动这次重构的恰恰是netlist分析、FPGA原型验证和LLM辅助理解这三股力量的交汇。先说清楚IC逆向到底在做什么。简单讲就是拿到一个已经制造出来的芯片或者一份已经综合好的门级网表netlist在没有任何原始RTL源码、没有设计文档的情况下反推出它的功能结构、模块划分、数据通路、控制逻辑甚至定位到具体的算法实现。这件事在硬件安全、IP合规审查、老旧芯片维护、竞品分析等场景里都有硬需求。以前做这件事主要靠人工读网表、画状态机、跑仿真对比一个中等规模的FPGA设计逆向下来几个月是常态。那篇综述的核心贡献在于它把IC逆向的技术路线梳理成了几个清晰的层次门级网表的结构化分析、功能模块的自动识别与聚类、控制逻辑的状态机重建、数据通路的位宽与运算推断以及跨层次的一致性验证。每一层都有对应的算法工具和评估指标不再是以前那种“师傅带徒弟、全靠经验”的作坊模式。但真正让我觉得值得写一篇东西的是这篇综述里反复提到的一个趋势LLM正在从“辅助工具”变成“逆向流程中的核心推理引擎”。这个判断和我在实际项目里的体感完全吻合。去年我帮朋友看一个基于FPGA的多端口DDR读写控制器的网表里面有一堆状态机和仲裁逻辑人工读了两天没理清楚。后来我把网表的关键片段做了结构化提取喂给一个本地部署的LLM做模式识别和功能标注两个小时就把主要模块的职责和交互关系理出来了。当然LLM会犯错但在“快速建立全局认知”这个环节它的效率提升是数量级的。所以这篇博文不打算复述那篇综述的内容——那是学术论文该干的事。我想做的是把综述里提到的技术框架和我自己在FPGA逆向、netlist分析、LLM辅助理解这几个方向上的实操经验结合起来给出一套能落地的IC逆向方法论。不管你是做FPGA开发的工程师、做硬件安全的研究生还是单纯对“怎么看懂一个陌生芯片”这件事好奇的技术爱好者下面这些内容应该都能给你一些可以直接用的东西。2. 门级网表到手之后先别急着读逻辑2.1 网表不是代码读之前先做结构预处理很多人拿到netlist的第一反应是打开文本编辑器从头开始读。这是最低效的做法。一个中等规模的FPGA设计综合之后门级网表动辄几十万行里面充斥着LUT6、FDRE、CARRY4、DSP48E1这类原语实例以及密密麻麻的net连接关系。直接读读三天也读不出全局结构。正确的第一步是做结构预处理。具体来说就是把网表转换成几种不同粒度的中间表示模块层次树从顶层往下把每个module的实例化关系抽出来形成一棵树。这棵树告诉你设计的物理分区和逻辑分区大致是什么样的。连接图把每个原语实例当作节点把net当作边构建一个有向图。这个图可以用来做后续的聚类和社区发现。扇入扇出统计对每个节点统计它的输入输出数量高扇出的节点往往是控制信号或者时钟复位网络低扇出的往往是数据通路上的局部逻辑。我通常用Python写脚本做这件事核心库是networkx和pyverilog如果是Verilog网表或者直接解析EDIF格式。下面是一个简化的预处理流程示例import networkx as nx from pyverilog.vparser.parser import parse # 解析网表文件提取模块层次和实例连接 ast, directives parse([design_netlist.v]) # 遍历AST提取module定义和instance # 构建层次树和连接图 # 对连接图做社区发现识别潜在的功能簇 communities nx.community.louvain_communities(conn_graph)这一步的输出不是给人看的是给后续分析工具和LLM看的。结构预处理的质量直接决定了后面所有分析的效率。我见过太多人跳过这一步结果在几十万行网表里迷路最后放弃。2.2 用社区发现算法定位功能簇连接图建好之后下一步是功能簇识别。一个设计再复杂它的内部也是由若干功能相对独立的模块组成的时钟管理、复位控制、数据缓存、运算单元、接口协议处理、状态机控制等等。这些模块在连接图上的表现是内部连接密集对外连接稀疏。Louvain社区发现算法在这件事上表现很稳。它不需要预先指定簇的数量而是通过优化模块度modularity自动发现图上的自然分组。我在一个FPGA图像处理项目的网表上试过Louvain把设计分成了17个社区其中12个和人工分析出来的功能模块完全对应剩下5个是跨模块的胶合逻辑和测试逻辑。这个准确率对于“快速建立全局认知”来说已经足够了。社区发现之后每个社区需要做特征提取为后续的LLM分析准备输入。特征包括特征类型具体内容用途规模特征节点数、边数、原语类型分布判断模块复杂度接口特征输入输出端口数量、位宽、方向推断模块边界时序特征是否包含寄存器、状态机原语区分组合逻辑和时序逻辑运算特征是否包含DSP、乘法器、加法器原语识别运算单元存储特征是否包含BRAM、分布式RAM原语识别缓存模块这些特征提取出来之后每个社区就变成了一个结构化的描述对象而不是一堆难以理解的网表行。这个描述对象就是喂给LLM的“原料”。2.3 为什么不能直接让LLM读原始网表这里要专门说一下。很多人听说LLM能辅助逆向第一反应是把整个网表文件丢给LLM让它分析。这个做法基本不可行原因有三个第一上下文长度限制。即使是最新的长上下文模型面对几十万行网表也力不从心。而且网表里大量重复的原语实例和net声明信息密度极低塞进去纯属浪费token。第二LLM不擅长精确的图结构推理。网表的本质是一个图LLM对图结构的理解能力远不如专门的图算法。让LLM去追踪一条跨十几个模块的信号路径它很容易跟丢。第三幻觉问题。LLM会“脑补”出不存在的连接关系或者功能描述。在逆向场景里一个错误的推断可能导致整个分析方向跑偏。正确的做法是分层处理图算法负责结构分析和聚类LLM负责语义标注和功能推断。图算法给出“这个簇有23个节点、包含4个DSP48、对外有3组32位数据接口”LLM根据这个描述推断“这很可能是一个32位复数乘法累加单元”。两者各司其职效率和准确率都高得多。3. 控制逻辑逆向状态机重建是绕不过去的坎3.1 从网表中提取状态机的完整链路任何有一定复杂度的数字设计核心都是一组状态机。数据通路决定“能算什么”控制逻辑决定“什么时候算、算什么、结果放哪里”。逆向一个设计如果状态机没理清楚数据通路分析得再细也没用。从门级网表提取状态机的标准流程是这样的识别寄存器组找到所有由同一个时钟驱动、共享复位信号的触发器组。这些触发器组就是状态寄存器的候选。提取状态转移条件对每个状态寄存器追踪它的D端输入逻辑一直追溯到其他状态寄存器的输出或者外部输入。这一步会得到一个布尔方程组。状态编码推断根据状态寄存器的位宽和实际取值推断编码方式二进制、格雷码、独热码。状态转移图构建把布尔方程组转换成状态转移表再画成状态转移图。状态语义标注结合数据通路的使能信号和外部接口的握手信号给每个状态赋予功能含义。这个流程听起来很线性实际操作中最大的难点在第二步和第五步。第二步的布尔方程组可能非常复杂尤其是当状态机有大量条件分支的时候。第五步的语义标注需要结合设计的外部行为单看网表很难确定“这个状态到底在等什么”。3.2 状态机语义标注LLM能帮上什么忙状态转移图建好之后每个状态节点只有编号和转移条件没有语义。比如“状态7在条件A下转到状态12在条件B下转到状态3”这本身不说明任何问题。要理解它的含义需要结合数据通路上的操作。我的做法是把状态转移图和每个状态对应的数据通路操作从使能信号和选择信号推断一起打包让LLM做语义标注。具体来说给LLM的输入包括状态转移表当前状态、条件、下一状态每个状态下活跃的数据通路组件哪些寄存器在加载、哪些MUX在选择、哪些运算单元在使能外部接口的握手信号状态如果有的话LLM的输出是对每个状态的功能描述比如“状态7等待输入FIFO非空同时配置DDR控制器的突发长度寄存器”。这个描述不一定100%准确但它给了你一个可以验证的假设。你可以根据这个假设去跑仿真看实际行为是否吻合。我在一个基于FPGA的串口通信项目里试过这个方法。设计里有一个发送状态机人工分析花了半天才理清楚它的重传逻辑。用LLM辅助标注之后它直接指出“状态5到状态8的循环对应超时重传重传计数器在状态8清零”这个判断和实际RTL完全一致。当然也有翻车的时候另一个项目里LLM把一个DDR刷新状态机误判成了数据搬运状态机原因是刷新计数器的位宽和地址计数器很像。所以LLM的输出必须验证不能直接采信。3.3 状态机逆向中的常见陷阱做了这么多项目状态机逆向有几个坑是反复踩的陷阱一异步复位和同步复位的混淆。网表里FDRE和FDCE的区别就是复位类型但有些综合工具会把同步复位转成异步复位加同步逻辑读网表的时候容易误判。我的经验是看复位信号是否直接连到触发器的CLR端如果是就是异步如果复位信号先经过一个与时钟同步的逻辑再进CLR就是同步。陷阱二状态编码的优化。综合工具会对状态编码做优化比如把独热码转成二进制码来省面积或者把等价状态合并。你从网表里提取出来的状态数可能比RTL里少这不是你提取错了是综合工具做了优化。遇到这种情况需要结合数据通路的位宽和控制信号的复杂度来反推原始状态数。陷阱三跨时钟域的状态机。如果设计里有多个时钟域每个时钟域可能有自己的状态机它们之间通过握手信号同步。逆向的时候必须先把时钟域划分清楚否则会把不同时钟域的状态混在一起分析得出完全错误的结论。提示在开始状态机逆向之前先用时钟树分析工具把设计的时钟域划分出来。这一步花的时间会在后面省回来十倍。4. 数据通路逆向位宽推断和运算识别4.1 位宽推断从原语连接反推数据宽度数据通路逆向的第一个任务是确定每条信号路径的位宽。在RTL里位宽是显式声明的在网表里位宽体现在连接关系上一条32位总线在网表里就是32根独立的net它们通常一起走线、一起进同一个模块的端口。位宽推断的基本方法是端口对齐分析。对每个模块实例看它的数据输入端口和输出端口分别连接了多少根net。如果一组net总是同时出现在同一个模块的同一个端口上它们很可能属于同一条总线。再结合模块内部的原语类型比如DSP48的A端口是25位、B端口是18位可以进一步确认位宽。实际操作中位宽推断最难处理的是位宽不匹配的连接。比如一个32位的数据要进一个18位的乘法器中间会有截断或者符号扩展逻辑。这些逻辑在网表里表现为一堆LUT和MUX需要仔细追踪才能确定实际参与运算的位宽。我通常用数据流追踪的方法从设计的输入端口开始沿着连接图往下游走每经过一个模块就更新当前信号的位宽属性。遇到位宽变化的地方截断、扩展、拼接记录下来这些往往是设计的关键决策点。4.2 运算单元识别DSP和LUT的分工FPGA上的运算实现有两种方式用DSP硬核或者用LUT搭建。DSP48系列硬核通常用于乘法、乘累加、复数运算等场景LUT搭建的运算则用于加法、比较、位操作等。从网表里识别运算单元关键是看原语类型和连接模式DSP48E1/E2直接识别看它的OPMODE和ALUMODE配置可以确定是做乘法、乘加还是逻辑运算。CARRY4/CARRY8进位链原语通常用于加法器、减法器、比较器。看进位链的输入输出连接可以推断运算类型和位宽。LUT6通用查找表可能是任意组合逻辑。需要结合上下文判断功能。这里有一个经验性的判断规则如果一个模块内部有大量CARRY4原语且它们的进位输出串联在一起这几乎肯定是一个加法器或者累加器。如果CARRY4的输入来自DSP的输出那这是一个乘累加结构。如果CARRY4的输入来自寄存器的反馈那这是一个计数器或者累加器。4.3 用LLM做运算功能的语义推断运算单元的结构识别出来之后还需要推断它的数学含义。比如一个模块有4个DSP48、若干CARRY4和一堆寄存器它到底是在做复数乘法、矩阵乘法、还是滤波器卷积这个层面的推断LLM可以帮上忙。给LLM的输入是运算单元的结构描述DSP的数量和配置、CARRY4的连接模式、寄存器的位宽和反馈路径、输入输出端口的位宽。LLM根据这些信息推断可能的数学运算类型并给出置信度。我在一个FPGA信号处理项目里试过这个方法。设计里有一个模块结构描述是“2个DSP48做18x25乘法结果进CARRY4做32位累加累加结果寄存后反馈回DSP的C端口”。LLM推断这是“乘累加结构可能用于FIR滤波或者矩阵向量乘法”。后来对照RTL确实是一个FIR滤波器。这个推断的准确率让我有点意外。当然LLM也会给出多个候选解释。比如同样的结构也可能是用于计算两个向量的点积。这时候需要结合外部接口的数据流模式来区分如果输入是连续流式的更可能是FIR如果输入是成批的向量更可能是点积。5. LLM辅助逆向的工程化落地5.1 本地部署还是API调用一个实际的选型分析把LLM引入IC逆向流程第一个决策是部署方式。这里有两个选项本地部署开源模型或者调用云端API。本地部署的优势是数据不出内网对于涉及敏感IP的逆向项目这是硬性要求。劣势是需要GPU资源而且模型能力通常不如云端的大模型。我目前用的方案是本地部署一个中等规模的开源模型具体型号不说了避免广告嫌疑配合结构化的输入输出约束在“功能标注”和“语义推断”这两个任务上准确率能满足需求。云端API的优势是模型能力强、无需维护基础设施。劣势是数据要上传而且对于大批量的网表分析token成本不低。我的建议是如果项目涉及第三方IP或者商业机密必须本地部署如果是学术研究或者开源项目分析可以用API。还有一个中间方案混合部署。把网表的结构化特征提取放在本地只把脱敏后的特征描述发给云端LLM做语义推断。这样既利用了云端模型的能力又避免了原始网表泄露。但脱敏过程本身需要仔细设计确保特征描述里不包含可识别设计来源的信息。5.2 提示词工程怎么问才能让LLM给出有用的回答LLM辅助逆向的效果很大程度上取决于你怎么问。我总结了几条实用的提示词设计原则原则一给结构不给原始数据。不要贴网表片段而是贴结构化的特征描述。比如“模块A有3个输入端口位宽分别是8、16、32内部有2个DSP48、15个CARRY4、200个FDRE输出端口1个位宽32”。这种描述LLM处理起来准确得多。原则二限定输出格式。要求LLM按照固定的JSON格式输出包括“功能描述”、“置信度”、“可能的替代解释”。这样后续可以程序化地处理LLM的输出也方便人工审核。原则三提供上下文约束。告诉LLM这个设计的大致应用领域比如“这是一个FPGA图像处理设计”可以显著提高推断的准确率。但要注意这个上下文本身不能是敏感信息。原则四要求LLM给出推理链。让LLM在给出结论之前先列出它的推理步骤。这样即使结论错了你也能看出它是在哪一步跑偏的方便调整提示词。下面是一个我常用的提示词模板你是一个数字电路逆向分析专家。下面是一个FPGA设计中的功能模块的结构化描述 模块名称mod_17 输入端口[{name: din, width: 32, direction: input}, ...] 输出端口[...] 内部原语统计{DSP48E1: 4, CARRY4: 32, FDRE: 512, LUT6: 1200, BRAM36: 2} 连接特征DSP48的输出连接到CARRY4的进位链CARRY4的输出反馈到FDREFDRE的输出连接到DSP48的C端口。 请推断这个模块的功能按以下JSON格式输出 { function: 功能描述, confidence: 0.0-1.0, reasoning: 推理步骤, alternatives: [替代解释1, 替代解释2] }这个模板在我自己的项目里跑下来对于运算密集型模块的功能推断准确率大概在70%左右。剩下的30%需要人工验证和修正。但对于“快速建立全局认知”来说70%的准确率已经能省下大量时间了。5.3 验证闭环LLM推断结果怎么落地LLM给出的功能推断必须经过验证才能写入逆向报告。验证的方法有三种方法一仿真对比。如果设计有可用的测试向量或者可以构造测试向量跑仿真看实际输出是否和LLM推断的功能一致。这是最可靠的验证方法但需要设计是可仿真的。方法二交叉验证。用不同的LLM或者同一LLM的不同提示词对同一个模块做多次推断看结果是否一致。如果多次推断结果一致可信度较高如果分歧很大说明这个模块的结构特征不够明确需要人工介入。方法三局部RTL重建。根据LLM的推断手工写出对应的RTL代码然后和原始网表做等价性检查。如果等价性通过说明推断正确。这个方法最严谨但工作量也最大通常只用于关键模块。我在实际项目里的做法是先用方法二做快速筛选对置信度高的模块直接采信对置信度低的模块用方法一或方法三做深入验证。这样在效率和准确性之间取得平衡。6. FPGA原型验证在逆向流程中的角色6.1 为什么逆向需要FPGA验证IC逆向的最终产出是一份对设计的功能理解但理解是否正确需要验证。FPGA在这个环节扮演的角色是提供一个可运行的验证平台。具体来说如果你逆向的是一个ASIC设计你不可能把ASIC重新流片来验证你的理解。但你可以把逆向出来的RTL或者部分RTL综合到FPGA上用实际的输入激励去跑看输出是否符合预期。如果符合说明你的逆向理解是正确的如果不符合说明某个环节出了问题需要回头修正。我在一个老旧通信芯片的逆向项目里用过这个方法。芯片的原始RTL已经丢失只有一份门级网表。我们花了三周时间逆向出主要模块的RTL综合到一块FPGA开发板上用信号发生器输入测试信号用逻辑分析仪抓输出。第一次跑的时候输出完全不对后来发现是一个状态机的转移条件理解错了。修正之后输出和芯片实测结果完全一致。这个验证过程给了我们很大的信心。6.2 FPGA验证平台搭建的实操要点搭建FPGA验证平台有几个关键点第一时钟和复位要可控。逆向出来的设计时钟频率和复位极性可能和原始设计不同。验证平台需要提供可配置的时钟生成和复位控制方便调试。第二接口要匹配。原始芯片的接口电平、协议、时序可能和FPGA开发板不同。需要设计接口转换电路或者用FPGA的IO资源做电平匹配和协议转换。第三观测点要充足。FPGA内部信号很难直接观测需要把关键信号引出到IO或者用集成逻辑分析仪ILA抓取。ILA的采样深度和触发条件要提前规划好否则跑起来之后发现抓不到想要的信号就得重新综合。第四测试向量要覆盖关键路径。逆向验证不需要穷举所有输入但需要覆盖设计的关键功能路径。测试向量的设计要结合逆向出来的状态转移图和数据通路结构确保每个主要状态和运算模式都被触发到。6.3 从FPGA验证结果反哺逆向分析FPGA验证不只是“确认对错”它还能反哺逆向分析。具体来说如果某个模块在FPGA上跑出来的行为和你逆向理解的不一致这个不一致本身就是线索。它告诉你你遗漏了某个条件分支或者误解了某个控制信号。如果某个模块在FPGA上根本无法正常工作比如时序不满足可能说明你逆向出来的逻辑结构有问题需要重新检查网表。如果某个模块的行为在不同输入下表现出你未曾预料到的模式这可能揭示了一个隐藏的功能或者工作模式。我在一个DDR控制器逆向项目里就遇到过这种情况。逆向出来的RTL在FPGA上跑的时候大部分读写操作都正常但在特定地址序列下会出现数据错误。追查之后发现原始设计里有一个地址对齐检查逻辑我们在逆向时把它当成了普通的地址译码逻辑忽略了它的对齐检查功能。修正之后问题消失。7. 逆向报告的撰写怎么把分析结果变成可交付的文档7.1 逆向报告的核心结构逆向分析的最终产出是一份报告。这份报告的质量决定了你的分析成果能不能被别人理解和使用。我写过的逆向报告核心结构包括第一部分设计概览。包括设计的整体功能、主要模块划分、时钟域分布、接口定义。这部分是给读者建立全局认知的。第二部分模块详细分析。每个模块一节包括功能描述、接口定义、内部结构、状态机描述、数据通路描述、关键信号说明。这部分是报告的主体。第三部分验证结果。包括仿真验证、FPGA验证、等价性检查的结果和结论。这部分是给报告的可信度背书的。第四部分未解问题和假设。逆向不可能100%还原所有细节总有一些地方是推断的或者不确定的。这部分要明确列出哪些是确定的、哪些是推断的、哪些是未知的。7.2 怎么用LLM辅助报告撰写写报告是一件很耗时的事情尤其是模块详细分析部分每个模块都要写功能描述、接口说明、内部结构。LLM在这个环节可以帮上忙。我的做法是把前面分析阶段积累的结构化数据模块特征、状态转移图、数据通路描述、LLM的功能推断整理成结构化的输入让LLM生成报告草稿。然后我人工审核和修正。这样能把写报告的时间压缩一半以上。但要注意LLM生成的报告草稿不能直接交付。必须人工审核每一个技术细节确保没有幻觉和错误。尤其是状态转移图和接口定义这种精确信息LLM很容易搞错。7.3 报告的可复现性设计一份好的逆向报告应该让读者能够复现你的分析过程。这意味着报告里要包含使用的工具和版本分析脚本和提示词模板关键中间结果的存储位置验证环境的配置说明我在报告里通常会附一个“复现指南”章节列出从原始网表到最终结论的完整步骤。这样即使换一个人来做也能按照同样的流程得到同样的结果。8. 一些踩过的坑和实际体会IC逆向这件事理论框架再漂亮实际操作中还是会遇到各种意想不到的问题。下面这几个坑是我自己踩过的写出来给后来者省点时间。第一个坑过度依赖自动化工具。刚开始做逆向的时候我总想找一个“一键逆向”的工具输入网表输出RTL。试了好几个没有一个能用的。后来想明白了逆向的本质是理解理解这件事没有捷径。工具能帮你做结构分析、模式识别、语义推断但最终的判断和验证必须靠人。把工具当作助手而不是替代品。第二个坑忽略设计的应用背景。有一次逆向一个通信接口芯片我埋头分析了三天网表状态机、数据通路都理清楚了但就是不明白为什么要这么设计。后来查了应用笔记才知道这个芯片用于某种特定的工业总线它的状态机设计是为了满足总线的时序要求。如果一开始就知道这个背景分析会快很多。所以在开始逆向之前尽可能收集设计的应用背景信息哪怕只是一句“这是用于某某场景的芯片”都能帮你少走弯路。第三个坑LLM的幻觉在逆向场景里特别危险。LLM在生成文本的时候会“自信地”编造出不存在的东西。在逆向场景里它可能编造出一个不存在的状态转移或者把一个模块的功能描述得完全错误。如果你没有验证就采信后面的分析全都会跑偏。我的做法是LLM的每一个输出都必须有对应的网表证据支持。如果LLM说“这个模块是一个FIR滤波器”我会去检查它的DSP配置和寄存器反馈路径看是否真的符合FIR的结构。没有证据支持的推断一律标记为“待验证”。第四个坑时间分配不合理。逆向一个中等规模的设计时间应该怎么分配我的经验是结构预处理和模块划分占20%状态机和数据通路分析占40%验证占30%报告撰写占10%。很多人把80%的时间花在分析上验证和报告草草了事结果分析出来的东西没人能看懂也没人敢用。验证和报告的时间和分析时间同等重要。第五个坑忽视版本管理。逆向过程中会产生大量的中间文件预处理脚本、连接图、社区发现结果、LLM输入输出、验证波形、报告草稿。这些东西如果没有版本管理过两周你自己都找不到哪个是最新的。我用Git管理所有分析脚本和报告用DVC管理大的中间文件连接图、波形文件。这个习惯帮我省了很多麻烦。最后说一个我自己的体会IC逆向这个方向正在从“手工艺”变成“工程”。以前靠师傅带徒弟、靠个人经验现在有了系统化的方法论、自动化的工具、LLM的辅助效率在快速提升。但核心能力没有变对数字电路设计的深刻理解、对细节的耐心追踪、对结论的严格验证。工具再好这三样东西还是得自己有。那篇TCHES综述的价值不在于它提出了什么革命性的算法而在于它把这个领域的方法论梳理清楚了让后来者有一个可以遵循的框架。我在上面分享的这些实操经验就是在这个框架下填进去的具体内容。希望能对做类似工作的朋友有所帮助。