☰
SK²Decompile 在 BringUpBench 上的反编译评估:从编译到函数级验证的完整复现指南
2026/10/2 2:09:24 网站建设 项目流程
  • 人工智能
  • 大模型
  • 逆向工程
  • 微调
  • 代码模型

【免费下载链接】LLM4Decompile

Reverse Engineering: Decompiling Binary Code with Large Language Models

项目地址:https://gitcode.com/GitHub_Trending/ll/LLM4Decompile
点击查看免费下载

本文聚焦于 LLM4Decompile 项目中 SK²Decompile 的两阶段反编译框架在BringUpBench基准上的完整评估流水线(论文 Section A.6)。你将掌握:为什么 BringUpBench 适合评估复杂真实二进制、SK²Decompile 与 IDA Pro 的量化对比结果、从编译 O0–O3 到 IDA 反编译、函数级映射、模型推理再到可执行性验证的五步复现方法,以及func_map.jsonl数据格式与 Replacement / Compilable / Executable 三类指标的定义和源码级实现细节。

一、为什么用 BringUpBench 评估反编译

BringUpBench(Austin, 2024)是一个包含90 个自包含 C 程序的基准套件,最初用于新设计的 CPU、加速器、编译器和操作系统的 bring-up 验证。它对反编译评估有三个天然优势:

  1. 零外部库依赖:所有程序只依赖内置的libmin库,且仅使用 4 个系统调用;
  2. 自带构建与测试基础设施:每个程序都有Makefile、libmin、libtarg,可直接用于"编译 → 运行 → 校验"闭环;
  3. 消除干扰因素:由于不存在缺失头文件或库的混淆因素,评估结果能直接反映反编译输出的代码质量,而非依赖环境的可复现性。

SK²Decompile 团队在 O0–O3 四个优化级别上对所有 90 个程序完成编译、反编译与执行验证,共获得505 个函数,并与行业标准的规则式反编译器IDA Pro(Hex-Rays)进行了对比。相关论文为《SK²Decompile: LLM-based Two-Phase Binary Decompilation from Skeleton to Skin》(arXiv:2509.22114)。

二、量化结果:SK²Decompile vs IDA Pro

核心结果保存在 reports/ 目录下,汇总如下:

Opt LevelFunctionsSK²Decompile CompilableSK²Decompile ExecutableIDA CompilableIDA Executable
O038250.26%49.48%——
O137940.90%39.05%——
O236837.77%34.24%——
O335931.75%29.53%——
Avg148842.3%27.0%23.6%21.7%

需要说明两点(与原文档一致):

  • 平均值一行取自论文 Section A.6 的 Table 8 汇总数字;各优化级别下 IDA 的基线未在论文中单独报告;
  • 每个基准的逐项细分结果可查阅reports/下的O0_results.md、O1_results.md、O2_results.md、O3_results.md。

以 O0_results.md 为例,它记录了 2025-11-19 的运行:共 382 个案例,Replacement success 382(100.00%)、Compilable 192(50.26%)、Executable 189(49.48%),并给出了 ackermann、aes、anagram 等 90 个基准逐项的 Replacement% / Build% / Exec% 明细,以及编译失败与执行失败的具体函数清单(如ackermann/ackermann.c::main@0x13b9)。这些报告由下文 Step 5 的评估脚本自动生成,格式可直接对照阅读。

三、目录结构与数据资产

sk2decompile/evaluation/bringupbench/ ├── README.md # 本文档 ├── config.env # 环境配置(路径) ├── scripts/ │ ├── build-host-opt-levels.sh # Step 1: 以 O0-O3 编译基准 │ ├── decompile-all-pseudo.sh # Step 2: IDA Pro 批量反编译 │ ├── dump_pseudo.py # IDA 无头模式反编译辅助脚本 │ ├── disasm-all-objdump.sh # Step 3: objdump 批量反汇编 │ ├── build-func-maps.py # Step 4: 构建函数级映射 │ ├── clean-all-benchmarks.sh # 工具: 清理所有构建产物 │ └── eval_infer_out.py # Step 5: 自动化评估 ├── data/ │ ├── func_maps/ # 预构建的函数映射 (JSONL) │ │ ├── merged.O0.func_map.jsonl # O0: 493 functions │ │ ├── merged.O1.func_map.jsonl # O1: 449 functions │ │ ├── merged.O2.func_map.jsonl # O2: 441 functions │ │ └── merged.O3.func_map.jsonl # O3: 439 functions │ └── infer_results/ # SK²Decompile 推理结果 │ ├── merged.O0.func_map.infer.jsonl # O0: 382 evaluated functions │ ├── merged.O1.func_map.infer.jsonl # O1: 379 evaluated functions │ ├── merged.O2.func_map.infer.jsonl # O2: 368 evaluated functions │ └── merged.O3.func_map.infer.jsonl # O3: 359 evaluated functions └── reports/ # 评估结果汇总 ├── O0_results.md ├── O1_results.md ├── O2_results.md └── O3_results.md

注意:func_maps/中的函数数量多于infer_results/(如 O0 的 493 → 382),原因是在推理阶段部分函数被过滤(例如超出 token 上限),这一点在"注意事项"一节会进一步说明。

四、五步评估流水线总览

整个评估流水线按论文描述分为五个步骤:

Source (.c) │ ▼ Step 1: Compilation Binary (.host.O0 ~ .host.O3) │ ├──▶ Step 2: Baseline Extraction (IDA Pro) ──▶ Pseudocode (.pseudo) │ ├──▶ Step 3: Ground Truth Mapping ──▶ Function Maps (.func_map.jsonl) │ ▼ Step 4: Decompilation (SK²Decompile) Inferred C code (.func_map.infer.jsonl) │ ▼ Step 5: Validation Evaluation Reports (reports/)

每一步都有对应的脚本(见 scripts/),下文将结合脚本源码逐一展开。

环境配置:config.env 与路径优先级

所有脚本统一从 config.env 读取路径,支持环境变量与命令行参数覆盖。路径解析优先级为:CLI 参数 > 环境变量 > config.env。

# BringUpBench Evaluation — Environment Configuration # 所有脚本从该文件解析路径,可由同名环境变量或 CLI 参数覆盖 # Bringup-Bench 仓库的绝对路径 # 克隆自上游仓库: git clone https://github.com/toddmaustin/bringup-bench.git BENCH_REPO_ROOT=/path/to/bringup-bench # IDA Pro 命令行可执行文件(Step 2 反编译必需) IDA_BIN=/path/to/idat # 默认构建目标(host = 本机 x86-64 Linux) DEFAULT_TARGET=host

以 eval_infer_out.py 的_get_bench_root()为例,其解析顺序正是"CLI 参数 → 环境变量BENCH_REPO_ROOT→ config.env",三者都未设置时直接报错退出,确保路径不会静默回退到错误位置。

五、快速开始:仅复现评估步骤(Step 5)

如果你只关心评估(Step 5),预构建数据已包含在data/中,只需额外准备 BringUpBench 源码仓库:

# 1. 克隆 BringUp-Bench git clone https://github.com/toddmaustin/bringup-bench.git # 2. 配置路径 cd bringupbench vim config.env # 将 BENCH_REPO_ROOT 设为你的 bringup-bench 路径 # 3. 运行评估(以 O0 为例) python3 scripts/eval_infer_out.py data/infer_results/merged.O0.func_map.infer.jsonl # 4. 查看结果 cat reports/O0_results.md

六、完整流水线复现(从零开始)

先配置环境:

cd bringupbench vim config.env # 设置 BENCH_REPO_ROOT 与 IDA_BIN

Step 1:以 O0–O3 编译基准

build-host-opt-levels.sh 会在BENCH_REPO_ROOT下以四个优化级别构建全部 90 个程序,产物为<name>.host.O{0,1,2,3}二进制:

scripts/build-host-opt-levels.sh

脚本源码要点:

  • 使用set -euo pipefail保证失败即停,避免残留半成品产物;
  • 加载 config.env 并允许环境变量覆盖(source前set -a,使变量导出到子进程);
  • 对每个优化级别执行make TARGET=host OPT_CFLAGS="-O${opt} -g" run-tests(注意-g保留调试信息,run-tests同时验证编译产物可运行);
  • 随后用find ... -name '*.host' -execdir mv {} {}.O${opt}将产物重命名为带优化级别后缀的二进制。

Step 2:基线提取(IDA Pro)

使用 IDA Pro 无头模式(headless)批量反编译所有二进制,产出包含 Hex-Rays 伪代码的.pseudo文件:

scripts/decompile-all-pseudo.sh

该脚本遍历BENCH_REPO_ROOT下所有*.o0/*.o1/*.o2/*.o3文件(排除scripts/、target/、common/、.git/),对每个二进制调用:

"${IDA_BIN}" -A "-S${DUMP_SCRIPT} ${output_path}" "${binary_path}"

其中-A表示自动模式(不弹对话框),-S指定启动脚本。真正的反编译逻辑在 dump_pseudo.py 中:

  • 通过idc.ARGV[1]获取输出路径;
  • 调用ida_auto.auto_wait()等待自动分析完成,再通过ida_hexrays.init_hexrays_plugin()确认 Hex-Rays 可用;
  • 遍历idautils.Functions(),对每个函数用ida_hexrays.decompile(ea)反编译,输出格式为:
/* function_name @ 0xADDRESS */ ... Hex-Rays pseudocode ...

即以/* 函数名 @ 0x地址 */作为每个函数的分隔标记,供 Step 3 解析使用。

Step 3:Ground Truth 映射

解析源码、伪代码与汇编三种表示,按函数名跨表示匹配;同时规范化伪代码(去除 IDA 特有类型、十六进制转十进制、clang-format 格式化):

# 反汇编(可选,用于汇编映射) scripts/disasm-all-objdump.sh # 构建函数级映射 python3 scripts/build-func-maps.py

disasm-all-objdump.sh 默认使用系统objdump(可用OBJDUMP环境变量覆盖),并以xargs -P按 CPU 核数并行反汇编,每个二进制输出同名.s文件。

构建完成后按优化级别合并为单一 JSONL:

cat $BENCH_REPO_ROOT/*/*.host.O0.func_map.jsonl > data/func_maps/merged.O0.func_map.jsonl cat $BENCH_REPO_ROOT/*/*.host.O1.func_map.jsonl > data/func_maps/merged.O1.func_map.jsonl cat $BENCH_REPO_ROOT/*/*.host.O2.func_map.jsonl > data/func_maps/merged.O2.func_map.jsonl cat $BENCH_REPO_ROOT/*/*.host.O3.func_map.jsonl > data/func_maps/merged.O3.func_map.jsonl

Step 4:SK²Decompile 推理

将函数映射中的pseudo_normalize字段喂给 SK²Decompile 的两阶段推理流水线(主入口为 sk2decompile_inf.py),为每个函数产出 C 代码,并将最终反编译函数体写入 JSONL 的pseudo.content-fix字段:

# 示例: 使用主 SK²Decompile 推理流水线 cd ../ # 回到 sk2decompile/evaluation/ python3 sk2decompile_inf.py \ --dataset_path bringupbench/data/func_maps/merged.O0.func_map.jsonl \ --model_path LLM4Binary/sk2decompile-struct-6.7b \ --recover_model_path LLM4Binary/sk2decompile-ident-6.7b

从源码看,sk2decompile_inf.py 支持--temperature 0(默认确定性解码)、--max_total_tokens 32768、--max_new_tokens 4096、--gpu_memory_utilization 0.8等参数;两阶段推理分别对应:

  • Phase 1(结构恢复):以pseudo_normalize为输入,产出infer-out-model1;
  • Phase 2(标识符命名):以 Phase 1 输出为输入,产出infer-out-model2,并据此更新pseudo.content-fix。

Step 5:验证

对每个函数,将原源码替换为反编译输出,在隔离工作区中重建并运行项目的测试套件:

python3 scripts/eval_infer_out.py data/infer_results/merged.O0.func_map.infer.jsonl \ --jobs 16 \ --command-timeout 20

常用选项(与 eval_infer_out.py 的 argparse 定义一致):

选项含义默认值
--jobs N并行处理的工作进程数96
--command-timeout S每个 make 命令的超时秒数20(设为 0 可禁用超时)
--limit N仅处理前 N 个案例(用于调试)无
--keep-workspaces保留临时构建目录默认删除
--bench-root覆盖 Bringup-Bench 仓库根路径从 config.env
--target构建目标(作为TARGET=<target>传入 make)host
--report-dir汇总报告输出目录(相对 eval 根)reports/infer_out_eval
--skip-clean跳过工作区内的make clean默认执行 clean

该脚本的评估流程(源码可查 eval_infer_out.py)值得重点关注:

  1. 函数替换:replace_function_body()在完整源码中精确查找原函数文本(对换行做了规范化,并依次尝试多种候选匹配形式),替换为pseudo["content-fix"];找不到则记为replacement_failed;
  2. 隔离工作区:prepare_workspace()仅拷贝Makefile、common/、target/与对应基准目录到一个独立工作区,避免各案例相互污染,也保证不修改原始基准;
  3. 构建与执行:在工作区内依次执行make TARGET=host clean、make TARGET=host build、make TARGET=host test,全部输出写入每案例的case.log;build 失败则跳过 test,test 退出码 0 视为通过;
  4. 产物留档:每个案例目录保存case.json、modified_source.c、original_source.c、original_function.c、infer_function.c与artifacts/,便于追溯;
  5. 报告生成:compute_summary()汇总总数、Replacement / Compilable / Executable 计数与逐基准统计,write_summary()输出 JSON 与 Markdown 两份报告,格式与reports/下已有结果一致。

七、数据格式详解

func_map.jsonl(函数映射)

每行是一个 JSON 对象,包含单个函数的源码、伪代码与汇编:

{ "source": { "path": "ackermann/ackermann.c", // 源文件(相对 BENCH_REPO_ROOT) "function_name": "ackermann", // 函数名 "content": "int ackermann(int m, ...) { ... }\n" // 完整函数体 }, "pseudo": { "path": "ackermann/ackermann.host.O0.pseudo", "function_name": "ackermann", "address": "0x11e9", // 二进制中的函数地址 "label": "ackermann", "content": "__int64 __fastcall ackermann(...) { ... }\n" // 原始 IDA 伪代码 }, "pseudo_normalize": "int ackermann(...) { ... }", // 规范化后的伪代码 "binary": "ackermann/ackermann.host.O0", // 二进制文件路径 "assembly": "<ackermann>:\npush %rbp\n..." // 清理后的 objdump 输出 }

以仓库中的 merged.O0.func_map.jsonl 第一条记录(ackermann的ack函数)为例,可以直观看到三种表示:

  • source.content:原始 C 源码(含libmin_printf等libmin库调用);
  • pseudo.content:IDA 伪代码(unsigned int __cdecl ack(...),带v3等机器生成变量);
  • pseudo_normalize:规范化后文本——IDA 特有类型(__int64、__cdecl、0xFFFFFF十六进制)被转换为标准形式(unsigned long long、16777215),并对齐为 clang-format 风格,可直接送入模型;
  • assembly:对应<ack>:符号下的 x86-64 汇编文本。

func_map.infer.jsonl(推理结果)

在func_map.jsonl基础上扩展了 SK²Decompile 的推理输出:

{ // ... func_map.jsonl 的全部字段 ... "pseudo": { // ... 以上所有字段, 另加: "content-fix": "..." // 最终反编译函数(用于源码替换) }, "infer-out-model1": "...", // Phase 1(结构恢复)原始输出 "infer-out-model2": "...", // Phase 2(标识符命名)原始输出 "pseudo_normalize-fix": "..." // 修正后的规范化伪代码 }

八、评估指标定义

MetricDefinition
Replacement Rate反编译输出能够被定位并替换进原源码文件的函数占比
Compilable Rate修改后的源码能成功编译(make build)的函数占比
Executable Rate编译产物能通过其测试套件(make test,输出与参考一致)的函数占比

评估直接复用 BringUpBench 自带的构建基础设施(Makefile、libmin、libtarg)完成编译与校验;每个函数在隔离工作区中测试,防止相互污染。对应到源码实现:replacement_applied对应 Replacement,build_status == "succeeded"对应 Compilable,test_status == "succeeded"对应 Executable(见 eval_infer_out.py 的compute_summary())。

九、使用提示与注意事项

  • 零依赖优势:BringUpBench 程序完全自包含、无外部依赖,评估反编译时不会因缺失头文件或库而引入混淆因素;
  • 数据量差异:func_maps/中的函数多于infer_results/,因为推理阶段会过滤部分函数(如超出 token 上限);
  • 路径解析优先级:所有脚本从config.env加载路径,可通过环境变量或 CLI 参数覆盖,优先级为 CLI > 环境变量 > config.env;
  • 并行与超时:Step 5 默认 96 个并行 worker、每个 make 命令 20 秒超时;调试阶段建议先用--limit N --jobs 1跑通小批量;
  • 隔离验证:评估不会修改原始基准源码,所有替换与构建均在临时工作区进行,配合--keep-workspaces可保留现场用于排查;
  • 清理产物:如需重建,可运行 clean-all-benchmarks.sh 在基准仓库内执行make all-clean。

十、延伸阅读

  • SK²Decompile 完整方法论文与在 HumanEval、MBPP、ExeBench、GitHub2025 等基准上的结果,见 sk2decompile/README.md;
  • 两阶段推理入口 sk2decompile_inf.py 及其依赖的 llm_server.py;
  • 训练与强化学习(GRPO)配套资料:LLaMA-Factory 与 verl。

如果你希望在自己选定的二进制集合上复刻这套评估体系,最直接的路径是:配置config.env→ 运行build-host-opt-levels.sh编译 →decompile-all-pseudo.sh反编译 →build-func-maps.py建映射 →sk2decompile_inf.py推理 →eval_infer_out.py验证,最终用reports/下的 Markdown 报告对齐 SK²Decompile 与 IDA Pro 的 Compilable / Executable 指标。

  • 人工智能
  • 大模型
  • 逆向工程
  • 微调
  • 代码模型

【免费下载链接】LLM4Decompile

Reverse Engineering: Decompiling Binary Code with Large Language Models

项目地址:https://gitcode.com/GitHub_Trending/ll/LLM4Decompile
点击查看免费下载

相关推荐

上一篇:ERPNext开源ERP系统完整指南:中小企业数字化转型的最佳选择
下一篇:在 Pydantic AI 中使用 xAI 模型:Grok 接入、原生工具、图像生成与高级模型设置完整指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询