Skip to content

Instantly share code, notes, and snippets.

@vrthra
Forked from guedou/GhidraDecompiler.java
Created April 11, 2019 11:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vrthra/bb4fb32d0ad4fcd3c673b69524d128a8 to your computer and use it in GitHub Desktop.
Save vrthra/bb4fb32d0ad4fcd3c673b69524d128a8 to your computer and use it in GitHub Desktop.
Call the Ghidra decompiler from the command line
// Copyright (C) 2019 Guillaume Valadon <guillaume@valadon.net>
// This program is published under a GPLv2 license
/*
* Decompile a function with Ghidra
*
* analyzeHeadless . Test.gpr -import $BINARY_NAME -postScript GhidraDecompiler.java $FUNCTION_ADDRESS -deleteProject -noanalysis
*
*/
import ghidra.app.decompiler.ClangLine;
import ghidra.app.decompiler.DecompInterface;
import ghidra.app.decompiler.DecompileResults;
import ghidra.app.decompiler.DecompiledFunction;
import ghidra.app.decompiler.PrettyPrinter;
import ghidra.app.decompiler.component.DecompilerUtils;
import ghidra.app.util.headless.HeadlessScript;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionIterator;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.pcode.HighFunction;
import java.util.ArrayList;
public class GhidraDecompiler extends HeadlessScript {
@Override
public void run() throws Exception {
// Stop after this headless script
setHeadlessContinuationOption(HeadlessContinuationOption.ABORT);
// Get the function address from the script arguments
String[] args = getScriptArgs();
println(String.format("Array length: %d", args.length)); // DEBUG
if (args.length == 0) {
System.err.println("Please specify a function address!");
System.err.println("Note: use c0ffe instead of 0xcoffee");
return;
}
int functionAddress;
try {
functionAddress = Integer.parseInt(args[0], 16);
}
catch (NumberFormatException e) {
System.err.println(String.format("Invalid hex address: %s", args[0]));
return;
}
println(String.format("Address: %x", functionAddress)); // DEBUG
DecompInterface di = new DecompInterface();
println("Simplification style: " + di.getSimplificationStyle()); // DEBUG
println("Debug enables: " + di.debugEnabled());
Function f = this.getFunction(functionAddress);
if (f == null) {
System.err.println(String.format("Function not found at 0x%x", functionAddress));
return;
}
println(String.format("Decompiling %s() at 0x%x", f.getName(), functionAddress));
println("Program: " + di.openProgram(f.getProgram())); // DEBUG
// Decompile with a 5-seconds timeout
DecompileResults dr = di.decompileFunction(f, 5, null);
println("Decompilation completed: " + dr.decompileCompleted()); // DEBUG
DecompiledFunction df = dr.getDecompiledFunction();
println(df.getC());
// Print lines prepend with addresses
PrettyPrinter pp = new PrettyPrinter(f, dr.getCCodeMarkup());
ArrayList<ClangLine> lines = pp.getLines();
for (ClangLine line : lines) {
long minAddress = Long.MAX_VALUE;
long maxAddress = 0;
for (int i = 0; i < line.getNumTokens(); i++) {
if (line.getToken(i).getMinAddress() == null) {
continue;
}
long addr = line.getToken(i).getMinAddress().getOffset();
minAddress = addr < minAddress ? addr : minAddress;
maxAddress = addr > maxAddress ? addr : maxAddress;
}
if (maxAddress == 0) {
println(String.format(" - %s", line.toString()));
} else {
println(String.format("0x%-8x 0x%-8x - %s", minAddress, maxAddress, line.toString()));
}
}
}
protected Function getFunction(int address) {
// Logic from https://github.com/cea-sec/Sibyl/blob/master/ext/ghidra/ExportFunction.java
Listing listing = currentProgram.getListing();
FunctionIterator iter = listing.getFunctions(true);
while (iter.hasNext() && !monitor.isCancelled()) {
Function f = iter.next();
if (f.isExternal()) {
continue;
}
Address entry = f.getEntryPoint();
if (entry != null && entry.getOffset() == address) {
return f;
}
}
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment