
الهندسة العكسية: تفكيك الكود الثنائي باستخدام نماذج اللغة الكبيرة
📊 النتائج | 🤗 النماذج | 🚀 بدء سريع | 📚 HumanEval-Decompile | 📎 الاستشهاد | 📝 الورقة البحثية | 🖥️ Colab | ▶️ YouTube
الهندسة العكسية: فك ترجمة الكود الثنائي باستخدام نماذج اللغة الكبيرة
أثناء الترجمة، يعالج المعالج الأولي (Preprocessor) الكود المصدري (SRC) لإزالة التعليقات وتوسيع وحدات الماكرو (macros) أو التضمينات (includes). ثم يُمرَّر الكود المنظف إلى المترجم (Compiler)، الذي يحوّله إلى كود تجميع (ASM). يحوّل المجمّع (Assembler) كود التجميع هذا إلى كود ثنائي (0 و1). يُنهي الرابط (Linker) العملية بربط استدعاءات الدوال لإنشاء ملف قابل للتنفيذ. أما فك الترجمة فيتضمن تحويل الكود الثنائي مرة أخرى إلى ملف مصدري. وبما أن نماذج اللغة الكبيرة مُدرَّبة على النصوص، فإنها تفتقر إلى القدرة على معالجة البيانات الثنائية مباشرة. لذلك، يجب أولًا تفكيك الملفات الثنائية بواسطة Objdump إلى لغة تجميع (ASM). تجدر الإشارة إلى أن الكود الثنائي ولغة التجميع المُفكَّكة متكافئان ويمكن التحويل بينهما، ولهذا نشير إليهما بالتبادل. وأخيرًا، يُحسب الفقد (loss) بين الكود المُفكَّك والكود المصدري لتوجيه التدريب. ولتقييم جودة الكود المُفكَّك (SRC')، يُختبر أداؤه الوظيفي من خلال تأكيدات الاختبار (قابلية إعادة التنفيذ).
تشمل LLM4Decompile نماذج بأحجام تتراوح بين 1.3 مليار و33 مليار معامل، وقد أتاحنا هذه النماذج على Hugging Face.
ملاحظة 3: تم تدريب سلسلة V1.5 على مجموعة بيانات أكبر (15 مليار رمز) وبحد أقصى لحجم الرموز يبلغ 4,096، مع أداء ملحوظ (تحسن بأكثر من 100%) مقارنة بالنموذج السابق.
ملاحظة 4: سلسلة V2 مبنية على Ghidra ومُدرَّبة على ملياري رمز لـتحسين شبه الكود المُفكَّك من 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) عينة، تحتوي كل عينة على خمسة مفاتيح:
task_id: يشير إلى معرف (ID) المسألة.type: مرحلة التحسين، وهي إحدى القيم [O0, O1, O2, O3].c_func: حل C لمسألة HumanEval.c_test: تأكيدات اختبار C.input_asm_prompt: تعليمات لغة التجميع مع المطالبات (prompts)، ويمكن اشتقاقها كما في مثال المعالجة المسبقة الخاص بنا.يُرجى مراجعة نصوص التقييم.
هذا المستودع البرمجي مرخَّص بموجب رخصة 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}
}
| النموذج | Checkpoint | الحجم | قابلية إعادة التنفيذ | ملاحظة |
|---|
| 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 |