Files
2026-06-08 23:22:16 +10:00

2.5 KiB

re/ — rekordbox export.pdb reverse-engineering

Shared record of the Ghidra/Frida work behind maple's pdb writer. See the top-level README.md for the high-level findings; this dir holds the raw artifacts so others can reproduce and extend the analysis.

What's here

scripts/ — Ghidra headless scripts (run against an analyzed rekordbox.exe):

  • FindPdb.java — locate the writer via string + magic-constant xrefs
  • DecPdb.java — decompile an explicit list of addresses
  • CallTree.java — walk a call tree, flag file-I/O / 4096-using functions
  • FindHash.java — hunt the per-track hash: decompile formatForSearch + callers + content-string xrefs

findings/ — script output (decompiled C + xref maps):

  • findpdb.txt — string xrefs → the export functions; magic-constant hit counts
  • decpdb.txt — decompiled export.pdb serializer call stack (DeviceSQL Page Manager)
  • calltree.txt — call tree under the export orchestrator FUN_14119d2d0
  • hash.txt — formatForSearch + callers + djmdContent/ContentID xrefs

Reproduce (not committed: the binary + Ghidra project)

rekordbox.exe and the analyzed Ghidra project are not in the repo (copyright + size). To rebuild from your own rekordbox install (Windows path visible from WSL):

export JAVA_HOME=~/jdk/jdk-21.0.11+10            # Ghidra needs JDK 21
GH=/path/to/ghidra_12.1.2_PUBLIC
# one-time: import + analyze (~1h, 10G heap, 8 cores)
GHIDRA_HEADLESS_MAXMEM=10G "$GH/support/analyzeHeadless" ~/ghidra_proj rbx \
    -import "/mnt/c/Program Files/rekordbox/rekordbox 7.0.5/rekordbox.exe" \
    -overwrite -max-cpu 8 -analysisTimeoutPerFile 7200
# then run any script without re-analyzing:
"$GH/support/analyzeHeadless" ~/ghidra_proj rbx -process rekordbox.exe -noanalysis \
    -scriptPath re/scripts -postScript FindPdb.java

Runtime→Ghidra address map: static = 0x140000000 + module_offset (Ghidra image base 0x140000000; ASLR runtime base varies — read rekordbox.exe+0xOFFSET from the Frida agent, never hardcode it).

Live capture (Frida, Windows)

../tools/capture.mjs (Node, npm i frida) + ../tools/rbx_pdb_capture.js (agent). Child-gates so the CIG-protected writer is hooked at spawn: node tools/capture.mjs --spawn.

Open questions

  • per-track 0x14 (28-bit) — varies per track, not a plain crc32; likely a stored djmdContent value. 0x18/0x1a are a per-export constant.
  • index_shift (row 0x02) — positional (~0x20/row, resets per page) but the exact formula isn't pinned. maple writes 0; rekordbox doesn't.