Page 14 - 《软件学报》2026年第6期
P. 14

李玉璋 等: BinDec: 面向  RISC-V  的  LLM  与符号执行协同反编译方法                                 2333


                    由于  LLM  本身存在固有的不确定性, 即使其输出的             IR  代码可通过编译, 仍无法保证其与原始二进制代码在
                 功能上完全一致. 为确保语义一致性, BinDec 采用基于符号执行的单元测试方法对生成的                         IR  进行验证. 首先, 为
                 提升后的   IR  函数生成一个包含      main  函数的可执行程序     (称为产品程序, 如图     3  所示). 该  main  函数包括对目标函
                 数参数的符号化声明、函数调用以及运行结果输出等部分, 其生成基于对目标函数的签名分析和预设的产品程序
                 模板. 需要注意的是, 目标函数可能调用外部函数. 由于               BinDec 以函数粒度运行, 一种直接的处理方式是按照调用
                 顺序依次处理各函数, 以确保外部函数已被提前反编译. 然而, 这种方式可能导致外层函数涉及复杂的调用关系,
                 显著增加符号执行的复杂度. 为此, 本文采用简化外部函数建模的策略, 参考已有研究                          [19] 将外部函数定义为直接
                 返回所有参数最低字节之和. 与实际函数定义相比, 该方法大幅提升了符号执行的效率; 同时, 由于所有参数均被
                 使用, 避免了因路径中断而影响符号执行的准确性. 随后, 对产品程序进行符号执行, 并根据搜索到的路径生成多
                 个测试用例. 接下来, 将产品程序编译为           RISC-V  目标二进制程序, 并通过二进制注入技术将其中的                main  函数及
                 所有模拟的外部函数定义注入原始二进制程序中, 从而实现对原始二进制代码中对应函数的独立执行. 最后, 分别
                 运行产品程序与注入后的原始二进制程序, 通过对比不同测试用例下的函数返回值, 判断提升后的                               IR  代码与原始
                 二进制代码的语义是否一致. 若出现返回值不一致或执行崩溃, 则判定为语义不一致, 此时丢弃当前提升结果, 重
                 新请求   LLM  生成  IR  代码并重复上述验证流程, 直至获得在测试集上完全等价的结果或达到最大尝试次数.
















                                              图 3 用于单元测试的产品程序示例

                  2.3   中间代码反编译
                    在基于第    2.1  节方法获得可编译且语义与原始二进制代码一致的                IR  代码后, BinDec 进一步将其反编译为       C
                 代码. 本节将介绍从      IR  代码反编译为   C  代码的具体过程, 主要包括       LLM  查询、C   语言代码重编译以及语义验证
                 这  3  个步骤.
                    本阶段仍以     LLM  为核心, 利用其代码生成能力实现从中间代码到高级语言表示的转换. 与二进制代码提升阶
                 段不同, 本阶段的输入为        IR  代码. 由于  IR  代码具有平台无关性且具备一定的可读性, 因此相比二进制代码更易
                 于  LLM  理解. 为进一步降低    LLM  理解  IR  代码的难度, BinDec 首先对输入的     IR  代码进行规范化处理. 具体做法
                 包括将变量和标签全部匿名化           (即统一表示为类似“%1”的无命名形式), 并移除所有非必要的函数和变量属性信
                 息  (例如用于指导代码优化的属性). 在常规编译流程中, 这类命名和属性信息通常由编译器前端生成, 以维持可读
                 性或指导后续优化步骤. 然而, 对于通过           LLM  从二进制代码提升得到的         IR  代码, 此类信息往往不准确甚至无意
                 义. 移除这些信息有助于降低         LLM  的理解负担, 并减少错误信息带来的干扰. 随后, BinDec 基于规范化后的                IR  代
                 码片段构造提示词, 要求       LLM  生成具备可读性的      C  代码. 对于  LLM  输出的  C  代码, BinDec 采用与二进制代码提
                 升阶段类似的方法进行可编译性修复, 即通过               C  编译器对代码进行编译, 并根据编译器报错信息构造提示词引导
                 LLM  迭代修复代码, 直至生成语法正确、可编译的              C  代码或达到预设的最大尝试次数.
                    为保障反编译所得       C  代码与输入   IR  代码之间的语义一致性, BinDec 在本阶段继续采用符号执行技术进行等
                 价性检验. 但与前一阶段不同的是, 本阶段不再依赖由符号执行生成的具体测试用例进行具体执行, 而是完全在符
                 号执行框架下完成判别. 该方法可减少等价性检查的步骤, 从而提升验证效率. 这一差异源于符号执行技术的适用
   9   10   11   12   13   14   15   16   17   18   19