intermediatecat/rev~3 min read

Android APK Reverse Engineering

Decompile Android applications, inspect Smali bytecode, patch logic checks, and dynamically hook runtime methods using Frida.

// prerequisite reading

Android APK Architecture

An Android Application Package (.apk) is a compressed ZIP archive containing:

  • classes.dex: Compiled Dalvik Executable bytecode.
  • AndroidManifest.xml: App permissions, declared activities, services, and receivers.
  • lib/<arch>/: Native C/C++ shared libraries (.so files).
  • assets/ & res/: Static resources and raw files.

1. Decompiling to Java with JADX

JADX decompiles Android DEX bytecode into clean Java source code.

# GUI interface
jadx-gui challenge.apk

# Command-line export to source directory
jadx -d out_src challenge.apk

Static Analysis Steps

  1. Inspect AndroidManifest.xml for exported activities or custom secret URI schemes.
  2. Search for flag checks, hardcoded cryptographic keys, or obfuscated XOR strings.
  3. Check System.loadLibrary("native-lib") calls for underlying JNI C/C++ native libraries.

2. Disassembling & Patching with Apktool

If static Java decompilation is insufficient or logic must be altered:

Step 1: Decode APK to Smali Bytecode

apktool d challenge.apk -o apk_decompiled

Step 2: Patch Smali Logic

Locate target .smali files in apk_decompiled/smali/. Smali uses register-based bytecode:

# Original Smali flag check logic
if-eqz v0, :cond_0    # Branch to cond_0 if v0 is FALSE

# Patching logic: Replace conditional branch with NOPs or invert branch condition
if-nez v0, :cond_0   # Branch if v0 is TRUE (inverting validation logic!)

Step 3: Rebuild, Align, & Sign APK

# Rebuild APK
apktool b apk_decompiled -o patched.apk

# Align memory offsets
zipalign -v 4 patched.apk patched_aligned.apk

# Generate self-signed key and sign APK
keytool -genkey -v -keystore my.keystore -alias key -keyalg RSA -keysize 2048 -validity 10000
apksigner sign --ks my.keystore patched_aligned.apk

3. Dynamic Instrumentation with Frida

Frida injects JavaScript snippets into running Android processes to hook methods, inspect arguments, and override return values without repackaging the APK.

Frida Setup

# Install Frida on host PC
pip install frida-tools

# Push frida-server to Android device / emulator
adb push frida-server /data/local/tmp/
adb shell "chmod 755 /data/local/tmp/frida-server && /data/local/tmp/frida-server &"

Frida Method Hooking Script (hook.js)

Java.perform(function () {
  // Target class and method
  var MainActivity = Java.use("com.example.ctf.MainActivity");

  // Override checkFlag method
  MainActivity.checkFlag.implementation = function (userInput) {
    console.log("[+] Hooked checkFlag! Input: " + userInput);

    // Call original function or force return true
    var result = this.checkFlag(userInput);
    console.log("[+] Original result: " + result);

    // Return true to bypass authentication check
    return true;
  };
});

Running Frida Hook

frida -U -f com.example.ctf -l hook.js