This commit is contained in:
Guus Waals 2024-10-04 22:42:00 +08:00
parent 3e469475c9
commit 7090abf5a2
2 changed files with 236 additions and 21 deletions

View File

@ -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<Function> callees;
}
HashSet<Address> 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<Address> queue = new ArrayList<>();
List<Function> functionsToDump = new ArrayList<>();
List<Function> 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<String>() {
{
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();
}
}

View File

@ -4,15 +4,22 @@ import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set;
import ghidra.app.decompiler.DecompileResults; import ghidra.app.decompiler.DecompileResults;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Function; 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.HighFunction;
import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.PcodeOpAST; import ghidra.program.model.pcode.PcodeOpAST;
import ghidra.program.model.pcode.Varnode; import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.Reference;
public class PCallTracer { public class PCallTracer {
public class QueueItem { public class QueueItem {
@ -30,38 +37,139 @@ public class PCallTracer {
List<QueueItem> queue = new ArrayList<>(); List<QueueItem> queue = new ArrayList<>();
HashSet<Address> visited = new HashSet<>(); HashSet<Address> visited = new HashSet<>();
DecompileCache decomp; // DecompileCache decomp;
GhidraScript script; GhidraScript script;
Program program;
public PCallTracer() { public PCallTracer() {
this.script = RecompileConfig.INSTANCE.script; this.script = RecompileConfig.INSTANCE.script;
this.decomp = RecompileConfig.INSTANCE.decompCache; this.program = this.script.getCurrentProgram();
// this.decomp = RecompileConfig.INSTANCE.decompCache;
} }
public void setBlacklist(HashSet<Address> blacklist) { public void setBlacklist(HashSet<Address> blacklist) {
this.visited = new HashSet<>(blacklist); this.visited = new HashSet<>(blacklist);
} }
void visit(HighFunction highFunction, int depth) { // public List<Address> getReferenceFromAddresses(Address address) {
Iterator<PcodeOpAST> opIter = highFunction.getPcodeOps(); // Reference[] referencesFrom = script.getReferencesFrom(address);
while (opIter.hasNext()) {
PcodeOpAST op = opIter.next(); // // get only the address references at the given address (ie no stack refs,
if (op.getOpcode() == PcodeOp.CALL) { // ...)
Varnode target = op.getInput(0); // List<Address> refFromAddresses = new ArrayList<Address>();
if (target.isAddress()) { // for (Reference referenceFrom : referencesFrom) {
Address callAddr = target.getAddress(); // if (referenceFrom.isMemoryReference()) {
Function calledFunction = script.getFunctionAt(callAddr); // refFromAddresses.add(referenceFrom.getToAddress());
if (calledFunction == null) { // }
script.println("PCallTracer, called function not found: " + op.toString() + " - " // }
+ highFunction.getFunction().getName());
continue; // return refFromAddresses;
} // }
if (!visited.contains(calledFunction.getEntryPoint())) {
queue.add(new QueueItem(calledFunction, depth + 1)); 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<Address> 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<Function> calledFunctions = new HashSet<Function>();
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<PcodeOpAST> 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) { void visit(Function function, int depth) {
@ -70,8 +178,8 @@ public class PCallTracer {
if (trace) { if (trace) {
script.println("PCallTracer, visiting " + function.getName() + " (depth:" + depth + ")"); script.println("PCallTracer, visiting " + function.getName() + " (depth:" + depth + ")");
} }
DecompileResults decompRes = decomp.getOrInsert(function); // DecompileResults decompRes = decomp.getOrInsert(function);
visit(decompRes.getHighFunction(), depth); visitInstructions(function, depth);
out.add(function); out.add(function);
} }
} }