rev-dex-dumper - Android DEX Dumper
Dump DEX files from a running Android application's memory via ADB. Two bundled tools (arm64):
| Tool | Access path | Freezes target | Role |
|---|---|---|---|
panda-dex-dumper |
/proc/<pid>/mem |
SIGSTOP / SIGCONT | primary |
mem-dex-dumper |
/proc/<pid>/mem or process_vm_readv(2) |
none | alternative / cross-check |
Neither tool uses ptrace. They read process memory directly (/proc/<pid>/mem; mem-dex-dumper can also use process_vm_readv(2)) and still work against a process that has claimed the ptrace slot via PTRACE_TRACEME (TracerPid != 0): anti-debug that polices TracerPid or blocks PTRACE_ATTACH does not stop them, while a genuinely ptrace-based dumper would be blocked.
Tool Location
The binaries are bundled in this skill's directory. Resolve absolute paths relative to this SKILL.md file:
skills/rev-dex-dumper/panda-dex-dumper
skills/rev-dex-dumper/mem-dex-dumper
skills/rev-dex-dumper/mem-dex-dumper.c (source)
Workflow
1. Push the tool to device
adb push <path-to>/panda-dex-dumper /data/local/tmp/
adb shell chmod +x /data/local/tmp/panda-dex-dumper
2. Determine target package name
If the user provides a package name, use it directly. Otherwise, get the foreground app:
adb shell dumpsys activity top | grep 'ACTIVITY' | tail -1 | awk '{print $2}' | cut -d/ -f1
3. Run the dumper
adb shell "cd /data/local/tmp && ./panda-dex-dumper -p $(adb shell pidof <package_name>)"
The dumped DEX files are saved to /data/local/tmp/panda/ on the device.
4. Pull DEX files to host
adb pull /data/local/tmp/panda/ ./
Pull to the user's current working directory.
5. Clean up device cache
adb shell rm -rf /data/local/tmp/panda/
adb shell rm /data/local/tmp/panda-dex-dumper
mem-dex-dumper (alternative / cross-check)
adb push <path-to>/mem-dex-dumper /data/local/tmp/
adb shell chmod +x /data/local/tmp/mem-dex-dumper
adb shell "su -c 'cd /data/local/tmp && ./mem-dex-dumper -p <pid> -o /data/local/tmp/memdump'"
adb pull /data/local/tmp/memdump/ ./
adb shell "su -c 'rm -rf /data/local/tmp/memdump/ /data/local/tmp/mem-dex-dumper'"
Options: -p <pid> (required), -o <outdir> (default /data/local/tmp/memdump), -b mem|vmreadv (default mem = /proc/<pid>/mem; vmreadv = process_vm_readv(2)). Use it to cross-check a panda dump, for extra coverage, or when the target must not be frozen.
Source: mem-dex-dumper.c in this directory. Rebuild with the NDK (r21+):
aarch64-linux-android29-clang -O2 -static -o mem-dex-dumper mem-dex-dumper.c
llvm-strip mem-dex-dumper
Background
mem-dex-dumperis a tool we developed in-house — source (mem-dex-dumper.c) and rebuild steps ship with the skill. When it misbehaves, fix the source and rebuild (see Debugging / fixing below).panda-dex-dumperis a third-party binary without source, so it can only be worked around, not fixed.- The two tools cross-check each other: for the same address, output is byte-identical whenever both choose the same size.
How it works
- Parse
/proc/<pid>/maps; iterate readable regions ≥ 0x70 bytes. - Read in 1 MiB chunks with a 7-byte overlap, so a
dex\nmagic straddling a chunk boundary is still seen. - Scan for
dex\n+ 3 digits + NUL (any DEX version). try_dump()validates the header before dumping:header_size == 0x70,endian_tag∈ {0x12345678, 0x78563412},0x70 ≤ file_size ≤ 1 GiB,string_ids/class_defstables insidefile_size.- Dedupe: hits inside an already-dumped range are skipped (also suppresses re-hits from chunk overlap).
- Dump
file_sizebytes in 1 MiB chunks; on a failed read keep the partial data (dumped < file_sizein the log).
Per-hit log: find dex off: 0x<addr> file_size: 0x<n> dumped: 0x<n>; final line scanned <N> bytes, done. — the primary diagnostic surface.
Known issues
| Symptom | Cause | Action |
|---|---|---|
open /proc/<pid>/mem: Permission denied |
not root / SELinux / kernel restriction | run via su -c; if still denied, try -b vmreadv |
-b vmreadv fails (EPERM/EINVAL) |
kernel/SELinux blocks process_vm_readv for the target |
use the default backend; syscall presence: grep process_vm_readv /proc/kallsyms |
| No hits although the app is packed | payload not decrypted yet, or header intentionally scrambled | keep the app foregrounded past splash; cross-check with panda |
| Fewer files than panda | (a) strict validation rejects corrupted headers that panda dumps as guess_size fragments; (b) range-dedupe swallows a DEX nested inside a bigger claimed range |
compare logs; for (b) bypass in_dumped() temporarily, or extract the inner address manually (dd from /proc/<pid>/mem) |
| Very large file (tens of MB) | .vdex-embedded header with inflated file_size |
noise — the payload lives in anon heap ([anon:libc_malloc]); verify structure first |
| Some classes fail to parse | torn live read (packer wrote memory while scanning) | re-run; if reproducible, prefer panda (SIGSTOP gives a frozen snapshot) |
| Won't exec on another device | arm64-only, static, API 29 | rebuild for the target ABI (above) |
Not bugs: extra/missing hits vs panda in mapped system-jar territory (/system/framework/*.jar, /apex/*/javalib/*.jar, *.vdex) — different scan heuristics, treat as noise. pidof returning several PIDs: dump each process separately, the payload may live in any of them.
Debugging / fixing
- Read stdout first: per-hit lines +
scanned N bytes. Name each hit's mapping withgrep <addr-prefix> /proc/<pid>/maps(file-backed = usually system noise; anon heap = payload). - Validate a suspicious dump structurally (header fields + class descriptors) before blaming the tool.
- Missing hits → loosen
try_dump()checks (start withheader_size), or confirm the region is readable (ddfrom/proc/<pid>/mem). - Compare with panda on shared addresses — md5-equal means both extracted the same bytes.
- Sandbox: a tiny process that loads a known DEX into heap and sleeps (run via
su) is a good repro target — dump it with both backends, compare md5 with the source file. - After any change: rebuild + strip (above), re-run the sandbox test, keep the log format stable.
Guidelines
- Always verify ADB connection first — run
adb devicesand confirm a device is listed before proceeding. - Root is required — both tools read another UID's process memory. On production builds
adb rootfails; run viasu -c. - Wait for app to fully load — if the user is dumping a packed app, the real DEX is only available after the packer's class loader has decrypted it. Advise the user to navigate past the splash screen before dumping.
- Handle pidof failure — if
pidofreturns empty, the app may not be running. Launch it first withadb shell monkey -p <package_name> -c android.intent.category.LAUNCHER 1. - Multiple DEX files are normal — packed apps often produce several DEX files. All files in
/data/local/tmp/panda/should be pulled. - Always clean up — remove both the dumped DEX files and the tool binary from the device after pulling results to avoid leaving artifacts.