ilylty/android_eBPF_dump_dex

GitHub: ilylty/android_eBPF_dump_dex

Stars: 0 | Forks: 0

# android_eBPF_dump_dex Android ARM64 eBPF uprobe DEX dumper. ## Quick Start Use `run_dexdump_full.sh` on the device. Put these files in the same directory: /data/local/tmp/dex_dump_bin /data/local/tmp/dex_dump.bpf.o /data/local/tmp/run_dexdump_full.sh Deploy: adb push dex_dump.bpf.o /data/local/tmp/ adb push dex_dump_bin /data/local/tmp/ adb push run_dexdump_full.sh /data/local/tmp/ adb shell chmod +x /data/local/tmp/dex_dump_bin /data/local/tmp/run_dexdump_full.sh Run from a device-side root shell with full capabilities: adb shell su cd /data/local/tmp ./run_dexdump_full.sh run After the script is running and waiting for events, open the target protected app and interact with it until its unpacking or DEX loading logic is triggered. Background mode: cd /data/local/tmp ./run_dexdump_full.sh start ./run_dexdump_full.sh logs ./run_dexdump_full.sh stop The script automatically: - checks `dex_dump_bin` and `dex_dump.bpf.o` - writes diagnostics to `dexdump.log` - cleans old `dump_pid_*.dex` files - runs with `-scan` - dumps full DEX files by default with `MAX_DUMP=0` Useful script environment variables: - `EXTRA_ARGS`: extra arguments passed to `dex_dump_bin`, for example `-symbol ...` or `-offset 0x...` - `MAX_DUMP`: max bytes to dump per DEX region. Default is `0`, meaning full dump - `LIB`: ART DEX library path. Default is `/apex/com.android.art/lib64/libdexfile.so` - `OUT`: dump output directory. Default is the script directory - `WORKDIR`: directory containing `dex_dump_bin` and `dex_dump.bpf.o`. Default is the script directory Examples: ./run_dexdump_full.sh run MAX_DUMP=65536 ./run_dexdump_full.sh run EXTRA_ARGS="-symbol '_ZNK3art16ArtDexFileLoader4OpenEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPKNS_10OatDexFileEbbPS9_NS3_10unique_ptrINS_16DexFileContainerENS3_14default_deleteISH_EEEE'" ./run_dexdump_full.sh run EXTRA_ARGS="-offset 0x19a90" ./run_dexdump_full.sh run Pull results: adb pull /data/local/tmp . adb pull /data/local/tmp/dexdump.log . ## Build GitHub Actions builds two artifacts: - `dex_dump.bpf.o`: eBPF bytecode - `dex_dump_bin`: Android ARM64 user-space loader/dumper Run the `Build Android eBPF Dex Dumper` workflow manually from Actions, or push to `main`. ## Deploy adb push dex_dump.bpf.o /data/local/tmp/ adb push dex_dump_bin /data/local/tmp/ adb shell chmod +x /data/local/tmp/dex_dump_bin ## Run Run from a device-side root shell with full capabilities. On some devices, `adb shell su -c` inherits `adbd`'s limited capability bounding set and cannot load eBPF programs. Basic run: adb shell su cd /data/local/tmp ./dex_dump_bin -lib /apex/com.android.art/lib64/libdexfile.so -package com.example.target -max-dump 65536 If the package is already running, `-package` resolves the current PID and filters events to that PID. If the app starts after the dumper, either start the dumper without `-package`, or start the app first and then run the dumper with `-package`. Without `-package`, all DEX load events are observed: ./dex_dump_bin -lib /apex/com.android.art/lib64/libdexfile.so -max-dump 65536 Use an explicit symbol when testing a symbol found with `readelf`: ./dex_dump_bin \ -lib /apex/com.android.art/lib64/libdexfile.so \ -symbol '_ZNK3art16ArtDexFileLoader4OpenEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPKNS_10OatDexFileEbbPS9_NS3_10unique_ptrINS_16DexFileContainerENS3_14default_deleteISH_EEEE' \ -package com.example.target \ -max-dump 65536 Use a file offset if symbol lookup fails or symbols are stripped: ./dex_dump_bin \ -lib /apex/com.android.art/lib64/libdexfile.so \ -offset 0x19a90 \ -package com.example.target \ -max-dump 65536 Enable header scanning as a fallback. This scans readable memory ranges for DEX headers after startup and after DEX events: ./dex_dump_bin -lib /apex/com.android.art/lib64/libdexfile.so -package com.example.target -scan -max-dump 65536 If eBPF loading fails from ADB root, create and run a device-side script from a real root context, for example through a Magisk service or local terminal root shell: cd /data/local/tmp ./dex_dump_bin -lib /apex/com.android.art/lib64/libdexfile.so -package com.example.target -scan -max-dump 65536 Dumped files are written under `/data/local/tmp//`. File name format: dump_pid__0x__.dex Pull results: adb pull /data/local/tmp . adb pull /data/local/tmp/dexdump.log . Useful flags: - `-obj`: path to `dex_dump.bpf.o` - `-lib`: path to the ART DEX library, default `/apex/com.android.art/lib64/libdexfile.so` - `-symbol`: optional symbol name to uprobe. If not set, the program tries the built-in symbol list in `main.go` - `-offset`: optional file offset to uprobe. If non-zero, this overrides symbol lookup - `-out`: dump output directory, default `/data/local/tmp` - `-max-dump`: max bytes to dump per DEX region, default `65536`. Use `0` to dump the full reported size - `-package`: optional Android package name filter - `-scan`: scan target process memory for DEX headers after events. Requires `-package` for initial scan ## Finding Hook Symbols Different Android versions and ROMs put ART DEX loading code in different libraries. Do not assume `libart.so` always contains the function you need. This project currently hooks DEX memory-open functions where the first useful arguments are: x0 = this x1 = const uint8_t* base x2 = size_t size ### 1. Check Which Library Has The Symbols Start with `libdexfile.so`, then check `libart.so` if needed: adb shell "readelf -Ws /apex/com.android.art/lib64/libdexfile.so | grep -iE 'ArtDexFileLoader|DexFileLoader|DexFileC|OpenCommon|OpenWithDataSection'" adb shell "readelf -Ws /apex/com.android.art/lib64/libart.so | grep -iE 'ArtDexFileLoader|DexFileLoader|DexFileC|OpenCommon|OpenWithDataSection'" Useful symbols usually look like one of these: art::ArtDexFileLoader::Open(const uint8_t*, size_t, ...) art::DexFileLoader::Open(const uint8_t*, size_t, ...) art::DexFileLoader::OpenWithDataSection(const uint8_t*, size_t, ...) art::DexFile::DexFile(const uint8_t*, size_t, ...) In mangled form, examples from one tested device were: _ZNK3art16ArtDexFileLoader4OpenEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPKNS_10OatDexFileEbbPS9_NS3_10unique_ptrINS_16DexFileContainerENS3_14default_deleteISH_EEEE _ZNK3art13DexFileLoader4OpenEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPKNS_10OatDexFileEbbPS9_NS3_10unique_ptrINS_16DexFileContainerENS3_14default_deleteISH_EEEE _ZN3art7DexFileC2EPKhmS2_mRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPKNS_10OatDexFileENS3_10unique_ptrINS_16DexFileContainerENS3_14default_deleteISG_EEEEb The important part is `EPKhm` in the mangled name. It means the function has `const uint8_t*` and `size_t` arguments, which are the DEX base and DEX size. ### 2. Ignore Undefined Symbols `readelf` may show `UND` entries. Those are imports, not implementations. Hook the library that contains a real address. Good: 0000000000019a90 FUNC GLOBAL PROTECTED ... _ZNK3art16ArtDexFileLoader4OpenEPKhm... Bad: 0000000000000000 FUNC GLOBAL DEFAULT UND _ZNK3art16ArtDexFileLoader4OpenEPKhm... If the symbol is `UND` in `libart.so`, check `libdexfile.so`. ### 3. Test A Symbol Without Rebuilding If you found a symbol in `libdexfile.so`, pass it with `-symbol`: ./dex_dump_bin \ -lib /apex/com.android.art/lib64/libdexfile.so \ -symbol '_ZNK3art16ArtDexFileLoader4OpenEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPKNS_10OatDexFileEbbPS9_NS3_10unique_ptrINS_16DexFileContainerENS3_14default_deleteISH_EEEE' \ -package com.example.target \ -max-dump 65536 If symbol names are stripped or `link.Uprobe` cannot resolve them, use the symbol value from `readelf` as a file offset: ./dex_dump_bin \ -lib /apex/com.android.art/lib64/libdexfile.so \ -offset 0x19a90 \ -package com.example.target \ -max-dump 65536 ### 4. What To Change In `main.go` Most of the time, you only need to change the default library or the built-in symbol list. Default library path is in `main.go`: libPath := flag.String("lib", "/apex/com.android.art/lib64/libdexfile.so", "path to target ART dex library") Built-in symbols are in `attachDexOpen()`: symbols := []string{ "_ZNK3art16ArtDexFileLoader4OpenEPKhm...", "_ZNK3art13DexFileLoader4OpenEPKhm...", "_ZN3art7DexFileC2EPKhmS2_m...", } Add the symbol you found to this list, preferably near the top if it is the best match for your ROM. You do not need to edit `main.go` if you use `-symbol` or `-offset` from the command line. ### 5. When You Must Change `dex_dump.bpf.c` Only change the eBPF argument registers if the function signature is different. Current expected layout: x1 = DEX base x2 = DEX size If you hook a function where the DEX pointer and size are in different arguments, update `dex_dump.bpf.c` accordingly. For example: event.base = ctx->regs[1]; event.size = ctx->regs[2]; Change `regs[1]` and `regs[2]` to the correct ARM64 argument registers for the function you selected. ### 6. Practical Workflow 1. Run `readelf -Ws` on `libdexfile.so` and `libart.so`. 2. Pick a defined symbol containing `EPKhm` or an equivalent `const uint8_t*, size_t` signature. 3. Test it with `-symbol` first. 4. If symbol lookup fails, test with `-offset` using the address from `readelf`. 5. If it works, optionally add the symbol to `attachDexOpen()` in `main.go`. 6. Rebuild and redeploy. ## Root Notes On some Magisk/rooted devices, `adb shell su -c` still lacks the capabilities required to load eBPF programs because it inherits `adbd`'s restricted capability bounding set. If loading fails with `operation not permitted` or memlock/capability errors, run the dumper from a real device-side root context, such as a Magisk service script or local root shell with full capabilities.
标签:EVTX分析