// Hunt for the track-row builder / the per-track 8-byte hash (row offsets // 0x14 u4, 0x18 u2, 0x1a u2) and index_shift (0x02). Decompiles the string-hash // function formatForSearch + its callers, and dumps xrefs of track/content/ // search-related strings. Output -> ~/ghidra_proj/hash.txt import java.io.PrintWriter; import java.util.*; import ghidra.app.script.GhidraScript; import ghidra.app.decompiler.*; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.*; public class FindHash extends GhidraScript { PrintWriter out; DecompInterface di; Set done = new HashSet<>(); FunctionManager fm; ReferenceManager rm; void dec(Function f, String why) { if (f == null) return; if (!done.add(f.getEntryPoint().toString())) return; out.println("\n//===== " + f.getName() + " @ " + f.getEntryPoint() + " [" + why + "] ====="); DecompileResults r = di.decompileFunction(f, 60, monitor); out.println(r != null && r.decompileCompleted() ? r.getDecompiledFunction().getC() : "// decompile failed"); } Function fn(String a) { return fm.getFunctionContaining(currentProgram.getAddressFactory().getAddress(a)); } @Override public void run() throws Exception { out = new PrintWriter("/home/ntr/ghidra_proj/hash.txt"); di = new DecompInterface(); di.openProgram(currentProgram); fm = currentProgram.getFunctionManager(); rm = currentProgram.getReferenceManager(); // 1. formatForSearch (string hash) + its callers Function fmt = fn("0x141a1afc0"); dec(fmt, "formatForSearch"); if (fmt != null) { int n = 0; for (Reference ref : rm.getReferencesTo(fmt.getEntryPoint())) { if (n++ >= 10) break; dec(fm.getFunctionContaining(ref.getFromAddress()), "caller of formatForSearch"); } } // 2. strings that hint at the track/content row builder -> xref functions String[] kw = {"djmdContent", "SearchStr", "formatForSearch", "AnalysisDataPath", "ContentID", "rb_data_status", "rb_local", "dsqlInsert", "AddTrack"}; DataIterator dit = currentProgram.getListing().getDefinedData(true); int shown = 0; while (dit.hasNext() && !monitor.isCancelled()) { Data d = dit.next(); if (d == null || !d.hasStringValue()) continue; Object v = d.getValue(); if (!(v instanceof String)) continue; String s = (String) v; for (String k : kw) { if (s.contains(k)) { out.println("\n// STRING @" + d.getAddress() + " : " + s); int n = 0; for (Reference ref : rm.getReferencesTo(d.getAddress())) { if (n++ >= 5) break; Function c = fm.getFunctionContaining(ref.getFromAddress()); out.println("// xref in " + (c != null ? c.getName() + " @" + c.getEntryPoint() : ref.getFromAddress())); } shown++; break; } } if (shown >= 30) break; } out.flush(); out.close(); println("wrote hash.txt"); } }