SuperAPI AI Directory

re-mobile-pack

General & other

View repository

Updated 10-15 21:34

About this skill

Android hardening unpacking (DEX recovery)

When to use / when not to use

  • Use: obtained an Android hardened (Legu/360/Bangbang/AiJiami, etc.) App and need to restore the real DEX to continue static analysis
  • Use: [[re-apk]] has identified hardening and a unpacking path needs to be chosen
  • Use: unpacked output has empty method bodies / instruction extraction and needs repair
  • Do not use: hardening is unconfirmed—first confirm statically with [[re-apk]]; ordinary Apps can just use jadx directly
  • Do not use: strong shells mainly based on VMP virtualization—switch to [[re-anti-analysis]] ([[re-unpack-advanced]] approach)
  • Do not use: need runtime hook / bypass detection (that is [[re-frida]])

Tool preparation

Dynamic unpacking is by default executed within a controlled device / emulator snapshot ([[re-analyze/platform-tips]] highest principle—default sandbox). Verify all tools before use.

frida + frida-dexdump —— main force for runtime unpacking

  • frida-tools: all platforms pip install frida-tools(Python 3.8+; venv recommended); the frida-server version must match the host and be pushed to the device (for the complete installation and anti-detection process see [[re-frida]] tool preparation)
  • frida-dexdump: all platforms pip install frida-dexdump(Python 3) —— searches the DEX magic in memory at runtime and dumps it
  • Verify: frida --version;frida-dexdump -h(can see the -U/-f/-d parameter)
  • Usage: frida-dexdump -U -f <包名>(spawn to start unpacking),frida-dexdump -U <pid>(attach)、frida-dexdump -U -f <包名> -d(deep search, covers multiple DEX / partial extraction)

BlackDex —— static unpacking machine (no frida required, the preferred alternative for ordinary hardening)

  • Install: download the APK from the GitHub release——https://github.com/CodingGay/BlackDex/releases; 32-bit and 64-bit are two separate APKs (if the target App does not appear in the list, switch to the other architecture version)
  • Environment: ordinary Android phone or emulator, Android 5.0~12, no root / customized environment required
  • Capability: covers three types of shells: landed loading / in-memory loading / instruction extraction; deep mode backfills method bodies for instruction extraction (experimental, may take several minutes or fail)
  • Output: hook_*.dex(obtained by hooking system APIs) and cookie_*.dex(DexFile cookie technique)
  • Verify: after installation it can list the target App and complete unpacking

Youpk —— active-call unpacking machine (the strongest path for extraction hardening)

  • Source/ROM: https://github.com/Youlor/Youpk——based on secondary development of Android 7.1.2_r33,only supports Google Pixel 1: after building with Android Studio flash-all.sh flash the custom ROM
  • Usage: adb shell "echo <包名> >> /data/local/tmp/unpacker.config" → launch the target App to automatically perform active-call unpacking (see "unpack end" in the log) → adb pull /data/data/<包名>/unpacker
  • Repair: java -jar dexfixer.jar ./unpacker ./out(accompanying DEX repair, backfills method instructions)
  • Verify: adb shell ls /data/data/<包名>/unpacker can see dex/method output

jadx —— decompile after unpacking (reuse [[re-apk]])

  • For cross-OS installation and verification see [[re-apk]] tool preparation; jadx supports direct analysis of multiple DEX and avoids manual merging

adb —— device interaction

  • Included with Android SDK platform-tools; verify adb --version; for emulator scenarios adb shell is enough
  • dexdump: bundled with the Android SDK build-tools (used in step 4 for DEX integrity checks); verify dexdump -h

Memory dump ([[re-memdump]] approach)

  • frida/objection memory dump or follow [[re-memdump]] to grep the DEX magic from the dump dex\n0xx extraction—the fallback path when frida-dexdump is unavailable

Procedure

Execute in order, archive each step's artifact (DEX path + sha256) (see [[re-triage]]).

  1. Packer identification (confirm before acting):

    • Class-name features: jadx decompilation only shows wrapper classes—com.stub.StubApp(ijiami),com.secneo.apkwrapper / com.bangcle.*(Bangcle), etc.; the entry Application is replaced by a wrapper class
    • Wrapper so features: ls out/lib/——libjiagu.so / libprotectClass.so(360 hardening),libDexHelper.so / libexec.so(ijiami),libsecexe.so / libsecmain.so(Bangcle)
    • DEX size: ls -la out/classes*.dex—the real DEX is stored encrypted (in assets/ or decrypted at runtime), and classes.dex inside the wrapper is abnormally small
    • Record the identified packer name to decide the path: conventional whole/ extraction hardening → this skill; virtualization-dominant → [[re-anti-analysis]]
  2. Runtime unpacking (frida-dexdump, default path):

    adb shell monkey -p <包名> 1            # 先启动 App,让壳把真 dex 加载进内存
    frida-dexdump -U -f <包名>              # 或 spawn 起步
    frida-dexdump -U <pid>                  # 已运行 attach
    frida-dexdump -U -f <包名> -d           # 深度搜索(多 DEX / 部分抽取场景)
    

    Artifacts are in the current directory <包名>/<时间戳>/*.dex。Timing: dump after the App has reached the business page ([[re-analyze/platform-tips]] key experience—dump timing); dumping right at startup only gets the packer's initial state.

  3. Static unpacking (BlackDex / Youpk, the alternative path when frida is detected):

    • BlackDex: install the APK for the corresponding architecture → select the target App → unpack (a few seconds for ordinary packers; enable deep mode for extraction packers, takes several minutes and risks failure) → export artifacts
    • Youpk (preferred for extraction hardening): flash Pixel 1 ROM → write the package-name configuration → launch the App and wait for automatic unpacking → pull unpacker/ directory → java -jar dexfixer.jar ./unpacker ./out
    • Cross-validation: compare artifacts from the two paths (the same method body should match); if they differ, take the more complete one
  4. DEX repair and integrity check:

    file out/*.dex                          # 应见 "Dalvik dex file version 035"(magic: dex\n035\0)
    dexdump out/classes.dex 2>/dev/null | head -30
    jadx -d java-out out/                   # 反编译验证:业务类是否齐全
    
    • Empty method bodies (CodeItem all nop / direct throw) → instruction-extraction packer did not backfill: re-unpack with dexfixer (bundled with Youpk artifacts) or BlackDex deep mode; if still failing → actively call methods to trigger execution and then dump ([[re-memdump]] approach)
    • Multiple DEX: check whether classes.dex / classes2.dex / ... are complete; frida-dexdump -d deep search as a fallback; jadx analyzes multiple DEX directly
    • After repair, you must decompile and spot-check before proceeding to business analysis (see pitfall 3)
  5. Post-unpacking analysis (follow the full [[re-apk]] workflow):

    • manifest entry/permissions → jadx decompile business code → locate the target logic (keys/protocol/checks)
    • Need to change behavior → smali patch + repackage and sign ([[re-apk]] step 4)
    • Native so (packer so / JNI business so) → [[re-binary-core]] ([[re-format-elf]] + [[re-ghidra]]); the packer's own anti-debugging/verification countermeasures → [[re-anti-analysis]]

Cross-domain combination

  • [[re-mobile]]: step 5 of the workflow, the hardening branch, always calls this skill (transferred after [[re-apk]] identification)
  • [[re-apk]]: packer identification (step 5) and post-unpacking static analysis (manifest / jadx / smali)
  • [[re-frida]]: runtime unpacking execution environment + anti-frida detection countermeasures (rename / change port / gadget)
  • [[re-memdump]]: In-memory DEX extraction approach (dump timing, magic scanning, multi-DEX fallback)
  • [[re-anti-analysis]]: VMP / virtualization hardening countermeasures (extraction + virtualization combined packer to strong packer workflow)
  • [[re-binary-core]]: Packer so / JNI native logic analysis ([[re-format-elf]] / [[re-ghidra]])
  • [[re-analyze/platform-tips]]: Default sandbox (emulator snapshot), key experience on dump timing
  • This skill is referenced by the triage "Mobile App Analysis" path of [[re-analyze]] (re-mobile → re-apk identify hardening → re-mobile-pack)

Common pitfalls and traps

  • VMP-level hardening (extraction + instruction virtualization) is very difficult to unpack: Symptoms — after frida-dexdump / BlackDex produce a DEX, method bodies are largely nop / empty shells, and some method logic can never be found in the dex; Cause — besides extracting instructions, the packer virtualizes key methods into the so (custom VM interpreted execution), and this part cannot be restored at the DEX layer; Countermeasures — when identified as an extraction + virtualization combination: for the extracted part use Youpk active invocation repair, for the virtualized part abandon DEX restoration and instead use dynamic [[re-frida]] hook to observe inputs and outputs, or restore the VM interpreter (high cost, mark the scope and switch to the [[re-anti-analysis]] strong packer approach)
  • Anti-frida detection: Symptoms — crash on spawn, frida-dexdump cannot connect or dumps empty results; Cause — the packer detects fingerprints such as the frida-server port 27042 / path / characteristic thread (gum-js-loop); Countermeasures — rename + change port according to the anti-detection section of [[re-frida]]; if still detected → switch to BlackDex / Youpk (which do not depend on frida) or frida-gadget injection
  • Incomplete DEX repair (method bodies empty shells): Symptoms — when jadx opens the unpacked DEX, half the methods have no decompiled content or directly throw; Cause — the CodeItem of the instruction-extraction packer was not backfilled (dump timing earlier than method execution / the repairer did not handle it); Countermeasures — dexfixer repair (bundled with Youpk output) or BlackDex deep mode re-unpack; trigger method execution with active invocation and then [[re-memdump]] dump; after repair do dexdump spot checks + jadx decompilation verification before proceeding to analysis
  • Multi-DEX merge/loss: Symptoms — only a single classes.dex is dumped, jadx reports missing classes / nonexistent references; Cause — after hardening, multiple DEX are loaded by the packer at runtime, and the default frida-dexdump search may miss them; Countermeasures —-d deep search, hook ClassLoader to enumerate loaded dex ([[re-frida]] enumeration), memory dump to extract all; jadx directly loads all dex for analysis
  • Dump timing too early: Symptoms — the dumped DEX cannot be opened / is the packer's initial data; Cause — the real dex has not yet been decrypted and loaded; Countermeasures — wait until the App enters a business page before dumping ([[re-analyze/platform-tips]] key experience on dump timing, the opposite end from "save immediately when decrypted data is seen")
  • PairIP (Google Play automatic protection) three gates: Symptoms — in JADX the key methods are only left with VMRunner.invoke("...") empty shells, and on the emulator it exits after running for a few seconds; Cause — the three-piece hardening automatically applied on Play listing: ①code virtualization: logic is extracted into an encrypted VM blob (random-named extensionless file in assets,\x00IAP header as decryption criterion) + native interpreter libpairipcore.so(executeVM and other symbol names are decoded at runtime from an XOR table and cannot be found via strings); ②TEE key: the blob is AES/GCM ciphertext, the wrapping key is stored in the device TEE (AndroidKeyStore), and Play delivers it via importWrappedKey(SecureKeyWrapper ASN.1) — three hard preconditions: Play installation (gpdeku split carrier), passes Play Integrity, has a Google account logged in; missing any one means the Finsky log shows FAILURE → local forgery isEncryptionKeyPresent() is also useless; ③ runtime anti-tampering:dl_iterate_phdr/opendir scans maps and finds an injected so → deliberately feeds an illegal length to std::vector → std::__throw_length_error abort (tombstone fingerprint length_error was thrown in -fno-exceptions mode) → if abort is neutralized, execution flow falls to the instruction after abort, stomps memory, SIGSEGV + SIG_DFL reset——signal-layer hooks can't stop it; the root cause is on the detection side (maps doesn't show its face); countermeasure——first pass Integrity (three-green real device or PlayIntegrityFix) + clear visible injection modules (restart after Zygisk disable)
  • PairIP plaintext extraction: call rather than hook: symptom——hooking VMRunner any method (getVmByteCode/executeVM/readByteCode) makes the process self-destruct immediately; cause——PairIP watches ArtMethod integrity: a frida hook rewriting entry_point_from_quick_compiled_code hits the detection; countermeasure——reflection directly callsthe decryption function (getVmByteCode is private static, callable via frida reflection; whether the blob name carries the assets/ prefix is inconsistent across versions, try both), with zero hooks and zero ArtMethod changes you can decrypt all blob plaintext——stripping PairIP doesn't need kernel-level stealth, only dynamic tracing of the interpreter requires it
  • Repackaging a hardened APK directly → black screen on real device: symptom——repackaging a hardened APK via apktool, after signing and installing the real device shows a black screen (process alive, no crash), while the same APK on an emulator "looks normal"; cause——repackaging rebuilds the DEX from smali, breaking the shell's layout and self-verification assumptions; the shell can't locate/verify the encrypted payload → no decryption → all platform channel handlers in the real DEX throw MissingPluginException → uncaught exceptions tear down rendering; on the emulator the shell's verification is relaxed, "runs on emulator" is not evidence; countermeasure——before repackaging, first do hardening detection (shell runtime so in assets (lib*sec*/lib*shell* style), dynamic DEX loader so, shell stub entry class, a single oversized classes.dex with no business strings, smali→dex round-trip splitting out multiple empty stub DEXs); if hardening is confirmed, abandon apktool repackaging; dumping memory must hit the decryption window——the shell transiently self-unloads,/proc/self/maps you may not even see the shell in it, too early/too late and you can't get the decrypted DEX; if the app itself also self-checks "whether the shell exists", unpacking needs to neutralize that check as well (source: reverse-skills (inliver233), MIT)
  • Hardened target delivery paths: unpack-and-repackage / repack-free injection / resident gadget:Phenomenon—the unpacked target runs abnormally after being directly unpacked and repackaged, or it is unclear which modification/delivery path to choose; Cause—after unpacking and repackaging, the packer artifacts are not completely cleaned up, and the packer runtime conflicts with the plaintext DEX; Countermeasure—choose according to the target state: Path a, unpack-and-repackage (high fidelity): blackdex / FART / frida-dexdump retrieve the real DEX from the live process during the decryption window and then repackage it (the packer is no longer needed); before repackaging, clear all packer artifacts (packer runtime so, packer directory, DEX loader); Path b, repackaging-free injection (do not reinstall the DEX, the packer and self-check remain completely untouched, low risk to the packer, preferred): replace libapp.so in place + use an LSPatch-like tool to inject a Java hook; note that the target may detect the injection framework itself (detection strings are common), which is an integrity signal that must be handled as well; Path c, persistent gadget (zero file changes): inject frida-gadget + a boot auto-start script to perform runtime signature adaptation and in-memory patch of libapp; note that the gadget can be detected, and runtime flipping of coupled check flags may backfire; not recommended to reverse-engineer the packer's verification logic to forcibly pass apktool repackaging—high difficulty and low payoff (Source: reverse-skills (inliver233), MIT)