Mobile Pentest Technique
Goal: systematically identify security weaknesses in Android and iOS applications following OWASP MASTG/MASVS.
When this technique applies
- Mobile application (Android or iOS) in scope for pentest or bug bounty.
- Need to test authentication, storage, network, or platform-specific controls.
- Reverse engineering mobile app logic or extracting secrets.
Boundary
- CTF mobile tasks: flag-extraction from APK/IPA/backup →
mobile-ctf (faster, CTF-specific patterns including .ab, Unity/IL2CPP, asset stego).
- Input from
web-exploit-technique: API-level findings from mobile app traffic.
- Deep binary analysis:
reversing-technique for obfuscated native libraries and IL2CPP binaries.
- Tool skills:
offensive-tools/rev/jadx/, offensive-tools/rev/apktool/, offensive-tools/rev/dex2jar/, offensive-tools/rev/androguard/, offensive-tools/rev/frida/.
Initial triage
Before decompiling or hooking broadly, classify the app, the platform, and the control family most likely to fail first.
- Starting state: are you testing Android or iOS, do you have only the package or also a device/emulator, and is the priority storage, auth, transport, local trust, or backend API behavior?
- First questions: what protections are present (pinning, root/jailbreak checks, obfuscation, native code), what app paths matter most, and what can be validated statically before runtime work?
- Immediate actions: extract package metadata, map exposed components and trust boundaries, then choose the first lane: static review, traffic interception, dynamic instrumentation, or backend/API analysis.
- Tool-family direction: use decompilation skills (
jadx, apktool, androguard, dex2jar) first for structure and secrets, then instrumentation (frida) and proxy skills after you know what runtime behavior must be observed or bypassed.
- Escalation rule: do not jump to native reversing or bypass scripts until the simpler Java/Kotlin/ObjC/Swift and network paths are exhausted.
Agent operating model
Per mobile application:
1. Static analysis — decompile, inspect manifest, search secrets.
2. Dynamic analysis — instrument with Frida, bypass SSL pinning.
3. Traffic interception — proxy through Burp/mitmproxy.
4. Storage analysis — inspect SharedPreferences, SQLite, KeyStore.
5. Authentication testing — test local auth, biometrics, session handling.
6. API testing — apply web-exploit-technique to backend APIs.
Android testing
Static analysis
# Quick win: strings on the raw APK first (zip container: unzip -p for embedded files)
strings target.apk | grep -iE "api[_-]?key|secret|password|token|bearer|firebaseio\.com|s3\.amazonaws"
# Decompile
jadx -d output_dir target.apk
apktool d target.apk -o output_dir # smali + decoded manifest + resources
# Manifest analysis: exported components, debuggable, allowBackup, permissions
aapt2 dump badging target.apk # aapt is deprecated; aapt2 in modern SDK build-tools
# Hardcoded crypto (SecretKeySpec, Cipher.getInstance — common leak point)
grep -r "SecretKeySpec\|Cipher\|AES\|DES\|encrypt\|decrypt\|base64" output_dir/ | grep -v "^Binary"
# Look for the hardcoded key argument passed to SecretKeySpec(key, "AES")
# Firebase and remote config leaks
cat output_dir/res/values/google-services.json 2>/dev/null
cat output_dir/assets/google-services.json 2>/dev/null
# Certificate analysis
apksigner verify --print-certs target.apk
# Asset inspection (images, data files bundled with APK)
find output_dir/assets/ -type f | xargs file
# Large images → potential steganography (zsteg, steghide, visual inspection)
Dynamic analysis
# Frida — SSL pinning bypass (spawn+resume is default since frida-tools 12+; do not pass --no-pause)
frida -U -f com.target.app -l ssl_pinning_bypass.js
# Objection — rapid assessment
objection -g com.target.app explore
# android sslpinning disable # OkHttp3, TrustManagerImpl, SSLContext, Conscrypt, etc.
# android root disable
# android hooking list activities
# Drozer (community fork WithSecureLabs/drozer) — exposed components
dz> run app.package.attacksurface com.target.app
dz> run app.provider.query content://com.target.app.provider/
Traffic interception
- Configure device/emulator proxy to Burp Suite.
- Install CA certificate (user store for Android 7+; system store requires root).
- SSL pinning bypass: Frida universal scripts (httptoolkit/frida-interception-and-unpinning) > Objection > LSPosed module (TrustMeAlready, JustTrustMe) > smali patching + repackage + resign.
Storage analysis
adb shell cat /data/data/com.target.app/shared_prefs/*.xml
adb pull /data/data/com.target.app/databases/
adb shell ls /data/data/com.target.app/files/
Android backup (.ab) analysis
.ab is a legacy channel. adb backup is restricted since Android 12 and requires android:debuggable=true for most apps; on Android 13+ most stock apps refuse it outright. Still useful for older/debuggable builds and forensic images.
# Header: "ANDROID BACKUP\n<ver>\n<compressed>\n<encryption>\n" (variable length — do NOT hardcode skip=)
python3 - <<'PY'
import zlib, pathlib
raw = pathlib.Path('backup.ab').read_bytes()
# Skip 4 newline-terminated header fields, then decompress the zlib stream that follows.
p = 0
for _ in range(4):
p = raw.index(b'\n', p) + 1
pathlib.Path('backup.tar').write_bytes(zlib.decompress(raw[p:]))
PY
tar xf backup.tar -C extracted/
# Triage extracted content
grep -rE "password|token|secret|api[_-]?key|bearer" extracted/ 2>/dev/null
find extracted/ -name "*.db" -exec sqlite3 {} ".tables" \; 2>/dev/null
Unity / IL2CPP APK
Unity games compile C# to native ARM via IL2CPP. jadx shows only stubs — reverse libil2cpp.so with metadata.
# Verify IL2CPP
ls apk_unzip/lib/arm64-v8a/ # → libil2cpp.so, libmain.so, libunity.so
# Il2CppDumper: recovers full class/method/field names from binary + metadata
# https://github.com/Perfare/Il2CppDumper
# Input: libil2cpp.so + assets/global-metadata.dat
# Output: dump.cs (all C# stubs with offsets), script.py (Ghidra import)
grep -i "flag\|key\|secret\|password\|cheat\|unlock" dump.cs
strings libil2cpp.so | grep -i "flag{"
# Load into Ghidra with Il2CppDumper's script.py for guided reversing
iOS testing
Static analysis
- Decrypt App Store IPA (jailbroken device required on iOS 15+):
frida-ios-dump, bagbak, or ipadecrypt. bfinject is dead (iOS 11 Electra-era); Needle is archived (Reversec Labs, May 2025) — do not use.
- Off-device sideload for testing on stock iOS: TrollStore (iOS 14.0–17.0 unpatched) or a paid developer profile for re-signing.
- Decompile with Hopper, Ghidra, or Binary Ninja; entitlements via
ldid -e, codesign -d --entitlements :-.
- Inspect
Info.plist for URL schemes, ATS exceptions, UIBackgroundModes, associated domains, and entitlements (keychain access groups, app groups).
- Search for hardcoded secrets in Mach-O binaries and bundled resources (
strings -a, rabin2 -zzz).
Dynamic analysis
- Frida:
frida -U -f com.target.app -l script.js (frida-tools spawns and auto-resumes; do not pass --no-pause).
- Objection:
objection -g com.target.app explore — ios sslpinning disable, ios jailbreak disable, ios cookies get, ios ui dump.
- r2frida (in-process r2 session):
r2 frida://spawn/usb//com.target.app for interactive dump/hook without a separate Frida script.
- App Attest / DeviceCheck: modern iOS apps bind API calls to a hardware attestation key; server-side rejection of forged attestations is common — validate via traffic replay, not just Frida hook success.
Keychain and storage
# Objection keychain dump
ios keychain dump
# NSUserDefaults
ios nsuserdefaults get
# SQLite databases
ls /var/mobile/Containers/Data/Application/<UUID>/Library/
OWASP MASVS mapping
| MASVS Category |
Key tests |
| MASVS-STORAGE |
SharedPreferences, SQLite, Keychain, logs, screenshots |
| MASVS-CRYPTO |
Hardcoded keys, weak algorithms, custom crypto |
| MASVS-AUTH |
Local auth, biometrics, session handling |
| MASVS-NETWORK |
SSL pinning, certificate validation, proxy detection |
| MASVS-PLATFORM |
Exported components, intent handling, WebView |
| MASVS-CODE |
Code tampering, debugging, root/jailbreak detection |
Hybrid Android triage cue
Keep this layer at routing depth. When a sample shows both loader and native signs, treat it as a hybrid app and pivot to offensive-coding skills for implementation-level work.
- Managed entry:
classes*.dex Java/Kotlin orchestration
- Native boundary:
System.loadLibrary, JNI_OnLoad, .so checks/unpackers
- Runtime payload:
DexClassLoader / InMemoryDexClassLoader second-stage code
- Instrumentation bridge: Frida hooks Java + native loader points
Deep-dive and patch path:
smali-dex-patching/references/dynamic-dex-and-native-loaders.md
android-jni-ndk
frida
Modern platform gotchas
Android:
- Play Integrity API replaced SafetyNet Attestation (fully retired 2025-01-31). Server verdicts (
MEETS_DEVICE_INTEGRITY, MEETS_BASIC_INTEGRITY, MEETS_STRONG_INTEGRITY) are backed by hardware key attestation on Android 13+; Magisk zygisk-assistant / PlayIntegrityFix bypass basic, not strong.
- Explicit
android:exported required on Android 12+ (targetSdk ≥ 31) for any activity/service/receiver with an <intent-filter>; missing attribute = install failure. Old "exported by intent-filter" implicit exports are gone — re-check attack surface.
- Runtime broadcast receivers on Android 14+ (targetSdk ≥ 34) must pass
RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED to registerReceiver — grep for these flags to map dynamic IPC exposure.
adb backup restricted since Android 12; requires android:debuggable=true. Most production apps yield an empty archive — pivot to root+tar of /data/data/<pkg>/ or Frida file dump.
- Xposed original is dead; use LSPosed (Zygisk module) on Android 8.1–15 for system-wide hooking modules.
- Full IPC attack surface — Intent redirection,
PendingIntent hijacking, exported ContentProvider (SQLi, path traversal in openFile), Service caller-UID/signature bypass, onNewIntent state pollution, WebView addJavascriptInterface gadgets → references/android-ipc-attack-surface.md.
iOS:
- TrustCache + CoreTrust enforce signed-binary allow-lists in the kernel; unsigned/adhoc binaries need a jailbreak or a TrollStore-style CoreTrust bypass (patched in iOS 17.0). No
bfinject/Needle era techniques apply.
- App Attest (
DCAppAttestService) binds requests to a Secure Enclave key; server rejects forged attestations even with a working Frida hook — always validate bypass end-to-end against the backend, not just on-device.
- Universal SSL pinning bypass landscape: httptoolkit/frida-interception-and-unpinning covers OkHttp/Conscrypt/BoringSSL/NSURLSession/CFNetwork; fall back to per-library hooks (
SSL_CTX_set_custom_verify, SecTrustEvaluateWithError) when custom pinners are used.
1---2name: mobile-technique3description: Auth assessment: mobile app security; Android/iOS static, storage, Frida/runtime, traffic, pinning, platform, API and crypto checks.4license: MIT5---67# Mobile Pentest Technique89Goal: systematically identify security weaknesses in Android and iOS applications following OWASP MASTG/MASVS.1011## When this technique applies1213- Mobile application (Android or iOS) in scope for pentest or bug bounty.14- Need to test authentication, storage, network, or platform-specific controls.15- Reverse engineering mobile app logic or extracting secrets.1617## Boundary1819- **CTF mobile tasks**: flag-extraction from APK/IPA/backup → `mobile-ctf` (faster, CTF-specific patterns including .ab, Unity/IL2CPP, asset stego).20- **Input from `web-exploit-technique`**: API-level findings from mobile app traffic.21- **Deep binary analysis**: `reversing-technique` for obfuscated native libraries and IL2CPP binaries.22- **Tool skills**: `offensive-tools/rev/jadx/`, `offensive-tools/rev/apktool/`, `offensive-tools/rev/dex2jar/`, `offensive-tools/rev/androguard/`, `offensive-tools/rev/frida/`.2324## Initial triage2526Before decompiling or hooking broadly, classify the app, the platform, and the control family most likely to fail first.2728- **Starting state**: are you testing Android or iOS, do you have only the package or also a device/emulator, and is the priority storage, auth, transport, local trust, or backend API behavior?29- **First questions**: what protections are present (pinning, root/jailbreak checks, obfuscation, native code), what app paths matter most, and what can be validated statically before runtime work?30- **Immediate actions**: extract package metadata, map exposed components and trust boundaries, then choose the first lane: static review, traffic interception, dynamic instrumentation, or backend/API analysis.31- **Tool-family direction**: use decompilation skills (`jadx`, `apktool`, `androguard`, `dex2jar`) first for structure and secrets, then instrumentation (`frida`) and proxy skills after you know what runtime behavior must be observed or bypassed.32- **Escalation rule**: do not jump to native reversing or bypass scripts until the simpler Java/Kotlin/ObjC/Swift and network paths are exhausted.3334## Agent operating model3536```37Per mobile application:38 1. Static analysis — decompile, inspect manifest, search secrets.39 2. Dynamic analysis — instrument with Frida, bypass SSL pinning.40 3. Traffic interception — proxy through Burp/mitmproxy.41 4. Storage analysis — inspect SharedPreferences, SQLite, KeyStore.42 5. Authentication testing — test local auth, biometrics, session handling.43 6. API testing — apply web-exploit-technique to backend APIs.44```4546## Android testing4748### Static analysis4950```bash51# Quick win: strings on the raw APK first (zip container: unzip -p for embedded files)52strings target.apk | grep -iE "api[_-]?key|secret|password|token|bearer|firebaseio\.com|s3\.amazonaws"5354# Decompile55jadx -d output_dir target.apk56apktool d target.apk -o output_dir # smali + decoded manifest + resources5758# Manifest analysis: exported components, debuggable, allowBackup, permissions59aapt2 dump badging target.apk # aapt is deprecated; aapt2 in modern SDK build-tools6061# Hardcoded crypto (SecretKeySpec, Cipher.getInstance — common leak point)62grep -r "SecretKeySpec\|Cipher\|AES\|DES\|encrypt\|decrypt\|base64" output_dir/ | grep -v "^Binary"63# Look for the hardcoded key argument passed to SecretKeySpec(key, "AES")6465# Firebase and remote config leaks66cat output_dir/res/values/google-services.json 2>/dev/null67cat output_dir/assets/google-services.json 2>/dev/null6869# Certificate analysis70apksigner verify --print-certs target.apk7172# Asset inspection (images, data files bundled with APK)73find output_dir/assets/ -type f | xargs file74# Large images → potential steganography (zsteg, steghide, visual inspection)75```7677### Dynamic analysis7879```bash80# Frida — SSL pinning bypass (spawn+resume is default since frida-tools 12+; do not pass --no-pause)81frida -U -f com.target.app -l ssl_pinning_bypass.js8283# Objection — rapid assessment84objection -g com.target.app explore85# android sslpinning disable # OkHttp3, TrustManagerImpl, SSLContext, Conscrypt, etc.86# android root disable87# android hooking list activities8889# Drozer (community fork WithSecureLabs/drozer) — exposed components90dz> run app.package.attacksurface com.target.app91dz> run app.provider.query content://com.target.app.provider/92```9394### Traffic interception9596- Configure device/emulator proxy to Burp Suite.97- Install CA certificate (user store for Android 7+; system store requires root).98- SSL pinning bypass: Frida universal scripts (httptoolkit/frida-interception-and-unpinning) > Objection > LSPosed module (TrustMeAlready, JustTrustMe) > smali patching + repackage + resign.99100### Storage analysis101102```bash103adb shell cat /data/data/com.target.app/shared_prefs/*.xml104adb pull /data/data/com.target.app/databases/105adb shell ls /data/data/com.target.app/files/106```107108### Android backup (.ab) analysis109110`.ab` is a legacy channel. `adb backup` is restricted since Android 12 and requires `android:debuggable=true` for most apps; on Android 13+ most stock apps refuse it outright. Still useful for older/debuggable builds and forensic images.111112```bash113# Header: "ANDROID BACKUP\n<ver>\n<compressed>\n<encryption>\n" (variable length — do NOT hardcode skip=)114python3 - <<'PY'115import zlib, pathlib116raw = pathlib.Path('backup.ab').read_bytes()117# Skip 4 newline-terminated header fields, then decompress the zlib stream that follows.118p = 0119for _ in range(4):120 p = raw.index(b'\n', p) + 1121pathlib.Path('backup.tar').write_bytes(zlib.decompress(raw[p:]))122PY123tar xf backup.tar -C extracted/124125# Triage extracted content126grep -rE "password|token|secret|api[_-]?key|bearer" extracted/ 2>/dev/null127find extracted/ -name "*.db" -exec sqlite3 {} ".tables" \; 2>/dev/null128```129130### Unity / IL2CPP APK131132Unity games compile C# to native ARM via IL2CPP. jadx shows only stubs — reverse `libil2cpp.so` with metadata.133134```bash135# Verify IL2CPP136ls apk_unzip/lib/arm64-v8a/ # → libil2cpp.so, libmain.so, libunity.so137138# Il2CppDumper: recovers full class/method/field names from binary + metadata139# https://github.com/Perfare/Il2CppDumper140# Input: libil2cpp.so + assets/global-metadata.dat141# Output: dump.cs (all C# stubs with offsets), script.py (Ghidra import)142143grep -i "flag\|key\|secret\|password\|cheat\|unlock" dump.cs144strings libil2cpp.so | grep -i "flag{"145146# Load into Ghidra with Il2CppDumper's script.py for guided reversing147```148149## iOS testing150151### Static analysis152153- Decrypt App Store IPA (jailbroken device required on iOS 15+): `frida-ios-dump`, `bagbak`, or `ipadecrypt`. `bfinject` is dead (iOS 11 Electra-era); Needle is archived (Reversec Labs, May 2025) — do not use.154- Off-device sideload for testing on stock iOS: TrollStore (iOS 14.0–17.0 unpatched) or a paid developer profile for re-signing.155- Decompile with Hopper, Ghidra, or Binary Ninja; entitlements via `ldid -e`, `codesign -d --entitlements :-`.156- Inspect `Info.plist` for URL schemes, ATS exceptions, `UIBackgroundModes`, associated domains, and entitlements (keychain access groups, app groups).157- Search for hardcoded secrets in Mach-O binaries and bundled resources (`strings -a`, `rabin2 -zzz`).158159### Dynamic analysis160161- Frida: `frida -U -f com.target.app -l script.js` (frida-tools spawns and auto-resumes; do not pass `--no-pause`).162- Objection: `objection -g com.target.app explore` — `ios sslpinning disable`, `ios jailbreak disable`, `ios cookies get`, `ios ui dump`.163- r2frida (in-process r2 session): `r2 frida://spawn/usb//com.target.app` for interactive dump/hook without a separate Frida script.164- App Attest / DeviceCheck: modern iOS apps bind API calls to a hardware attestation key; server-side rejection of forged attestations is common — validate via traffic replay, not just Frida hook success.165166### Keychain and storage167168```bash169# Objection keychain dump170ios keychain dump171172# NSUserDefaults173ios nsuserdefaults get174175# SQLite databases176ls /var/mobile/Containers/Data/Application/<UUID>/Library/177```178179## OWASP MASVS mapping180181| MASVS Category | Key tests |182|----------------|-----------|183| MASVS-STORAGE | SharedPreferences, SQLite, Keychain, logs, screenshots |184| MASVS-CRYPTO | Hardcoded keys, weak algorithms, custom crypto |185| MASVS-AUTH | Local auth, biometrics, session handling |186| MASVS-NETWORK | SSL pinning, certificate validation, proxy detection |187| MASVS-PLATFORM | Exported components, intent handling, WebView |188| MASVS-CODE | Code tampering, debugging, root/jailbreak detection |189190## Hybrid Android triage cue191192Keep this layer at routing depth. When a sample shows both loader and native signs, treat it as a hybrid app and pivot to offensive-coding skills for implementation-level work.193194- Managed entry: `classes*.dex` Java/Kotlin orchestration195- Native boundary: `System.loadLibrary`, `JNI_OnLoad`, `.so` checks/unpackers196- Runtime payload: `DexClassLoader` / `InMemoryDexClassLoader` second-stage code197- Instrumentation bridge: Frida hooks Java + native loader points198199Deep-dive and patch path:200201- `smali-dex-patching/references/dynamic-dex-and-native-loaders.md`202- `android-jni-ndk`203- `frida`204205## Modern platform gotchas206207Android:208- **Play Integrity API** replaced SafetyNet Attestation (fully retired 2025-01-31). Server verdicts (`MEETS_DEVICE_INTEGRITY`, `MEETS_BASIC_INTEGRITY`, `MEETS_STRONG_INTEGRITY`) are backed by hardware key attestation on Android 13+; Magisk `zygisk-assistant` / `PlayIntegrityFix` bypass basic, not strong.209- **Explicit `android:exported`** required on Android 12+ (targetSdk ≥ 31) for any activity/service/receiver with an `<intent-filter>`; missing attribute = install failure. Old "exported by intent-filter" implicit exports are gone — re-check attack surface.210- **Runtime broadcast receivers** on Android 14+ (targetSdk ≥ 34) must pass `RECEIVER_EXPORTED` or `RECEIVER_NOT_EXPORTED` to `registerReceiver` — grep for these flags to map dynamic IPC exposure.211- **`adb backup`** restricted since Android 12; requires `android:debuggable=true`. Most production apps yield an empty archive — pivot to root+`tar` of `/data/data/<pkg>/` or Frida file dump.212- **Xposed original** is dead; use **LSPosed** (Zygisk module) on Android 8.1–15 for system-wide hooking modules.213- **Full IPC attack surface** — Intent redirection, `PendingIntent` hijacking, exported ContentProvider (SQLi, path traversal in `openFile`), Service caller-UID/signature bypass, `onNewIntent` state pollution, WebView `addJavascriptInterface` gadgets → [references/android-ipc-attack-surface.md](references/android-ipc-attack-surface.md).214215iOS:216- **TrustCache** + **CoreTrust** enforce signed-binary allow-lists in the kernel; unsigned/adhoc binaries need a jailbreak or a TrollStore-style CoreTrust bypass (patched in iOS 17.0). No `bfinject`/`Needle` era techniques apply.217- **App Attest** (`DCAppAttestService`) binds requests to a Secure Enclave key; server rejects forged attestations even with a working Frida hook — always validate bypass end-to-end against the backend, not just on-device.218- **Universal SSL pinning bypass** landscape: httptoolkit/frida-interception-and-unpinning covers OkHttp/Conscrypt/BoringSSL/NSURLSession/CFNetwork; fall back to per-library hooks (`SSL_CTX_set_custom_verify`, `SecTrustEvaluateWithError`) when custom pinners are used.