LLM4Decompile aims to decompile x86 assembly instructions into C. The newly released V2 series are trained with a larger dataset (2B tokens) and a maximum token length of 4,096, with remarkable performance (up to 100% improvement) compared to the previous model.
Here is an example of how to use our model (Only for V2. For previous models, please check the corresponding model page at HF).
1cd LLM4Decompile/ghidra
2wget https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_11.0.3_build/ghidra_11.0.3_PUBLIC_20240410.zip
3unzip ghidra_11.0.3_PUBLIC_20240410.zip
1apt-get update
2apt-get upgrade
3apt install openjdk-17-jdk openjdk-17-jre
1import os
2import subprocess
3from tqdm import tqdm,trange
4
5OPT = ["O0", "O1", "O2", "O3"]
6timeout_duration = 10
7
8ghidra_path = "./ghidra_11.0.3_PUBLIC/support/analyzeHeadless"#path to the headless analyzer, change the path accordingly
9postscript = "./decompile.py"#path to the decompiler helper function, change the path accordingly
10project_path = "."#path to temp folder for analysis, change the path accordingly
11project_name = "tmp_ghidra_proj"
12func_path = "../samples/sample.c"#path to c code for compiling and decompiling, change the path accordingly
13fileName = "sample"
14
15with tempfile.TemporaryDirectory() as temp_dir:
16 pid = os.getpid()
17 asm_all = {}
18 for opt in [OPT[0]]:
19 executable_path = os.path.join(temp_dir, f"{pid}_{opt}.o")
20 cmd = f'gcc -{opt} -o {executable_path} {func_path} -lm'
21 subprocess.run(
22 cmd.split(' '),
23 check=True,
24 stdout=subprocess.DEVNULL, # Suppress stdout
25 stderr=subprocess.DEVNULL, # Suppress stderr
26 timeout=timeout_duration,
27 )
28
29 output_path = os.path.join(temp_dir, f"{pid}_{opt}.c")
30 command = [
31 ghidra_path,
32 temp_dir,
33 project_name,
34 "-import", executable_path,
35 "-postScript", postscript, output_path,
36 "-deleteProject", # WARNING: This will delete the project after analysis
37 ]
38 result = subprocess.run(command, text=True, capture_output=True, check=True)
39 with open(output_path,'r') as f:
40 c_decompile = f.read()
41 c_func = []
42 flag = 0
43 for line in c_decompile.split('\n'):
44 if "Function: func0" in line:#**Replace** func0 with the function name you want to decompile.
45 flag = 1
46 c_func.append(line)
47 continue
48 if flag:
49 if '// Function:' in line:
50 if len(c_func) > 1:
51 break
52 c_func.append(line)
53 if flag == 0:
54 raise ValueError('bad case no function found')
55 for idx_tmp in range(1,len(c_func)):##########remove the comments
56 if 'func0' in c_func[idx_tmp]:
57 break
58 c_func = c_func[idx_tmp:]
59 input_asm = '\n'.join(c_func).strip()
60
61 before = f"# This is the assembly code:\n"#prompt
62 after = "\n# What is the source code?\n"#prompt
63 input_asm_prompt = before+input_asm.strip()+after
64 with open(fileName +'_' + opt +'.pseudo','w',encoding='utf-8') as f:
65 f.write(input_asm_prompt)
1undefined4 func0(float param_1,long param_2,int param_3)
2{
3 int local_28;
4 int local_24;
5
6 local_24 = 0;
7 do {
8 local_28 = local_24;
9 if (param_3 <= local_24) {
10 return 0;
11 }
12 while (local_28 = local_28 + 1, local_28 < param_3) {
13 if ((double)((ulong)(double)(*(float *)(param_2 + (long)local_24 * 4) -
14 *(float *)(param_2 + (long)local_28 * 4)) &
15 SUB168(_DAT_00402010,0)) < (double)param_1) {
16 return 1;
17 }
18 }
19 local_24 = local_24 + 1;
20 } while( true );
21}
1from transformers import AutoTokenizer, AutoModelForCausalLM
2import torch
3
4model_path = 'LLM4Binary/llm4decompile-6.7b-v2' # V2 Model
5tokenizer = AutoTokenizer.from_pretrained(model_path)
6model = AutoModelForCausalLM.from_pretrained(model_path, torch_dtype=torch.bfloat16).cuda()
7
8with open(fileName +'_' + OPT[0] +'.pseudo','r') as f:#optimization level O0
9 asm_func = f.read()
10inputs = tokenizer(asm_func, return_tensors="pt").to(model.device)
11with torch.no_grad():
12 outputs = model.generate(**inputs, max_new_tokens=2048)### max length to 4096, max new tokens should be below the range
13c_func_decompile = tokenizer.decode(outputs[0][len(inputs[0]):-1])
14
15with open(fileName +'_' + OPT[0] +'.pseudo','r') as f:#original file
16 func = f.read()
17
18print(f'pseudo function:\n{func}')# Note we only decompile one function, where the original file may contain multiple functions
19print(f'refined function:\n{c_func_decompile}')
20
This code repository is licensed under the MIT License.
If you have any questions, please raise an issue.