Created
January 27, 2024 06:16
-
-
Save moyix/b364e21ea0ffdcd5a5a4d2fb52f4afba to your computer and use it in GitHub Desktop.
Revisions
-
moyix created this gist
Jan 27, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,55 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.HashMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import ghidra.app.script.GhidraScript; import ghidra.app.decompiler.DecompInterface; import ghidra.app.decompiler.DecompileResults; import com.google.gson.*; public class DecompileToJson extends GhidraScript { private static Logger log; public DecompileToJson() { log = LogManager.getLogger(DecompileToJson.class); } public void export(String filename) { Gson gson = new GsonBuilder().setPrettyPrinting().create(); File outputFile = new File(filename); HashMap<String, String> json_dict = new HashMap<String, String>(); DecompInterface ifc = new DecompInterface(); ifc.openProgram(currentProgram); for (var func : currentProgram.getListing().getFunctions(Boolean.TRUE)) { DecompileResults res = ifc.decompileFunction(func,0,monitor); if (!res.decompileCompleted()) { System.err.println(res.getErrorMessage()); continue; } String code = res.getDecompiledFunction().getC(); json_dict.put(func.getName(), code); System.out.println(func.getName()); } // Convert the HashMap to JSON String json = gson.toJson(json_dict); // Write JSON to file try (FileWriter writer = new FileWriter(outputFile)) { writer.write(json); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() throws Exception { String[] args = getScriptArgs(); export(args[0]); } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,257 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.List; import java.util.HashMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import ghidra.app.script.GhidraScript; import ghidra.app.util.EolComments; import ghidra.program.model.listing.CodeUnit; import ghidra.program.model.listing.CodeUnitFormat; import ghidra.program.model.listing.CodeUnitFormatOptions; import ghidra.program.model.listing.CodeUnitIterator; import ghidra.program.model.listing.Data; import ghidra.program.model.listing.Instruction; import ghidra.program.model.listing.Listing; import ghidra.program.model.listing.Variable; import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.symbol.Symbol; import ghidra.app.util.template.TemplateSimplifier; import ghidra.app.util.viewer.field.EolExtraCommentsOption; import com.google.gson.*; public class DisassembleToJson extends GhidraScript { private static Logger log; public DisassembleToJson() { log = LogManager.getLogger(DisassembleToJson.class); } private String getBytes(CodeUnit cu) { StringBuffer bytesbuf = new StringBuffer(); try { byte[] bytes; if (cu instanceof Instruction instr) { bytes = instr.getParsedBytes(); } else { bytes = cu.getBytes(); } for (int i = 0; i < bytes.length; ++i) { if (bytes[i] >= 0x00 && bytes[i] <= 0x0F) { bytesbuf.append("0"); } bytesbuf.append(Integer.toHexString(bytes[i] & 0xff)); } } catch (MemoryAccessException e) { return ""; } return bytesbuf.toString(); } private String getOperands(CodeUnit cu, CodeUnitFormat cuFormat) { StringBuffer buffy = new StringBuffer(); if (cu instanceof Instruction) { Instruction inst = (Instruction) cu; int opCnt = inst.getNumOperands(); String firstSeparator = ((Instruction) cu).getSeparator(0); String[] opSeparators = new String[opCnt]; String[] opReps = new String[opCnt]; for (int i = 0; i < opCnt; ++i) { opReps[i] = cuFormat.getOperandRepresentationString(cu, i); opSeparators[i] = ((Instruction) cu).getSeparator(i + 1); if (opSeparators[i] == null) { opSeparators[i] = ""; } } if (firstSeparator != null) { buffy.append(firstSeparator); } for (int i = 0; i < opCnt; ++i) { buffy.append(opReps[i]); buffy.append(opSeparators[i]); } } else if (cu instanceof Data) { Data data = (Data) cu; String opRep = cuFormat.getDataValueRepresentationString(data); buffy.append(opRep); } return buffy.toString(); } private String getVariableSorageString(Variable var) { String offsetStr; if (var.isStackVariable()) { int offset = var.getStackOffset(); offsetStr = (offset >= 0 ? " 0x" + Integer.toHexString(offset) : "-0x" + Integer.toHexString(-offset)); } else if (var.isRegisterVariable()) { offsetStr = var.getRegister().getName(); } else { offsetStr = var.getVariableStorage().toString(); } return offsetStr; } public void export(String filename) { Gson gson = new GsonBuilder().setPrettyPrinting().create(); File outputFile = new File(filename); HashMap<String, String> json_dict = new HashMap<String, String>(); // Formatter for disassembled code TemplateSimplifier simplifier = new TemplateSimplifier(); simplifier.setEnabled(false); CodeUnitFormatOptions formatOptions = new CodeUnitFormatOptions( CodeUnitFormatOptions.ShowBlockName.NEVER, CodeUnitFormatOptions.ShowNamespace.NON_LOCAL, null, true, // doRegVariableMarkup true, // doStackVariableMarkup true, // includeInferredVariableMarkup true, // alwaysShowPrimaryReference true, // includeScalarReferenceAdjustment true, // showLibraryInNamespace true, // followReferencedPointers simplifier ); var cuf = new CodeUnitFormat(formatOptions); // Annoying thing: for some reason catch blocks are not considered part of // a function (listing.getFunctionContaining() returns null), so we'll just // keep track of the last function we saw and assume that the next code unit // belongs to the same function if it's not in a function. ghidra.program.model.listing.Function lastFunc = null; CodeUnitIterator cuIterator = currentProgram.getListing().getCodeUnits(true); Listing listing = currentProgram.getListing(); for (var cu : cuIterator) { var currentAddress = cu.getMinAddress(); var func = listing.getFunctionContaining(currentAddress); if (func == null) { if (cu instanceof Instruction && lastFunc != null) { log.warn(String.format( "Instruction at [%s] not in a function; assuming it's part of %s", currentAddress, lastFunc )); func = lastFunc; } else { // System.err.printf( // "[%s] Note: skipping CU of type %s\n", // currentAddress, cu.getClass().getName() // ); continue; } } lastFunc = func; boolean isFunctionEntryPoint = func.getEntryPoint().equals(currentAddress); // Get the code for this function so far, or create a new one String code = json_dict.getOrDefault(func.getName(), ""); // If this is the first code unit in the function, add preamble if (isFunctionEntryPoint) { log.info(String.format( "Processing: %s [%s,%s]", func.getName(), func.getBody().getMinAddress(), func.getBody().getMaxAddress() )); // Add comment with function signature code += String.format("; %s\n", func.getPrototypeString(true, true)); // Add comment with parameters code += "; Parameters:\n"; for (var v : func.getParameters()) { code += String.format("; %-14s %-14s %s\n", v.getName(), v.getDataType().getDisplayName(), getVariableSorageString(v) ); } // Add comment with local variables on the stack code += "; Stack variables:\n"; for (var v : func.getLocalVariables()) { code += String.format("; %-14s %-14s %s\n", v.getName(), v.getDataType().getDisplayName(), getVariableSorageString(v) ); } } String addrString = cu.getAddressString(true, false); // Any pre-comment String preComment = cu.getComment(CodeUnit.PRE_COMMENT); if (preComment != null) { code += String.format("%-16s %-16s ; %s\n", "", "", preComment ); } // Primary symbol name (either function name or label) Symbol primarySymbol = cu.getPrimarySymbol(); if (primarySymbol != null) { code += String.format("%-16s %-16s %s:\n", "", "", primarySymbol.getName()); } // Disassembly code += String.format("%-16s %-16s %-11s %-40s", addrString, getBytes(cu), cu.getMnemonicString(), getOperands(cu, cuf), cuf.getRepresentationString(cu, true) ); // EOL comments EolExtraCommentsOption eolOption = new EolExtraCommentsOption(); EolComments eolComments = new EolComments(cu, true, 6 /* arbitrary */, eolOption); List<String> comments = eolComments.getComments(); if (comments.size() > 0) { code += " ; " + String.join(", ", comments); } // Trim trailing whitespace code = code.stripTrailing(); code += "\n"; // Any post-comment String postComment = cu.getComment(CodeUnit.POST_COMMENT); if (postComment != null) { code += String.format("%-16s %-16s ; %s\n", "", "", postComment ); } // Update the code for this function json_dict.put(func.getName(), code); } // Convert the HashMap to JSON String json = gson.toJson(json_dict); // Write JSON to file try (FileWriter writer = new FileWriter(outputFile)) { writer.write(json); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() throws Exception { String[] args = getScriptArgs(); export(args[0]); } }