Mobile App Testing Notes: APK Analysis, Jailbreak Detection, and Traffic Interception
Manual mobile test tasks: decompiling APKs, dealing with jailbreak and root detection, and intercepting TLS traffic.
Mobile App Testing Notes: APK Analysis, Jailbreak Detection, and Traffic Interception#
Why this topic matters: the phone is where credentials, tokens, and payment flows live in plain sight of the app, so the app deserves the same review as the API.
Ethics and scope: test builds the vendor gave you, or your own build. Do not strip protections from apps you have no permission to analyze. API classes behind the app are covered in OWASP Top 10 notes.
Android: Start From the Package#
The APK is a zip of code, resources, and a manifest. Work in that order.
Static analysis#
- Unzip the APK and look at
AndroidManifest.xml. - Note exported activities and services.
- Check permissions, especially the dangerous set: camera, location, SMS, contacts.
- Look for hard-coded endpoints, debug flags, and test keys.
Dynamic analysis#
Run the app on an emulator or an instrumented device and watch it call home. Tools that help:
| Tool | Job |
|---|---|
| Frida | Runtime instrumentation |
| Objection | Packaging and SSL-pinning helpers |
| Drozer | Attack-surface probing |
| Jadx | Decompile to readable Java |
| jadx-gui | Browse the decompiled tree |
The first dynamic question#
Does the app validate the API's responses? Many apps render whatever the server returns, which just moves the finding to the web side. For that side, see the XSS delivery notes.
The Manifest Checklist#
| Field | What to flag |
|---|---|
android:exported="true" | Entry points from other apps |
android:debuggable="true" | Debug builds in release |
android:allowBackup="true" | Backup extraction without root |
| Permissions | Dangerous set beyond need |
android:usesCleartextTraffic | Plaintext allowed |
| Deep links | Unvalidated intent filters |
iOS: Trust, Then Bypass, Then Read#
Getting a test device#
A jailbroken or instrumented device lets you inspect the filesystem and hook Objective-C methods. Use your own hardware and your own app builds.
Reading the binary#
- Dump the decrypted IPA.
- Class-dump to see the Objective-C interface.
- Check for ATS settings, plist flags, and embedded keys.
- Trace network setup in the delegate.
SSL Pinning: The Gate#
Most hardened apps pin the server certificate inside the app. Until you can see the traffic, every other check is guesswork.
Approaches#
| Approach | Shape |
|---|---|
| Objection | Hook the pinning check at runtime |
| Frida script | Rewrite the trust evaluation |
| System-wide trust store | Trust your CA and lower the check |
| Proxy with upstream trust | TLS to your CA, TLS to the server |
Document which one you used, because the report's reproducibility depends on it.
Traffic Interception Setup#
- Put the device on a test Wi-Fi you control.
- Configure the device to use the proxy.
- Install the proxy CA on the device.
- Run the app and watch the history.
- Disable pinning in a test build, not the release.
# Device points at your laptop's proxy, e.g. # adb shell settings put global http_proxy 192.168.1.10:8080 # Proxy: Burp or mitmproxy, with its CA trusted on the device.
Common Findings#
| Finding | Where it shows up |
|---|---|
| Tokens in logs | ADB logcat |
| Secrets in the APK or IPA | Static strings pass |
| Plaintext endpoints | Manifest or plist |
| Weak validation of API responses | Web views render raw HTML |
| Client-side price or score logic | Game and payment flows |
| Deep-link abuse | Intent filters with weak matching |
Proxy Side Notes#
Once the device talks to your proxy, the web-side skills transfer: Burp basics, ZAP notes, and the API-side checks in the BOLA matrix.
Storage Review#
- What lives in SharedPreferences, the keychain, or the app group?
- Are tokens rotated?
- Does anything write secrets to the filesystem?
- Does a backup export include the session?
# Android: look at shared_prefs and cache adb shell run-as com.example.app ls shared_prefs/ # iOS: dump the app container from a test device # objection --gadget com.example.app explore --> ios keychain dump
What to Note in the Report#
- The build under test: version, signing state, source.
- The pinning state: on, off, or bypassed for this build.
- The exact proxy setup.
- One screenshot per finding, trimmed.
False Positives to Expect#
- Cleartext that only fires on a debug endpoint.
- Tokens in logs that are already rotated.
- Pinning that breaks the app on some devices but not others.
- A debuggable flag on a staging build, not the production one.
Walkthrough: One Session#
- Install the test build on the instrumented device.
- Configure the proxy and the CA.
- Disable pinning in the test build.
- Exercise the main flows for ten minutes.
- Export the proxy history to JSONL.
- Sort the requests: GET, POST, and mutating POSTs first.
- Replay the mutating POSTs with changed fields.
- Record the mutations that worked and the ones that were blocked.
Walkthrough: Storage Pass#
- With the app open and logged in, snapshot the app container.
- Log out and snapshot again.
- Diff the two snapshots.
- Note what survives logout: tokens, caches, keys.
- Repeat the check after a failed login.
Walkthrough: Manifest Pass#
- Decompile the APK with jadx.
- Copy every exported activity and service into a table.
- For each, note whether it requires a permission.
- Check each deep link for input validation.
- Record one line per entry point.
Limits of These Notes#
- Protections change with each app release.
- Pinning bypass methods differ per app.
- A finding on a test build may not reproduce on release.
- Traffic interception only works where the app cooperates.
- These notes cover the manual side; automated mobile scans exist but this note does not score them.
The Small Ethics Section#
Do not apply this workflow to apps you have not been given permission to test. A bypassed pinning check is not a bypassed consent. Pair this testing with a scope document that names the bundle IDs, the builds, and the devices.
Related Reading#
- The API behind the app: API access control test plan.
- The hidden-field problem on APIs: shadow API inventory.
- Server action analogs for mobile: server actions authorization.
- Class context: web hacking 101.
- Delivery of the web views: XSS types compared.
- Cloud backend behind the app: AWS testing notes.
- Web-side recon that feeds this: automating dead link detection.
- The tool that watches the network: Wireshark guide.
- The roadmap: reading order.
- The triage mindset: denied request alert triage.
Glossary#
| Term | Meaning |
|---|---|
| Pinning | App checks the server cert against one it carries |
| ATS | iOS App Transport Security |
| Exported component | Android entry point reachable from other apps |
| Frida | Runtime instrumentation toolkit |
| Objection | Mobile testing helper built on Frida |
Closing Notes#
The phone app is a client with better networking than the web. Treat it as one. The checks that matter are the same ones the web runs: does the API trust the client, does the client trust the server, and does the client trust what it renders.
Packets You Will See#
| Packet shape | What to note |
|---|---|
| Login POST with a device ID | Does the device ID change on logout? |
| Token refresh | Is the refresh token rotating? |
| Config fetch | What does the client fetch before first use? |
| Web view | Does it render API responses as HTML? |
| Upload POST | Does it check file type on the server? |
False Friends on Mobile#
- A finding on an emulator that does not reproduce on the hardware build.
- Pinning that fails only when the device clock is wrong.
- Trace logs that only appear on debug devices.
- A storage snapshot taken after the app was backgrounded and re-logged.
Small Rules#
- Pin state is a fact about the build, record it.
- Proxy history is evidence, export it.
- Cleartext is a finding only when the request carries real data.
- A token in a log is one fact; a token that works twice is another.
Where These Notes End#
They end where the interesting logic moves to the server, which is why every mobile session should be paired with the web-side notes: OWASP Top 10 notes for the class map, API access control test plan for the authz shape, and shadow API inventory for endpoints the mobile app did not advertise.
What to Avoid#
- Shipping a report without the build identifier.
- Calling cleartext a finding when the request carried a public asset.
- Claiming a pinning bypass you cannot reproduce on the release build.
- Treating a web view renderer as a mobile-only bug.
A Cross-Check List#
- Pin state recorded?
- Build identifier recorded?
- Proxy history exported?
- Exported components enumerated?
- Storage snapshot diffed across logout?
- One scanner pass, one manual pass, one writeup?
A Short Example Session#
09:12 app started, debug logcat captured 09:14 login POST captured, token refresh noted 09:19 storage snapshot taken 09:23 logout, snapshot taken, diff shows token remains 09:31 exported component list written to notes 09:40 history exported to JSONL
Six timestamps; enough to reconstruct what was tested and what was found.
A Note on Builds#
Test the build you ship notes about. Internal builds often differ from release builds in pinning, debuggability, and cleartext settings. The build identifier belongs in the report header.
Per-Permission Triage#
| Permission | Question |
|---|---|
| CAMERA | Does a scan flow actually need it? |
| LOCATION | Background or foreground only? |
| READ_SMS | What feature names this? |
| RECORD_AUDIO | Any voice feature in the build? |
| READ_CONTACTS | A social feature, or a default? |
One More Loop#
Dump, intercept, replay, compare, record. Same loop as web, different tooling. The discipline transfers; the class does not change.
Proxy History Hygiene#
Save the session, trim the history, keep the POST bodies that matter, and export one JSONL before closing. The next run can diff against it, and the finding travels with the session instead of the memory.
Final Shape#
One build, one proxy session, one writeup. Mobile adds two facts to the web discipline: the pinning state and the storage snapshot. Record both, and the note stands on its own.
Ties to the Web Side#
The mobile session usually hands you an API map. Hand that map back to the web-side notes: API access control test plan for authz, BOLA test matrix for object access, and shadow API inventory for endpoints the app never names.
Wrapping Up#
The loop is short on purpose. Dump, intercept, replay, compare, record. Everything else in this note is a way to keep that loop honest against a mobile target.
One Screen, One Rule#
Treat every screen as a renderer, every field as a payload candidate, and every request as a record. The phone shows you more of the app's logic than any single page does; write it down while it is open.
Traffic Interception Checklist#
- Install the CA on the device trust store; on iOS this means Settings -> General -> About -> Certificate Trust Settings, then enabling full trust for the proxy CA.
- On Android 7+, user CAs are ignored by default. Use an emulator with a writable system partition or Frida's
objection android sslpinning disable. - Point the proxy at the app's traffic and watch for the first TLS error. That error names the pinning code path.
- If the app uses certificate transparency enforcement, expect pinning to be layered; one bypass rarely suffices.
Manifest Triage#
Start with aapt dump badging app.apk and aapt dump permissions app.apk. Exported activities without permission guards show up as android:exported=true with no android:permission attribute. Deep links registered through <intent-filter> deserve the same scrutiny as any public endpoint.
| Setting | Risk when loose |
|---|---|
android:debuggable="true" | Arbitrary code execution via adb |
android:allowBackup="true" | Token extraction through adb backup |
android:usesCleartextTraffic="true" | Cleartext credential capture |
What do you think?
React to show your appreciation