Skip to content

Oat2Dex | Android pentesting (Medium)

Source

Content

DEX and OAT

  • DEX (Dalvik Executable): bytecode container executed by Android Runtime (ART). A typical APK includes classes.dex with app classes and methods. Java/Kotlin sources compile to .class, then are merged/converted into .dex for ART (different opcodes than classic JVM bytecode).

  • OAT: produced by the OS to speed app load. On install/boot, ART optimizes app bytecode; the optimized artifact is often described as an OAT (implementation-wise tied to ELF). Paths and layout vary by Android version and OEM; the article cites examples such as /data/dalvik-cache/ and dex2oat under /system/bin/dex2oat/. On Android 5.0+, ART uses AOT plus profiling/JIT behavior; pre-Lollipop used .odex (optimized DEX) more prominently than modern OAT-centric flows.

  • dex2oat: ART component that compiles DEX to native code for the optimized artifact. The article states optimized output is ELF-shaped even when referred to as OAT.

Oat2dex (SmaliEx)

Purpose: convert AOT-compiled / optimized artifacts back toward DEX for static analysis (e.g. when you lack a full APK or classes.dex, such as system apps).

Why it matters (article’s framing):

  • System apps may not ship as a user-installable APK you can trivially pull.
  • You may only have optimized on-device bytecode (e.g. from cache-style locations), not the original DEX inside an APK.

boot.oat (article):

  • Described as produced on system upgrade or first boot after purchase, and referenced when apps call framework APIs.

Workflow (condensed from article):

  1. Download SmaliEx from GitHub and extract.

  2. Build distribution (article uses Gradle):

    bash
    gradlew -b smaliex/build.gradle dist
  3. Use oat2dex.jar from the produced smaliex-bin output (article suggests optionally copying the JAR to the repo root for convenience).

  4. On device, locate boot.oat (article example path segment: /data/dalvik-cache/x86/ — treat as illustrative; verify on your device/image).

  5. Pull boot.oat to the host, then de-optimize boot classes:

    bash
    java -jar oat2dex.jar boot <path-to-system@framework@boot.oat>

    Output: folder of de-optimized DEX files for boot/framework.

  6. Pull an optimized per-app artifact from /data/dalvik-cache/ (article uses Calculator as an example; the exact adb pull path is only in the article’s screenshots), then de-optimize with oat2dex.jar using the boot DEX output as context. The full java -jar oat2dex.jar … line for that step is likewise in images on Medium, not in the article body—use SmaliEx documentation for the current subcommands and arguments.

  7. Convert resulting DEX with dex2jar / JD-GUI or disassemble with baksmali / similar (article mentions JD-GUI: http://jd.benow.ca/ — may be outdated; prefer current jd-gui releases).

Direct smali from odex/oat (article):

  • Pull .odex from /system/app/... (paths differ by API level and split APK layout).

  • Run:

    bash
    java -jar oat2dex.jar smali <path-to-odex-or-oat>

    to emit smali with optimized opcodes (article notes additional commands exist upstream).

Caveats

  • 2018 article: Android paths, dalvik-cache usage, and /system/app vs /system/priv-app layouts have evolved; always confirm on your target API.
  • Prefer SmaliEx / oat2dex upstream README for authoritative CLI and supported Android versions.

Key takeaways

  • DEX is the APK-level bytecode container; ART ahead-of-time compilation produces optimized artifacts the article groups under OAT, backed by ELF.
  • oat2dex helps recover analyzable DEX when you only have optimized on-device output—useful for system components without a simple APK.
  • boot.oat / boot classpath artifacts de-optimize first, then enable de-optimizing app-specific optimized files.
  • Pair recovered DEX with dex2jar + decompiler UI or smali pipelines for review.

See also

Personal notes