Files
maple/maple-py/re/README.md
T
2026-06-08 23:22:16 +10:00

55 lines
2.5 KiB
Markdown

# 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):
```bash
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.