📊 结果 | 🤗 模型 | 🚀 快速开始 | 📚 HumanEval-Decompile | 📎 引用 | 📝 论文 | 🖥️ Colab | ▶️ YouTube
逆向工程:利用大型语言模型反编译二进制代码
在编译过程中,预处理器(Preprocessor)处理源代码(SRC)以去除注释并展开宏或包含的头文件。清理后的代码随后被传递给编译器(Compiler),编译器将其转换为汇编代码(ASM)。汇编器(Assembler)再将该 ASM 转换为二进制代码(0 和 1)。链接器(Linker)通过链接函数调用来完成最后一步,生成可执行文件。反编译则是将二进制代码转换回源文件的过程。由于 LLM 是在文本上训练的,它们不具备直接处理二进制数据的能力。因此,二进制文件必须先由 Objdump 反汇编为汇编语言(ASM)。需要注意的是,二进制与反汇编后的 ASM 是等价的,它们可以相互转换,因此我们会互换使用这两个术语。最后,在反编译代码与源代码之间计算损失以指导训练。为了评估反编译代码(SRC')的质量,需要通过测试断言(可重执行性)来检验其功能。
我们的 LLM4Decompile 系列包含参数规模从 13 亿到 330 亿不等的模型,并已将这些模型发布在 Hugging Face 上。
注释 3:V1.5 系列使用更大的数据集(15B token)和最大 4,096 的 token 长度进行训练,与之前的模型相比性能显著提升(提升超过 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
数据以 JSON 列表格式存储在 llm4decompile/decompile-eval/decompile-eval-executable-gcc-obj.json 中。共有 164*4(O0、O1、O2、O3)个样本,每个样本包含五个键:
task_id:表示问题 ID。type:优化阶段,取值为 [O0, O1, O2, O3] 之一。c_func:HumanEval 问题的 C 语言解决方案。c_test:C 语言测试断言。input_asm_prompt:带有提示词的汇编指令,可按照我们的预处理示例生成。请查看评估脚本。
本代码仓库采用 MIT 和 DeepSeek 许可证。
@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}
}
| 模型 | 检查点 | 参数规模 | 可重执行率 | 备注 |
|---|
| llm4decompile-1.3b-v1.5 | 🤗 HF 链接 | 1.3B | 27.3% | 注释 3 |
| llm4decompile-6.7b-v1.5 | 🤗 HF 链接 | 6.7B | 45.4% | 注释 3 |
| llm4decompile-1.3b-v2 | 🤗 HF 链接 | 1.3B | 46.0% | 注释 4 |
| llm4decompile-6.7b-v2 | 🤗 HF 链接 | 6.7B | 52.7% | 注释 4 |
| llm4decompile-9b-v2 | 🤗 HF 链接 | 9B | 64.9% | 注释 4 |
| llm4decompile-22b-v2 | 🤗 HF 链接 | 22B | 63.6% | 注释 4 |