From 7090abf5a2b23fbe85ebdddf8bdce7c13034f304 Mon Sep 17 00:00:00 2001 From: Guus Waals <_@guusw.nl> Date: Fri, 4 Oct 2024 22:42:00 +0800 Subject: [PATCH] WIP --- scripts/DumpCurrentFunctionN.java | 107 +++++++++++++++++++++ scripts/re3lib/PCallTracer.java | 150 +++++++++++++++++++++++++----- 2 files changed, 236 insertions(+), 21 deletions(-) create mode 100644 scripts/DumpCurrentFunctionN.java diff --git a/scripts/DumpCurrentFunctionN.java b/scripts/DumpCurrentFunctionN.java new file mode 100644 index 00000000..36de4516 --- /dev/null +++ b/scripts/DumpCurrentFunctionN.java @@ -0,0 +1,107 @@ +// Decompile selected function recursively (until a given number of new functions is reached) +// @category _Reman3 +// @menupath Reman3.Dump N Functions + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import ghidra.app.script.GhidraScript; +import ghidra.pcodeCPort.address.Address; +import ghidra.program.model.listing.Function; +import re3lib.FunctionDumper; +import re3lib.GlobalDumper; +import re3lib.PCallTracer; +import re3lib.RecompileConfig; +import re3lib.TypeDumper; + +public class DumpCurrentFunctionN extends GhidraScript { + final int NumFunctions = 8; + + class Entry { + Function function; + } + class QueueEntry { + Function function; + List callees; + } + + HashSet
visited = new HashSet<>(); + + QueueEntry enter(Function function) { + if (visited.contains(function.getEntryPoint())) + return null; + + visited.add(function.getEntryPoint()); + + QueueEntry entry = new QueueEntry(); + entry.function = function; + + function.getCalledFunctions(monitor); + + } + + @Override + public void run() throws Exception { + RecompileConfig.INSTANCE = new RecompileConfig(this); + RecompileConfig.INSTANCE.createDirectories(); + + GlobalDumper globalDumper = new GlobalDumper(this); + globalDumper.loadGlobalManifest(); + + FunctionDumper functionDumper = new FunctionDumper(this, globalDumper); + + // PCallTracer tracer = new PCallTracer(); + // tracer.setBlacklist(functionDumper.functionAddrBlackList); + // tracer.traceCalls(getFunctionContaining(currentAddress)); + + List
queue = new ArrayList<>(); + + List functionsToDump = new ArrayList<>(); + List functionsToDumpNew = new ArrayList<>(); + for (Function func : tracer.out) { + if (FunctionDumper.isDumpedFix(func)) + continue; + + println("Dump: " + func.getName()); + functionsToDump.add(func); + + if (!FunctionDumper.isDumpedAuto(func)) + functionsToDumpNew.add(func); + } + + if (!functionsToDump.isEmpty()) { + String newOpt = "Only new (" + functionsToDumpNew.size() + ")"; + String okOpt = "Yes (" + functionsToDump.size() + ")"; + String choice = askChoice("Confirmation", "About to generate " + functionsToDump.size() + " functions (" + + functionsToDumpNew.size() + " new), continue?", + new ArrayList() { + { + add(okOpt); + add(newOpt); + add("No"); + } + }, okOpt); + if (choice == okOpt) { + } else if (choice == newOpt) { + functionsToDump = functionsToDumpNew; + } else { + return; + } + + for (Function func : functionsToDump) { + functionDumper.dump(func); + } + + if (functionDumper.createdFile) + RecompileConfig.INSTANCE.touchCMakeTimestamp(); + + globalDumper.dumpGlobals(); + globalDumper.saveGlobalManifest(); + } + + // Dump types + TypeDumper dumper = new TypeDumper(this); + dumper.run(); + } +} diff --git a/scripts/re3lib/PCallTracer.java b/scripts/re3lib/PCallTracer.java index 1503e115..99ef3fa8 100644 --- a/scripts/re3lib/PCallTracer.java +++ b/scripts/re3lib/PCallTracer.java @@ -4,15 +4,22 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import ghidra.app.decompiler.DecompileResults; import ghidra.app.script.GhidraScript; import ghidra.program.model.address.Address; +import ghidra.program.model.lang.Register; import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.FunctionManager; +import ghidra.program.model.listing.Instruction; +import ghidra.program.model.listing.InstructionIterator; +import ghidra.program.model.listing.Program; import ghidra.program.model.pcode.HighFunction; import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.PcodeOpAST; import ghidra.program.model.pcode.Varnode; +import ghidra.program.model.symbol.Reference; public class PCallTracer { public class QueueItem { @@ -30,38 +37,139 @@ public class PCallTracer { List queue = new ArrayList<>(); HashSet
visited = new HashSet<>(); - DecompileCache decomp; + // DecompileCache decomp; GhidraScript script; + Program program; public PCallTracer() { this.script = RecompileConfig.INSTANCE.script; - this.decomp = RecompileConfig.INSTANCE.decompCache; + this.program = this.script.getCurrentProgram(); + // this.decomp = RecompileConfig.INSTANCE.decompCache; } public void setBlacklist(HashSet
blacklist) { this.visited = new HashSet<>(blacklist); } - void visit(HighFunction highFunction, int depth) { - Iterator opIter = highFunction.getPcodeOps(); - while (opIter.hasNext()) { - PcodeOpAST op = opIter.next(); - if (op.getOpcode() == PcodeOp.CALL) { - Varnode target = op.getInput(0); - if (target.isAddress()) { - Address callAddr = target.getAddress(); - Function calledFunction = script.getFunctionAt(callAddr); - if (calledFunction == null) { - script.println("PCallTracer, called function not found: " + op.toString() + " - " - + highFunction.getFunction().getName()); - continue; - } - if (!visited.contains(calledFunction.getEntryPoint())) { - queue.add(new QueueItem(calledFunction, depth + 1)); - } + // public List
getReferenceFromAddresses(Address address) { + // Reference[] referencesFrom = script.getReferencesFrom(address); + + // // get only the address references at the given address (ie no stack refs, + // ...) + // List
refFromAddresses = new ArrayList
(); + // for (Reference referenceFrom : referencesFrom) { + // if (referenceFrom.isMemoryReference()) { + // refFromAddresses.add(referenceFrom.getToAddress()); + // } + // } + + // return refFromAddresses; + // } + + public Function getReferencedFunction(Address address, boolean getThunkedFunction) { + Reference[] referencesFrom = script.getReferencesFrom(address); + + if (referencesFrom.length == 0) { + return null; + } + + for (Reference referenceFrom : referencesFrom) { + Address referencedAddress = referenceFrom.getToAddress(); + if (referencedAddress == null) { + continue; + } + + Function function = script.getFunctionAt(referencedAddress); + + if (function == null) { + continue; + } + + if (!getThunkedFunction) { + return function; + } + + if (function.isThunk()) { + function = function.getThunkedFunction(true); + } + return function; + } + + return null; + // List
referencesFrom = getReferenceFromAddresses(address); + // if (referencesFrom.size() != 1) { + // return null; + // } + + // Address functionAddress = referencesFrom.get(0); + + // Register lowBitCodeMode = program.getRegister("LowBitCodeMode"); + // if (lowBitCodeMode != null) { + // long longValue = functionAddress.getOffset(); + // longValue = longValue & ~0x1; + // functionAddress = functionAddress.getNewAddress(longValue); + // } + + // Function function = script.getFunctionAt(functionAddress); + // if (function == null) { + // // try to create function + // function = script.createFunction(functionAddress, null); + // if (function == null) { + // return null; + // } + // } + + // // if function is a thunk, get the thunked function + // if (function.isThunk()) { + // Function thunkedFunction = function.getThunkedFunction(true); + // function = thunkedFunction; + // } + + // return function; + } + + void visitInstructions(Function function, int depth) { + Set calledFunctions = new HashSet(); + + InstructionIterator instructions = script.getCurrentProgram() + .getListing() + .getInstructions(function.getBody(), true); + while (instructions.hasNext()) { + Instruction instruction = instructions.next(); + if (instruction.getFlowType().isCall()) { + + FunctionManager functionManager = script.getCurrentProgram().getFunctionManager(); + Function calledFunction = getReferencedFunction(instruction.getMinAddress(), true); + if (calledFunction == null) { + continue; + } + + if (!visited.contains(calledFunction.getEntryPoint())) { + queue.add(new QueueItem(calledFunction, depth + 1)); } } } + + // Iterator opIter = highFunction.getPcodeOps(); + // while (opIter.hasNext()) { + // PcodeOpAST op = opIter.next(); + // if (op.getOpcode() == PcodeOp.CALL) { + // Varnode target = op.getInput(0); + // if (target.isAddress()) { + // Address callAddr = target.getAddress(); + // Function calledFunction = script.getFunctionAt(callAddr); + // if (calledFunction == null) { + // script.println("PCallTracer, called function not found: " + op.toString() + " + // - " + // + highFunction.getFunction().getName()); + // continue; + // } + // if (!visited.contains(calledFunction.getEntryPoint())) { + // queue.add(new QueueItem(calledFunction, depth + 1)); + // } + // } + // } + // } } void visit(Function function, int depth) { @@ -70,8 +178,8 @@ public class PCallTracer { if (trace) { script.println("PCallTracer, visiting " + function.getName() + " (depth:" + depth + ")"); } - DecompileResults decompRes = decomp.getOrInsert(function); - visit(decompRes.getHighFunction(), depth); + // DecompileResults decompRes = decomp.getOrInsert(function); + visitInstructions(function, depth); out.add(function); } }