// GhidraScript: FindVtableOffsetCalls.java // Usage: // analyzeHeadless -process -noanalysis -readOnly \ // -scriptPath tools/ghidra_scripts -postScript FindVtableOffsetCalls.java 0xb0 import ghidra.app.script.GhidraScript; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Instruction; import ghidra.program.model.scalar.Scalar; public class FindVtableOffsetCalls extends GhidraScript { private boolean hasScalar(Instruction ins, long want) { for (int op = 0; op < ins.getNumOperands(); op++) { for (Object obj : ins.getOpObjects(op)) { if (obj instanceof Scalar) { Scalar s = (Scalar)obj; if (s.getUnsignedValue() == want || s.getSignedValue() == want) return true; } } } return false; } @Override public void run() throws Exception { String[] args = getScriptArgs(); if (args == null || args.length == 0) { printerr("FindVtableOffsetCalls: needs one or more vtable offsets, e.g. 0xb0"); return; } for (String arg : args) { long want = Long.decode(arg); println("=== vtable call offset " + arg + " ==="); int hits = 0; for (Instruction ins : currentProgram.getListing().getInstructions(true)) { if (!"CALL".equals(ins.getMnemonicString())) continue; if (!hasScalar(ins, want)) continue; hits++; Function f = getFunctionContaining(ins.getAddress()); String fs = f == null ? "(no func)" : f.getName() + " @ " + f.getEntryPoint(); println(""); println(ins.getAddress() + " " + fs + " " + ins); Instruction prev = ins; for (int i = 0; i < 10; i++) { prev = prev.getPrevious(); if (prev == null) break; println(" " + prev.getAddress() + " " + prev); } if (hits >= 300) { println("(truncated at 300 hits)"); break; } if (monitor.isCancelled()) break; } println("hits: " + hits); } } }