// Export every function in the current Ghidra program as one traceable C-like file. // @category TDKPIN import java.io.BufferedWriter; import java.io.FileWriter; import java.io.PrintWriter; import ghidra.app.decompiler.DecompInterface; import ghidra.app.decompiler.DecompileResults; import ghidra.app.script.GhidraScript; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.FunctionIterator; import ghidra.program.model.mem.MemoryBlock; public class ExportDecompilation extends GhidraScript { @Override public void run() throws Exception { String[] args = getScriptArgs(); if (args.length != 2) { throw new IllegalArgumentException("usage: ExportDecompilation.java OUTPUT_C OUTPUT_TSV"); } DecompInterface decompiler = new DecompInterface(); decompiler.toggleCCode(true); decompiler.toggleSyntaxTree(true); if (!decompiler.openProgram(currentProgram)) { throw new IllegalStateException("cannot open program in decompiler"); } int total = 0; int internal = 0; int external = 0; int succeeded = 0; int failed = 0; try (PrintWriter c = new PrintWriter(new BufferedWriter(new FileWriter(args[0]))); PrintWriter ledger = new PrintWriter(new BufferedWriter(new FileWriter(args[1])))) { c.println("/*"); c.println(" * Raw Ghidra decompilation of TDKPIN.EXE."); c.println(" * Function boundaries and names are analysis artifacts, not original source symbols."); c.println(" */"); c.println(); ledger.println("address\tname\tkind\tstatus\tmessage"); FunctionIterator functions = currentProgram.getFunctionManager().getFunctions(true); while (functions.hasNext() && !monitor.isCancelled()) { Function function = functions.next(); total++; String address = function.getEntryPoint().toString(); String name = function.getName(); MemoryBlock block = currentProgram.getMemory().getBlock(function.getEntryPoint()); boolean imported = function.isExternal() || block == null || !block.isInitialized() || "EXTERNAL".equals(block.getName()); if (imported) { external++; ledger.printf("%s\t%s\texternal\tn/a\timported function%n", address, name); continue; } internal++; DecompileResults result = decompiler.decompileFunction(function, 120, monitor); c.printf("/* ===== %s %s ===== */%n", address, name); if (result.decompileCompleted() && result.getDecompiledFunction() != null) { c.println(result.getDecompiledFunction().getC()); succeeded++; ledger.printf("%s\t%s\tinternal\tok\t%n", address, name); } else { String message = result.getErrorMessage(); c.printf("/* DECOMPILATION FAILED: %s */%n%n", message); failed++; ledger.printf("%s\t%s\tinternal\tfailed\t%s%n", address, name, message == null ? "" : message.replace('\t', ' ').replace('\n', ' ')); } } c.printf("/* SUMMARY: total=%d internal=%d external=%d succeeded=%d failed=%d */%n", total, internal, external, succeeded, failed); println(String.format("Exported total=%d internal=%d external=%d succeeded=%d failed=%d", total, internal, external, succeeded, failed)); } finally { decompiler.dispose(); } } }