-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathHaruspex.java
139 lines (126 loc) · 4.4 KB
/
Haruspex.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
* Haruspex.java - Extract pseudo-code from Ghidra's decompiler
* Copyright (c) 2022-2024 Marco Ivaldi <[email protected]>
*
* "Et immolantem haruspex Spurinna monuit, caveret periculum, quod non
* ultra Martias Idus proferretur."
* -- Suetonius
*
* Haruspex is a simple Ghidra script to assist with reverse engineering
* and vulnerability research tasks. It extracts all pseudo-code generated
* by the Ghidra decompiler in a format that should be suitable to be
* imported into an IDE, such as VS Code, or parsed by static analysis
* tools, such as Semgrep.
*
* See also:
* https://github.com/0xdea/ghidra-scripts/blob/main/Rhabdomancer.java
* https://github.com/0xdea/semgrep-rules
* https://joern.io/blog/joern-supports-binary/
* https://www.s3.eurecom.fr/docs/asiaccs22_mantovani.pdf
*
* Usage:
* - Analyze your target binary and manually add/modify functions if needed
* - Copy the script into your ghidra_scripts directory
* - Open the Script Manager in Ghidra and run the script
* - You can also run it via the Tools > Haruspex menu or the shortcut "H"
* - Enter an output path in which the pseudo-code will be saved
*
* Tested with Ghidra v11.2.1.
*/
// This script extracts all pseudo-code generated by the Ghidra decompiler
// in a format that should be suitable to be imported into an IDE, such as
// VS Code, or parsed by static analysis tools, such as Semgrep.
// @author Marco Ivaldi <[email protected]>
// @category VulnDev
// @keybinding H
// @menupath Tools.Haruspex
// @toolbar
import java.util.List;
import java.util.ArrayList;
import java.io.FileWriter;
import java.io.PrintWriter;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.symbol.*;
import ghidra.program.model.listing.*;
import ghidra.app.decompiler.DecompInterface;
import ghidra.app.decompiler.DecompileOptions;
import ghidra.app.decompiler.DecompileResults;
public class Haruspex extends GhidraScript
{
List<Function> functions;
DecompileOptions options;
DecompInterface decomp;
String outputPath = "/tmp/haruspex.out";
static int TIMEOUT = 60;
@Override
public void run() throws Exception
{
printf("\nHaruspex.java - Extract Ghidra decompiler's pseudo-code\n");
printf("Copyright (c) 2022 Marco Ivaldi <[email protected]>\n\n");
// ask for output directory path
try {
outputPath = askString("Output directory path", "Enter the path of the output directory:");
} catch (Exception e) {
printf("Output directory not supplied, using default \"%s\".\n", outputPath);
}
// get all functions
functions = new ArrayList<>();
getAllFunctions();
// extract pseudo-code of all functions (using default options)
decomp = new DecompInterface();
options = new DecompileOptions();
decomp.setOptions(options);
decomp.toggleCCode(true);
decomp.toggleSyntaxTree(true);
decomp.setSimplificationStyle("decompile");
if (!decomp.openProgram(currentProgram)) {
printf("Could not initialize the decompiler, exiting.\n\n");
return;
}
printf("Extracting pseudo-code from %d functions...\n\n", functions.size());
functions.forEach(f -> extractPseudoCode(f));
}
// collect all Function objects into a global ArrayList
public void getAllFunctions()
{
SymbolTable st = currentProgram.getSymbolTable();
SymbolIterator si = st.getSymbolIterator();
while (si.hasNext()) {
Symbol s = si.next();
if ( (s.getSymbolType() == SymbolType.FUNCTION) && (!s.isExternal()) ) {
Function fun = getFunctionAt(s.getAddress());
if (!fun.isThunk()) {
functions.add(fun);
}
}
}
}
// extract the pseudo-code of a function
// @param func target function
public void extractPseudoCode(Function func)
{
DecompileResults res = decomp.decompileFunction(func, TIMEOUT, monitor);
if(res.getDecompiledFunction() != null){
saveToFile(outputPath, func.getName() + "@" + func.getEntryPoint() + ".c", res.getDecompiledFunction().getC());
}
else{
printf("Can't decompile %s\n\n", func.getName());
}
}
// save results to file
// @param path name of the output directory
// @param name name of the output file
// @param output content to save to file
public void saveToFile(String path, String name, String output)
{
try {
FileWriter fw = new FileWriter(path + "/" + name);
PrintWriter pw = new PrintWriter(fw);
pw.write(output);
pw.close();
} catch (Exception e) {
printf("Cannot write to output file \"%s\".\n\n", path + "/" + name);
return;
}
}
}