From 48f15947d814bdd2c786317886faa6224d337ff2 Mon Sep 17 00:00:00 2001 From: Guus Waals <_@guusw.nl> Date: Sun, 15 Sep 2024 20:01:35 +0800 Subject: [PATCH] Wip decompile export script --- .gitignore | 1 + .vscode/settings.json | 59 ++++++ ghidra.rep/projectState | 322 +++++++++++++++++++++++++++++++- ghidra.rep/user/00/00000003.prp | 11 ++ scripts/DecompileC.java | 145 ++++++++++++++ scripts/LICENSE | 23 +++ scripts/readme.md | 3 + 7 files changed, 563 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json create mode 100644 ghidra.rep/user/00/00000003.prp create mode 100644 scripts/DecompileC.java create mode 100644 scripts/LICENSE create mode 100644 scripts/readme.md diff --git a/.gitignore b/.gitignore index 9650dd3e..020dbfed 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ windows_libs_other/ ~* *.lock~ *.lock +.venv ACP_Ray2/ build/ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..fb2c36dd --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,59 @@ +{ + // "java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx1G -Xms100m -Xlog:disable -jar C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\Base\\lib\\Base.jar" + // "java.configuration.runtimes": [ + // { + // "name": "JavaSE-1.8", + // "path": "C:\\Program Files\\Microsoft\\jdk-17.0.11.9-hotspot\\", + // "sources": "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\Base\\lib\\Base.jar" + // } + // ], + "java.project.referencedLibraries": [ + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\Base\\lib\\Base.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\Decompiler\\lib\\Decompiler.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\BSim\\lib\\BSim.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\BSimFeatureVisualizer\\lib\\BSimFeatureVisualizer.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\Base\\lib\\Base.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\BytePatterns\\lib\\BytePatterns.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\ByteViewer\\lib\\ByteViewer.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\CodeCompare\\lib\\CodeCompare.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\DebugUtils\\lib\\DebugUtils.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\Decompiler\\lib\\Decompiler.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\DecompilerDependent\\lib\\DecompilerDependent.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\FileFormats\\lib\\FileFormats.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\FunctionGraph\\lib\\FunctionGraph.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\FunctionGraphDecompilerExtension\\lib\\FunctionGraphDecompilerExtension.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\FunctionID\\lib\\FunctionID.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\GhidraGo\\lib\\GhidraGo.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\GhidraServer\\lib\\GhidraServer.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\GnuDemangler\\lib\\GnuDemangler.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\GraphFunctionCalls\\lib\\GraphFunctionCalls.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\GraphServices\\lib\\GraphServices.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\MicrosoftCodeAnalyzer\\lib\\MicrosoftCodeAnalyzer.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\MicrosoftDemangler\\lib\\MicrosoftDemangler.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\MicrosoftDmang\\lib\\MicrosoftDmang.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\PDB\\lib\\PDB.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\ProgramDiff\\lib\\ProgramDiff.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\ProgramGraph\\lib\\ProgramGraph.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\Python\\lib\\Python.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\Recognizers\\lib\\Recognizers.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\Sarif\\lib\\Sarif.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\SourceCodeLookup\\lib\\SourceCodeLookup.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\SwiftDemangler\\lib\\SwiftDemangler.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\SystemEmulation\\lib\\SystemEmulation.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\VersionTracking\\lib\\VersionTracking.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\VersionTrackingBSim\\lib\\VersionTrackingBSim.jar", + "C:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Features\\WildcardAssembler\\lib\\WildcardAssembler.jar", + "c:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Framework\\DB\\lib\\DB.jar", + "c:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Framework\\Docking\\lib\\Docking.jar", + "c:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Framework\\Emulation\\lib\\Emulation.jar", + "c:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Framework\\FileSystem\\lib\\FileSystem.jar", + "c:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Framework\\Generic\\lib\\Generic.jar", + "c:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Framework\\Graph\\lib\\Graph.jar", + "c:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Framework\\Gui\\lib\\Gui.jar", + "c:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Framework\\Help\\lib\\Help.jar", + "c:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Framework\\Project\\lib\\Project.jar", + "c:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Framework\\Pty\\lib\\Pty.jar", + "c:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Framework\\SoftwareModeling\\lib\\SoftwareModeling.jar", + "c:\\Projects\\ghidra_11.1.2_PUBLIC\\Ghidra\\Framework\\Utility\\lib\\Utility.jar" + ] +} diff --git a/ghidra.rep/projectState b/ghidra.rep/projectState index 11eed53f..19190bbb 100644 --- a/ghidra.rep/projectState +++ b/ghidra.rep/projectState @@ -9,7 +9,327 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ghidra.rep/user/00/00000003.prp b/ghidra.rep/user/00/00000003.prp new file mode 100644 index 00000000..6bfcac4f --- /dev/null +++ b/ghidra.rep/user/00/00000003.prp @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/scripts/DecompileC.java b/scripts/DecompileC.java new file mode 100644 index 00000000..098ba63c --- /dev/null +++ b/scripts/DecompileC.java @@ -0,0 +1,145 @@ + +// Test script +import java.io.File; +import java.io.PrintWriter; +import java.net.URL; +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; + +import ghidra.app.decompiler.DecompInterface; +import ghidra.app.decompiler.DecompileResults; +import ghidra.app.script.GhidraScript; +import ghidra.app.script.GhidraScriptUtil; +import ghidra.program.model.address.GlobalSymbol; +import ghidra.program.model.data.DataType; +import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.Variable; +import ghidra.program.model.pcode.HighSymbol; +import ghidra.program.model.symbol.SourceType; +import ghidra.program.model.symbol.Symbol; + +public class DecompileC extends GhidraScript { + private static final String OUTPUT_DIR = "game_re"; + private static final int TIMEOUT = 10000; + + // Auto rename invalid symbols + private static final boolean AUTO_RENAME_SYMBOLS = true; + + @Override + public void run() throws Exception { + if (currentProgram == null) { + return; + } + + // Make sure to create OUTPUT_PATH + File rootDir = new File(sourceFile.getAbsolutePath()).getParentFile().getParentFile(); + File outputDir = new File(rootDir, OUTPUT_DIR); + + if (!outputDir.exists()) { + throw new Exception("Output directory does not exist: " + outputDir.getCanonicalPath()); + } + + File dirDecompAuto = new File(outputDir, "gh_auto"); + File dirDecompFix = new File(outputDir, "gh_fix"); + + println("Output path: " + outputDir.getCanonicalPath()); + + DecompInterface decomp = new DecompInterface(); + decomp.openProgram(currentProgram); + + List functions = new ArrayList<>(); + List uniqueVars = new ArrayList<>(); + + Iterator functionsIt = currentProgram.getFunctionManager().getFunctions(true).iterator(); + while (functionsIt.hasNext()) { + Function function = functionsIt.next(); + String comment = function.getComment(); + if (comment != null && comment.contains("TODO")) { + println("Function: " + function.getName() + " - " + comment); + } + functions.add(function); + + for (Variable var : function.getAllVariables()) { + uniqueVars.add(var); + } + } + + Hashtable globalSymbols = new Hashtable<>(); + + File functionList = new File(outputDir, "functions.txt"); + PrintWriter writer = new PrintWriter(functionList, "UTF-8"); + for (Function function : functions) { + String fileName = sanitizeFunctionName(function.getName()) + ".c"; + + File f1 = new File(dirDecompFix, fileName); + if (f1.exists()) { + println("Func " + function.getName() + " skipped (gh_fix)"); + continue; + } + + File f0 = new File(dirDecompAuto, fileName); + if (f0.exists()) { + f0.delete(); + } + + DecompileResults decompRes = decomp.decompileFunction(function, TIMEOUT, monitor); + PrintWriter writer2 = new PrintWriter(f0, "UTF-8"); + writer2.println(decompRes.getDecompiledFunction().getC()); + writer2.close(); + + Iterator smyIt = decompRes.getHighFunction().getGlobalSymbolMap().getSymbols(); + while (smyIt.hasNext()) { + HighSymbol gsym = smyIt.next(); + if (globalSymbols.containsKey(gsym.getName())) + continue; + println("GLOBAL: " + gsym.getName()); + String sanitizedName = sanitizeFunctionName(gsym.getName()); + if (!sanitizedName.equals(gsym.getName())) { + if (AUTO_RENAME_SYMBOLS) { + println("Renaming global symbol: " + gsym.getName() + " -> " + sanitizedName); + Symbol symbol = gsym.getSymbol();// currentProgram.getSymbolTable().getSymbol(gsym.getName()); + if (symbol != null) { + try { + symbol.setName(sanitizedName, SourceType.USER_DEFINED); + println("Renamed global symbol: " + gsym.getName() + " -> " + sanitizedName); + } catch (Exception e) { + println("Error renaming symbol: " + e.getMessage()); + } + } else { + println("Could not find symbol to rename: " + gsym.getName()); + } + } + println("Invalid global symbol name: " + gsym.getName() + " - " + function.getName()); + } + globalSymbols.put(gsym.getName(), gsym); + } + } + writer.close(); + + File uniqueVarsList = new File(outputDir, "unique_vars.txt"); + writer = new PrintWriter(uniqueVarsList, "UTF-8"); + for (Variable var : uniqueVars) { + writer.println(var.getName()); + } + writer.close(); + + File globalSymbolsListH = new File(outputDir, "global.h"); + File globalSymbolsListC = new File(outputDir, "global.c"); + PrintWriter hwriter = new PrintWriter(globalSymbolsListH, "UTF-8"); + PrintWriter cwriter = new PrintWriter(globalSymbolsListC, "UTF-8"); + for (HighSymbol sym : globalSymbols.values()) { + DataType dt = sym.getDataType(); + hwriter.println("extern " + dt.toString() + " " + sym.getName() + ";"); + cwriter.println(sym.getDataType().toString() + " " + sym.getName() + " {}"); + } + hwriter.close(); + cwriter.close(); + } + + String sanitizeFunctionName(String name) { + return name.replaceAll("[^a-zA-Z0-9_]", "_"); + } +} diff --git a/scripts/LICENSE b/scripts/LICENSE new file mode 100644 index 00000000..a3427dfb --- /dev/null +++ b/scripts/LICENSE @@ -0,0 +1,23 @@ +Parts used from https://github.com/tenable/ghidra_tools + +MIT License + +Copyright (c) 2022 Tenable + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/scripts/readme.md b/scripts/readme.md new file mode 100644 index 00000000..e2d20dae --- /dev/null +++ b/scripts/readme.md @@ -0,0 +1,3 @@ +# Ghidra Scripts + +Add this to your scripts folder and run to generate c code for all functions in the project \ No newline at end of file