android::re

tool apktool · jadx android · frida
APK basicsjadxapktool adbsmaliDynamic Find flags
01APK Structure
APK = ZIP archive
# APK is just a zip — unzip to inspect raw contents
unzip -l challenge.apk
unzip challenge.apk -d apk_raw/

# Key files:
# AndroidManifest.xml  — permissions, activities, package name
# classes.dex          — compiled Java/Kotlin bytecode
# classes2.dex ...     — multidex (large apps)
# res/                 — resources (layouts, strings, drawables)
# assets/              — raw files bundled with app
# lib/                 — native .so libraries (arm64-v8a, x86…)
# META-INF/            — signature files

# Check for interesting files immediately
find apk_raw/ -name "*.db" -o -name "*.sqlite"   # databases
find apk_raw/ -name "*.key" -o -name "*.pem"     # crypto material
find apk_raw/ -name "*.so"                        # native libs
cat apk_raw/res/values/strings.xml | grep -i "flag\|secret\|key\|pass"
Quick recon
# strings across entire APK
strings challenge.apk | grep -i "picoCTF\|flag\|secret"

# strings in native libraries
find apk_raw/lib/ -name "*.so" -exec strings {} \; | grep -i "flag"

# Identify certificate / signer
apksigner verify --verbose challenge.apk
keytool -printcert -jarfile challenge.apk

# File type check (may not be .apk extension)
file challenge.apk
02jadx — Decompiler
CLI usage
# Install
# Download: https://github.com/skylot/jadx/releases
# chmod +x jadx-1.x.x/bin/jadx

# Decompile APK to Java source
jadx -d output/ challenge.apk

# Decompile with resources
jadx -d output/ --show-bad-code challenge.apk

# Search in decompiled code
grep -r "flag" output/sources/
grep -ri "picoCTF\|secret\|password\|encrypt" output/sources/

# Output: output/sources/com/example/... (Java files)
#         output/resources/ (AndroidManifest, etc.)

# Launch GUI
jadx-gui challenge.apk
jadx-gui tips
# jadx-gui keyboard shortcuts:
# Ctrl+F       search in current file
# Ctrl+Shift+F search all (text search)
# N            rename variable
# X            show usages (cross-reference)
# Ctrl+G       go to line
# F5           decompile / refresh

# Key places to look:
# MainActivity.onCreate() — app entry point
# Any class named: Check, Verify, Flag, License
# BuildConfig class — may have hardcoded strings
# R.string — string resources

# Export all strings from resources
cat output/resources/res/values/strings.xml
03apktool — Decompile & Recompile
Decompile & rebuild
# Install
sudo apt install apktool
# or: https://apktool.org/

# Decompile (to smali + resources)
apktool d challenge.apk -o decompiled/
apktool d challenge.apk -o decompiled/ -f  # force overwrite

# Decompiled structure:
# decompiled/smali/     — Dalvik assembly
# decompiled/res/       — resources (decoded XML)
# decompiled/AndroidManifest.xml

# Search in smali
grep -r "flag\|picoCTF" decompiled/smali/
grep -r "const-string" decompiled/smali/ | grep -i "key\|secret"

# Recompile after patching
apktool b decompiled/ -o patched.apk

# Sign (required to install)
keytool -genkey -v -keystore ctf.jks -keyalg RSA -keysize 2048 -validity 365 -alias ctf
apksigner sign --ks ctf.jks patched.apk
Smali patching
# smali = Dalvik assembly (one file per class)
# Common patch: make check() always return true

# Find check method
grep -r "checkFlag\|verify\|isCorrect" decompiled/smali/

# In .smali file, change return value:
# Original:  return-boolean v0   (returns variable)
# Patched:   const/4 v0, 0x1    (v0 = true)
#            return-boolean v0

# Common smali instructions:
# const/4 v0, 0x1      → v0 = true (1)
# const/4 v0, 0x0      → v0 = false (0)
# return-boolean v0    → return bool
# return-void          → return nothing
# const-string v0, "..." → v0 = string literal

# Log to Logcat (for debugging)
# invoke-static {v0}, Landroid/util/Log;->d(Ljava/lang/String;)I
04adb — Android Debug Bridge
Device & files
# Connect / list devices
adb devices
adb -s emulator-5554 shell    # specific device

# Start emulator (AVD)
emulator -avd Pixel_5_API_31 &

# Install APK
adb install challenge.apk
adb install -r patched.apk    # replace existing

# File transfer
adb push local_file /sdcard/
adb pull /sdcard/file ./
adb pull /data/data/com.example.app/files/  # app data (root)

# Shell
adb shell
adb shell 'cat /data/data/com.example.app/shared_prefs/*.xml'
adb shell 'ls /data/data/com.example.app/'
Logcat & monitoring
# Logcat — watch app output
adb logcat
adb logcat *:E                       # errors only
adb logcat -s "MainActivity"         # specific tag
adb logcat | grep -i "flag\|picoCTF\|secret"

# Clear logcat
adb logcat -c

# App data locations
# /data/data/<package>/shared_prefs/ — SharedPreferences (XML)
# /data/data/<package>/databases/    — SQLite DBs
# /data/data/<package>/files/        — internal files
# /sdcard/Android/data/<package>/    — external storage

# Pull database
adb shell 'cp /data/data/com.app/databases/app.db /sdcard/'
adb pull /sdcard/app.db ./
sqlite3 app.db '.dump'
05Dynamic Analysis
Frida on Android
# Push frida-server to device
adb push frida-server /data/local/tmp/
adb shell 'chmod +x /data/local/tmp/frida-server'
adb shell '/data/local/tmp/frida-server &'

# List running apps
frida-ps -U

# Hook Java method
frida -U -f com.example.app -l hook.js

# hook.js — hook checkFlag method
Java.perform(() => {
    const Main = Java.use('com.example.app.MainActivity');
    Main.checkFlag.implementation = function(flag) {
        console.log('Flag attempt:', flag);
        const result = this.checkFlag(flag);
        console.log('Result:', result);
        return true;   // always succeed
    };
});
Bypass root detection & SSL pinning
# Common bypass scripts (Frida)

# Root detection bypass
# https://codeshare.frida.re/@dzonerzy/fridantiroot/
frida -U -f com.app --codeshare dzonerzy/fridantiroot

# SSL pinning bypass
# https://codeshare.frida.re/@pcipolloni/universal-android-ssl-pinning-bypass-with-frida/
frida -U -f com.app --codeshare pcipolloni/universal-android-ssl-pinning-bypass-with-frida

# Objection: automated bypass framework
pip install objection
objection -g com.example.app explore
# Inside objection shell:
android sslpinning disable
android root disable
android hooking list classes
android hooking watch class_method com.example.app.MainActivity.checkFlag --dump-args --dump-return
06Find the Flag
Priority checklist for Android CTF
# 1. Strings hunt (30 seconds)
strings challenge.apk | grep -i "picoCTF\|flag"
unzip -p challenge.apk res/values/strings.xml | grep -i "flag\|key\|secret"

# 2. Decompile with jadx, search source
jadx -d out/ challenge.apk
grep -ri "picoCTF\|flag\|encrypt\|decode\|base64" out/sources/

# 3. Check resources
cat out/resources/res/values/strings.xml
find out/resources/ -type f | xargs file | grep -v "XML\|PNG\|GIF"  # unusual files

# 4. Native libraries
find apk_raw/lib/ -name "*.so" -exec strings {} \; | grep -i "flag"
# Open .so in Ghidra or radare2 for deeper analysis

# 5. Run and monitor
adb logcat | grep -i "flag\|picoCTF"

# 6. Hook with Frida — intercept comparisons
# Hook String.equals, strcmp, all check functions

# 7. Patch smali — bypass check → always return true → app reveals flag
apktool d challenge.apk -o dec/
# Edit smali: change return-boolean to const/4 v0, 0x1; return-boolean v0
apktool b dec/ -o patched.apk && apksigner sign ...
ANDROID CTF QUICKSTART →  ① strings apk | grep picoCTF  ② jadx -d out/ app.apkgrep -ri flag out/sources/  ③ cat out/resources/res/values/strings.xml  ④ find lib/ -name "*.so" -exec strings {} \;  ⑤ Frida hook check methods → dump args → flag revealed  ⑥ smali patch: force return true → app shows flag