forked from 0xdea/ghidra-scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHaruspex.java
129 lines (116 loc) · 4.09 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
/*
* Haruspex.java - Extract Ghidra decompiler's pseudo-code
* Copyright (c) 2022 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 v10.2.2.
*/
// 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.DecompileResults;
public class Haruspex extends GhidraScript
{
List<Function> functions;
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();
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()) ) {
functions.add(getFunctionAt(s.getAddress()));
}
}
}
// 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;
}
}
}