📊 结果 | 🤗 模型 | 🚀 快速开始 | 📚 HumanEval-Decompile | 📎 引用 | 📝 论文 | 🖥️ Colab | ▶️ YouTube
逆向工程:利用大型语言模型反编译二进制代码
在编译过程中,预处理器(Preprocessor)处理源代码(SRC)以去除注释并展开宏或包含的头文件。清理后的代码随后被传递给编译器(Compiler),编译器将其转换为汇编代码(ASM)。汇编器(Assembler)再将该 ASM 转换为二进制代码(0 和 1)。链接器(Linker)通过链接函数调用来完成最后一步,生成可执行文件。反编译则是将二进制代码转换回源文件的过程。由于 LLM 是在文本上训练的,它们不具备直接处理二进制数据的能力。因此,二进制文件必须先由 Objdump 反汇编为汇编语言(ASM)。需要注意的是,二进制与反汇编后的 ASM 是等价的,它们可以相互转换,因此我们会互换使用这两个术语。最后,在反编译代码与源代码之间计算损失以指导训练。为了评估反编译代码(SRC')的质量,需要通过测试断言(可重执行性)来检验其功能。
我们的 LLM4Decompile 系列包含参数规模从 13 亿到 330 亿不等的模型,并已将这些模型发布在 Hugging Face 上。
| 模型 | 检查点 | 参数规模 | 可重执行率 | 备注 |
|---|---|---|---|---|
| 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 |
注释 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