开源项目LLM4Decompile用大语言模型辅助反汇编分析,为逆向工程和安全研究提供新工具。适合做代码分析和安全审计的程序员。
📊 结果 | 🤗 模型 | 🚀 快速开始 | 📚 HumanEval-Decompile | 📎 引用 | 📝 论文 | 🖥️ Colab | ▶️ YouTube
[2025-10-04]:发布 SK²Decompile:一种基于 LLM、从骨架到皮肤的两阶段二进制反编译方法。阶段 1,结构恢复(骨架):将二进制代码/伪代码转换为经过混淆的中间表示 🤗 HF Link。阶段 2,标识符命名(皮肤):生成带有语义化标识符、便于人类阅读的源代码 🤗 HF Link。
[2025-05-20]:发布 decompile-bench,其中包含用于训练的 200 万组二进制代码—源代码函数对,以及用于评估的 7 万组函数对。详情请参阅 decompile-bench 文件夹。
[2024-10-17]:发布 decompile-ghidra-100k,这是一个包含 10 万条训练样本的子集,每种优化级别各 2.5 万条。我们提供了一份训练脚本,在单张 A100 40G GPU 上运行约 3.5 小时即可完成训练。其可重新执行率达到 0.26,总成本不到 20 美元,便于快速复现 LLM4Decompile。
[2024-09-26]:更新 Colab notebook,演示 LLM4Decompile 模型的用法,其中包括 LLM4Decompile-End 和 LLM4Decompile-Ref 模型的示例。
[2024-09-23]:发布 LLM4Decompile-9B-v2。该模型基于 Yi-Coder-9B 微调,在 Decompile benchmark 上实现了 0.6494 的可重新执行率。
[2024-06-19]:发布 V2 系列(LLM4Decompile-Ref)。V2 系列模型规模覆盖 1.3B~22B,构建于 Ghidra 之上,使用 20 亿 token 进行训练,用于优化 Ghidra 反编译出的伪代码。22B-V2 版本的表现比 6.7B-V1.5 又提升了 40.1%。详情请查看 ghidra 文件夹。
[2024-05-13]:发布 V1.5 系列(LLM4Decompile-End,使用 LLM 直接反编译二进制代码)。V1.5 使用更大的数据集(150 亿 token)训练,最大 token 长度为 4,096;与上一版本模型相比,性能提升显著,超过 100%。
[2024-03-16]:新增 llm4decompile-6.7b-uo 模型。该模型在训练时不预先提供优化级别(O0~O3)信息,平均可重新执行率约为 0.219,是我们所有模型中表现最好的。
LLM4Decompile 是首个专门用于反编译的开源大语言模型。当前版本支持将采用 GCC O0~O3 优化级别的 Linux x86_64 二进制代码反编译为便于人类阅读的 C 源代码。我们的团队致力于持续扩展这一工具的能力,目前正在努力支持更多架构和配置。
LLM4Decompile-End 专注于直接反编译二进制代码。LLM4Decompile-Ref 则用于优化 Ghidra 反编译出的伪代码。
在编译过程中,Preprocessor 首先处理源代码(SRC),删除注释并展开宏或 include。清理后的代码随后被送入 Compiler,由其转换为汇编代码(ASM)。接着,Assembler 将 ASM 转换成二进制代码(0 和 1)。最后,Linker 通过链接函数调用完成整个流程,生成可执行文件。反编译则是相反的过程,即把二进制代码转换回源文件。由于 LLM 基于文本训练,无法直接处理二进制数据,因此必须先通过 Objdump 将二进制文件反汇编成汇编语言(ASM)。需要说明的是,二进制代码与反汇编得到的 ASM 是等价的,两者可以相互转换,因此本文会交替使用这两个概念。最后,通过计算反编译代码与源代码之间的 loss 来指导训练。为了评估反编译代码(SRC')的质量,我们会使用测试断言检验其功能,也就是评估可重新执行性。
可重新执行性用于评估反编译代码能否正常执行,并通过所有预定义的测试用例。
HumanEval-Decompile:由 164 个 C 函数组成,这些函数仅依赖标准 C 库。
ExeBench:由来自真实项目的 2,621 个函数组成,每个函数都会使用用户自定义函数、结构体和宏。
LLM4Decompile 包含参数规模从 13 亿到 330 亿不等的模型,我们已经在 Hugging Face 上公开了这些模型。
注 3:V1.5 系列使用更大的数据集(150 亿 token)训练,最大 token 大小为 4,096;与上一版本模型相比,性能提升显著,超过 100%。
注 4:V2 系列构建于 Ghidra 之上,使用 20 亿 token 进行训练,用于优化 Ghidra 反编译出的伪代码。详情请查看 ghidra 文件夹。
请使用下面的脚本安装所需环境。
git clone https://github.com/albertan017/LLM4Decompile.git
cd LLM4Decompile
conda create -n 'llm4decompile' python=3.9 -y
conda activate llm4decompile
pip install -r requirements.txt
下面是使用我们模型的示例(已针对 V1.5 修订。对于之前的模型,请查看 HF 上对应的模型页面)。注意:请将 "func0" 替换为你想要反编译的函数名。
将 C 代码编译成二进制文件,再把二进制文件反汇编成汇编指令。
import subprocess
import os
func_name = 'func0'
OPT = ["O0", "O1", "O2", "O3"]
fileName = 'samples/sample' #'path/to/file'
for opt_state in OPT:
output_file = fileName +'_' + opt_state
input_file = fileName+'.c'
compile_command = f'gcc -o {output_file}.o {input_file} -{opt_state} -lm'#compile the code with GCC on Linux
subprocess.run(compile_command, shell=True, check=True)
compile_command = f'objdump -d {output_file}.o > {output_file}.s'#disassemble the binary file into assembly instructions
subprocess.run(compile_command, shell=True, check=True)
input_asm = ''
with open(output_file+'.s') as f:#asm file
asm= f.read()
if '<'+func_name+'>:' not in asm: #IMPORTANT replace func0 with the function name
raise ValueError("compile fails")
asm = '<'+func_name+'>:' + asm.split('<'+func_name+'>:')[-1].split('\n\n')[0] #IMPORTANT replace func0 with the function name
asm_clean = ""
asm_sp = asm.split("\n")
for tmp in asm_sp:
if len(tmp.split("\t"))<3 and '00' in tmp:
continue
idx = min(
len(tmp.split("\t")) - 1, 2
)
tmp_asm = "\t".join(tmp.split("\t")[idx:]) # remove the binary code
tmp_asm = tmp_asm.split("#")[0].strip() # remove the comments
asm_clean += tmp_asm + "\n"
input_asm = asm_clean.strip()
before = f"# This is the assembly code:\n"#prompt
after = "\n# What is the source code?\n"#prompt
input_asm_prompt = before+input_asm.strip()+after
with open(fileName +'_' + opt_state +'.asm','w',encoding='utf-8') as f:
f.write(input_asm_prompt)
汇编指令应采用以下格式:
<FUNCTION_NAME>:\nOPERATIONS\nOPERATIONS\n
典型的汇编指令可能如下所示:
<func0>:
endbr64
lea (%rdi,%rsi,1),%eax
retq
使用 LLM4Decompile 将汇编指令转换成 C:
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
model_path = 'LLM4Binary/llm4decompile-6.7b-v1.5' # V1.5 Model
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(model_path,torch_dtype=torch.bfloat16).cuda()
with open(fileName +'_' + OPT[0] +'.asm','r') as f:#optimization level O0
asm_func = f.read()
inputs = tokenizer(asm_func, return_tensors="pt").to(model.device)
with torch.no_grad():
outputs = model.generate(**inputs, max_new_tokens=2048)### max length to 4096, max new tokens should be below the range
c_func_decompile = tokenizer.decode(outputs[0][len(inputs[0]):-1])
with open(fileName +'.c','r') as f:#original file
func = f.read()
print(f'original function:\n{func}')# Note we only decompile one function, where the original file may contain multiple functions
print(f'decompiled function:\n{c_func_decompile}')
# build docker
docker build -t llm4decompile .
# run docker with GPU
docker run --gpus all -it --name llm4decompile llm4decompile /bin/bash
# run demo.py (choose a model suitable for your resources before running)
cd ghidra
python demo.py
数据存储在 llm4decompile/decompile-eval/decompile-eval-executable-gcc-obj.json 中,采用 JSON 列表格式。其中共有 164×4 个样本,分别对应 O0、O1、O2、O3,每个样本包含五个 key:
task_id:表示题目的 ID。
type:优化阶段,是 [O0, O1, O2, O3] 之一。
c_func:HumanEval 问题的 C 语言解法。
c_test:C 测试断言。
input_asm_prompt:带 prompt 的汇编指令,可以按照我们的预处理示例生成。
请查看评估脚本。
提供经过清理流程处理的更大规模训练数据集。(已完成:2024.05.13)
支持主流语言、平台和配置。
支持可执行二进制文件。(已完成:2024.05.13)
集成反编译工具,例如 Ghidra、Rizin。
本代码仓库采用 MIT License 和 DeepSeek License。
@misc{tan2024llm4decompile,
title={LLM4Decompile: Decompiling Binary Code with Large Language Models},
author={Hanzhuo Tan and Qi Luo and Jing Li and Yuqun Zhang},
year={2024},
eprint={2403.05286},
archivePrefix={arXiv},
primaryClass={cs.PL}
}