Files
maple/maple-py/re/scripts/FindPdb.java
T
2026-06-08 23:22:16 +10:00

97 lines
4.2 KiB
Java

// Locate the rekordbox .pdb serializer via known strings + magic-number constants.
// Run headless: analyzeHeadless <proj> rbx -process rekordbox.exe -noanalysis \
// -scriptPath ~/ghidra_scripts -postScript FindPdb.java
// Output goes to ~/ghidra_proj/findpdb.txt (and the log).
import java.io.PrintWriter;
import java.util.*;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.*;
import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.*;
public class FindPdb extends GhidraScript {
// Strings that mark the export code paths.
static final String[] KEYWORDS = {
"export.pdb", "exportExt.pdb", "USBANLZ", "PIONEER",
"ANLZ", "HOT CUE BANK", "ORIGINAL ARTIST", "rekordbox/export"
};
// Magic numbers maple currently guesses (various widths/combinations).
static final long[] MAGICS = {
42343L, 54995L, // 0xA567 / 0xD6D3 per-track markers
0xD6D3A567L, 0xA567D6D3L, // combined 32-bit forms
788224L, // 0x000C0700 track bitmask
1004L, // 0x03EC "strange page" marker
0x64L, 0x44L, 0x24L, // page-flag bytes
19048L, 30967L // the schema author's original guesses
};
PrintWriter out;
void emit(String s) { println(s); if (out != null) out.println(s); }
@Override
public void run() throws Exception {
out = new PrintWriter("/home/ntr/ghidra_proj/findpdb.txt");
Listing listing = currentProgram.getListing();
ReferenceManager rm = currentProgram.getReferenceManager();
FunctionManager fm = currentProgram.getFunctionManager();
emit("===== STRING XREFS =====");
DataIterator di = listing.getDefinedData(true);
while (di.hasNext() && !monitor.isCancelled()) {
Data d = di.next();
if (d == null || !d.hasStringValue()) continue;
Object val = d.getValue();
if (!(val instanceof String)) continue;
String s = (String) val;
for (String kw : KEYWORDS) {
if (s.contains(kw)) {
emit("\nSTRING @ " + d.getAddress() + " : " + s.replace("\n", "\\n"));
ReferenceIterator ri = rm.getReferencesTo(d.getAddress());
int n = 0;
while (ri.hasNext() && n++ < 25) {
Reference r = ri.next();
Function f = fm.getFunctionContaining(r.getFromAddress());
emit(" xref from " + r.getFromAddress()
+ (f != null ? " in " + f.getName() + " @ " + f.getEntryPoint() : " (no func)"));
}
break;
}
}
}
emit("\n===== CONSTANT XREFS =====");
Set<Long> targets = new HashSet<>();
for (long m : MAGICS) targets.add(m);
Map<Long, Integer> counts = new TreeMap<>();
InstructionIterator ii = listing.getInstructions(true);
while (ii.hasNext() && !monitor.isCancelled()) {
Instruction insn = ii.next();
for (int op = 0; op < insn.getNumOperands(); op++) {
for (Object o : insn.getOpObjects(op)) {
if (o instanceof Scalar) {
long v = ((Scalar) o).getUnsignedValue();
if (targets.contains(v)) {
Function f = fm.getFunctionContaining(insn.getAddress());
emit(String.format("CONST 0x%X (%d) @ %s %s in %s", v, v,
insn.getAddress(), insn.toString(),
f != null ? f.getName() + " @ " + f.getEntryPoint() : "(no func)"));
counts.merge(v, 1, Integer::sum);
}
}
}
}
}
emit("\n===== CONSTANT HIT COUNTS =====");
for (Map.Entry<Long, Integer> e : counts.entrySet())
emit(String.format("0x%X (%d): %d hits", e.getKey(), e.getKey(), e.getValue()));
out.flush();
out.close();
emit("\nwrote /home/ntr/ghidra_proj/findpdb.txt");
}
}