97 lines
4.2 KiB
Java
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");
|
|
}
|
|
}
|