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 xrefsDecPdb.java— decompile an explicit list of addressesCallTree.java— walk a call tree, flag file-I/O / 4096-using functionsFindHash.java— hunt the per-track hash: decompileformatForSearch+ callers + content-string xrefs
findings/ — script output (decompiled C + xref maps):
findpdb.txt— string xrefs → the export functions; magic-constant hit countsdecpdb.txt— decompiledexport.pdbserializer call stack (DeviceSQL Page Manager)calltree.txt— call tree under the export orchestratorFUN_14119d2d0hash.txt—formatForSearch+ callers +djmdContent/ContentIDxrefs
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 storeddjmdContentvalue.0x18/0x1aare a per-export constant. index_shift(row0x02) — positional (~0x20/row, resets per page) but the exact formula isn't pinned. maple writes0; rekordbox doesn't.