agentleFS
eisbaweisbaw/mped-skills/skills/android-emulator-app-live-inspect/SKILL.md

android-emulator-app-live-inspect

Skill11 starsChanged 3 months agoMITView on GitHub

Live-inspect an Android app's network on a rooted emulator — nixpkgs emulator + Magisk root + Frida TLS-unpinning + mitmproxy capture, then export decrypted flows. Use when you want to MITM/decrypt an app's HTTPS API, defeat certificate pinning, observe its cloud calls, or capture a login/session flow on an emulator. Generic across apps; complements (does not replace) the android-app-reverser static skill.

The file

We split this skill into the rules it gives an agent

6 rules. About 0 are common, 1 is distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Run all just recipes from inside nix develop.

    line 34
  2. Very specific:

    Follow the runbook in the justfile header: sdk-bootstrap → avd-create → emu → root → emu (cold-boot) → root-grant-bootstrap → frida-up.

    line 61
  3. Very specific:

    After this, adb -s <serial> shell su -c id returns uid=0 and persists.

    line 63
  4. Very specific:

    Export: run scripts/export-flows.py as a mitmproxy addon over the .mitm file with OUT=<dest>/flows.json (see its header).

    line 75
  5. Very specific:

    Add [fully.qualified.Class, method] entries to EXTRA_BOOLEAN_HOOKS at the top of scripts/agent/agent.js, then just unpin-build and re-run.

    line 89
  6. Distinctive:

    Zygisk often does NOT inject on a rootAVD/emulator Magisk: When it doesn't, Magisk DenyList and Shamiko are inert — system-wide root-hiding …

    line 101

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Android Emulator App Live Inspect

Stand up a rooted Android emulator from nixpkgs, run a target app under Frida with TLS unpinning + anti-tamper bypass, route it through mitmproxy, and export decrypted request/response flows. Dynamic counterpart to static APK reversing: it shows what the app actually sends.

Built and proven against a heavily-hardened Tuya-SDK app, but this skill is app-agnostic — the app-specific bits are isolated to one editable hook list.

When to use

  • "Capture / decrypt this app's HTTPS traffic", "bypass its cert pinning", "see its API calls", "MITM the login", "what does it phone home".
  • You have (or can run) a Linux box with Nix + KVM.

When NOT to use

  • You only need static analysis (use the android-app-reverser skill).
  • The data you want rides non-HTTP transports (MQTT/WebRTC/PPCS) — see Limitations.

Prerequisites

  • Nix with flakes, and /dev/kvm accessible (x86_64 emulator).
  • A graphical $DISPLAY for the one-time Magisk GUI grant (or adapt — see Limitations).
  • Everything else (adb, emulator, frida, jadx, mitmproxy, node, python+frida) is provided by flake.nix — never install tools globally.

Files in this skill

Run all just recipes from inside nix develop. SKILL.md points at these; it does not re-embed the commands — read the file for exact flags.

  • flake.nix / flake.lock — FHS dev shell. Provides the tools and the native libs Google's emulator/Qt need on NixOS (the non-obvious part). Pinned.
  • justfile — every step as a recipe; its header is the ordered runbook.
  • scripts/spawn-unpin.py — Frida harness: spawns the app, loads the agent, keeps the session alive, fails loud on detach. (just unpin calls it.)
  • scripts/spawn-capture.py — same harness as spawn-unpin.py, but also appends the agent's structured send({tag,text}) messages to a JSONL dump (<serial> <package> <script.js> <dump.jsonl>). Use it for custom capture agents (plaintext/crypto/signaling hooks) layered on the unpinner.
  • scripts/agent/agent.js — the generic unpinning + anti-tamper agent (native BoringSSL + Java OkHttp/JSSE + RootBeer + a per-app hook list). This is the one file you edit per target. Compiled via scripts/agent/ with frida-compile (bundles frida-java-bridge, which Frida 17 dropped as a global).
  • scripts/export-flows.py — mitmproxy addon: dumps a .mitm capture to structured JSON (parsed form fields, gunzipped bodies). OUT=<path> env sets output.
  • scripts/magisk-grant-shell.sh — one-time GUI bootstrap that grants the adb shell user root in Magisk (Android 14 blocks Magisk's background prompt).
  • scripts/magisk-hide-root.sh — Zygisk + DenyList config (see Limitations re Zygisk).
  • scripts/extract-xz-zip.py — extracts Magisk-module zips that use XZ/zstd ZIP entries (stock unzip can't), for manual module installs.

Workflow

A. One-time host setup (per machine)

Follow the runbook in the justfile header: sdk-bootstrap → avd-create → emu → root → emu (cold-boot) → root-grant-bootstrap → frida-up. After this, adb -s <serial> shell su -c id returns uid=0 and persists.

B. Per-app live inspection

  1. Install the target: just install-xapk <dir-of-base+split-apks> (the Play x86_64 image translates arm64-only libs).
  2. Build the agent once (and after any edit): just unpin-build (compiles scripts/agent/agent.js → scripts/agent/unpin-compiled.js).
  3. Capture in one shell: just sniff (mitmproxy → flows.mitm).
  4. Route + run in another: just proxy-on then just unpin <pkg> — spawn-unpin.py launches the app from process start with the agent's hooks already installed, so flow #1 is captured and decrypted.
  5. Interact (or let it idle); when done, just proxy-off and stop sniff.
  6. Export: run scripts/export-flows.py as a mitmproxy addon over the .mitm file with OUT=<dest>/flows.json (see its header). Also mitmdump -nr flows.mitm --flow-detail 4 for a human-readable dump.

For most apps (OkHttp + Conscrypt, no serious anti-tamper) steps 1–6 yield decrypted plaintext JSON immediately — no per-app work.

C. If the app detects root / Frida / emulator (or still won't decrypt)

The generic agent already no-ops RootBeer and the common JSSE/OkHttp pinning. For a custom check:

  1. Decompile: just decompile <apk> (jadx) — or use the android-app-reverser skill.
  2. Grep the sources for the dialog/exit strings it shows ("rooted", "jailbroken", "frida", "emulator") and for su-path arrays / /proc/maps scans; find the boolean method(s) that gate the block.
  3. Add [fully.qualified.Class, method] entries to EXTRA_BOOLEAN_HOOKS at the top of scripts/agent/agent.js, then just unpin-build and re-run. (A subagent over the decompiled tree finds these targets quickly.)

D. Read a capture

mitmproxy -nr flows.mitm (TUI) or open the exported flows.json. Every REST call, endpoint, header and body is there — decrypted at the TLS layer.


Limitations & potential solutions

  1. Zygisk often does NOT inject on a rootAVD/emulator Magisk. When it doesn't, Magisk DenyList and Shamiko are inert — system-wide root-hiding silently does nothing (a stale "Do not remind" dismissal can mask this). Solution: rely on the in-process agent bypass (EXTRA_BOOLEAN_HOOKS), which works under instrumentation regardless of Zygisk. Verify hiding on a fresh pm clear launch, not a cached one. If you need root hidden even when not under Frida, use a real device or a working-Zygisk setup.
  2. App-layer payload encryption (e.g. Tuya postData/result). Unpinning TLS reveals the HTTP envelope but the body may be separately AES/RSA- encrypted by the app, so you see ciphertext. Solution: hook the app's encrypt/sign function (e.g. a libthing_security-style JNI encryptPostData) to log plaintext before encryption — add an Interceptor/Java hook to the agent. Most apps don't do this; once TLS is stripped you see plaintext JSON.
  3. Native / statically-linked TLS pinning. The native BoringSSL hook only catches modules that export SSL_*_set_custom_verify. A stripped, static TLS stack exposes nothing to hook by name (you'll see "0 hooks"). Solution: hook by offset after reversing the lib, or hook the higher Java caller, or patch the pin set in the app's assets.
  4. Non-HTTP transports are invisible to the proxy. MQTT, PPCS/WebRTC video, QUIC, raw sockets bypass an HTTP proxy entirely. Solution: native socket / SSL_read/SSL_write hooks to dump plaintext, a transparent/tproxy setup, a dedicated MQTT proxy, or hook the SDK's decode function.
  5. Per-app anti-tamper still needs decompilation. The generic layer covers RootBeer + common JSSE pinning, but a bespoke check needs the manual step in section C. Solution: the EXTRA_BOOLEAN_HOOKS extension point + a decompile-and-grep subagent make this ~minutes for Java checks; native checks cost more.
  6. Frida is itself detectable (checks that scan /proc/maps for frida-agent). Solution: it's almost always easier to hook the boolean that consumes the check (section C) than to hide the agent; the agent does exactly this for known patterns.
  7. Floating SDK/Magisk/agent versions. cmdtools_ver in the justfile can 404; platform-tools/emulator/system-image and Magisk (rootAVD master) float to "latest at bootstrap"; frida-server must match the host frida-tools. Solution: flake.lock pins the host toolchain; pin the rest by convention and bump cmdtools_ver when the download 404s. The frida-server-push recipe already version-matches the server to the tools.
  8. NixOS-specific friction baked in. The FHS env + native-lib list exist because Google ships dynamically-linked prebuilts that don't run on NixOS. On a normal FHS distro this is simpler (the raw SDK runs) — but the flake still works and pins everything.
  9. One-time GUI grant needs a display. root-grant-bootstrap drives the Magisk app via uiautomator (it scrolls with coordinates tuned for the default re-pixel AVD). Solution: on a different DPI/AVD, adjust the swipes in scripts/magisk-grant-shell.sh, or grant once interactively then persist via just root-grant-shell (sqlite, reboot-safe).

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.