SReverseby Simpa Labs

Protected builds

Reading OAT, VDEX and compact DEX files

The DEX file inside an APK describes the code the developer compiled. The code the device runs was prepared afterwards from that file, and on many devices the two are different artifacts in different locations.

What each artifact contains

Android compiles application code ahead of time or as it runs, and the output is stored in several files whose names describe their contents. Reading a request flow means knowing which of them holds the description of the code and which holds the executable result.

  • OAT holds the same code compiled for the device. The file keeps the method bodies that were translated into machine instructions together with the metadata the runtime needs to find and run them. When compilation succeeded for a method, the instructions the processor executes come from here.
  • VDEX holds the verification and layout information. The file records which classes and methods verified, the resolution results the verifier produced, and the DEX layout in the low-level form the runtime reads. That data saves the device from repeating verification at every startup, which matters on hardware with limited resources.
  • Compact DEX holds a space-reduced form of the original bytecode. Compact DEX represents offsets in fewer bytes, reorganises the tables and uses a smaller instruction encoding for common operations. The class definitions, method references and bytecode are the ones the developer wrote, in a form optimised for the installed size.

A standard DEX file carries the same class and method structure in the format the platform defines, and it is the one you see when you unpack an APK. The compiled form on the device is produced from it by the installer and by later compilation, and the runtime prefers the compiled form when it is present.

Why the code on disk differs from the code that runs

The bytecode you unpack and the code the processor executes are related by a translation that is not reversible in one direction. A method compiled ahead of time has no interpreter involvement, so its observable behaviour includes the result of optimisation decisions: constants folded, small calls inlined, and in rare cases a method compiled to nothing because its result is unused.

When compilation has not happened or has been discarded, the runtime interprets the bytecode from the compact form. The same method then runs through the interpreter, and the difference shows up in timing rather than in results. An observation strategy that relies on instruction counts or execution time has to account for that. For a request reconstruction the important point is that both paths compute the same values, which is why the request itself is the durable evidence and the artifact is the map.

How a loaded class comes from a source other than the packaged DEX

A class that runs in the process was not necessarily in the file you unpacked. Several mechanisms put code in front of the runtime from elsewhere.

  • The application loads its own DEX at runtime. It may download a file, decrypt one stored in its assets, or assemble one in memory, then hand it to the runtime as an additional class path. The packaged application then contains the loader while the interesting logic lives in the loaded file.
  • A second stage arrives after installation. Some apps fetch their real implementation on first run, so a static package inspection describes the bootstrap and not the delivered application.
  • An optimised copy replaces the original. The installer converts packaged bytecode into the device's compiled form, so the artifact in the app directory is a derived file. Any modification made to the packaged version is absent from the derived one unless the installer was made to regenerate it.

Correlating what is loaded with what is on disk

The runtime exposes the link between a loaded class and its origin, and that link is the starting point for correlation. A reflection call on a loaded class reports which file it came from, and a tool that inspects a running process can list the class path the runtime actually uses. Comparing that list with the files you extracted shows which code the app executes and which code is merely present.

The comparison usually produces a short list of resident artifacts, and reading work begins there. Where the loaded file is not the one from the APK, the same class can appear in both versions, so the mapping has to be by method signature and behaviour rather than by name, because renaming is applied per artifact. The verification data in the VDEX file is also evidence: a class the verifier recorded tells you the runtime reached it, which distinguishes code that runs from code that shipped.

For a reconstruction the goal is a usable client, not a copy of the on-device files. The artifact set explains why a class you found in the APK cannot be the one producing the request, and the running process supplies the values that matter.

Reviewed 28 September 2026 · SReverse research desk

Start your full APK reconstruction

Send the full APK

Projects start at $120. Choose WhatsApp or email, then attach the APK in the app that opens. We reply within one hour with the next step and send the fixed quote after review.

Want us to contact you?