Mobile App Pentesting Lab Setup: The Complete 2026 Guide (Android, Burp, Frida)

Introduction
Most mobile bug bounty submissions fail before testing even begins. The device isn't rooted, the proxy isn't trusted, the target app pins its certificate, or the whole setup breaks on the next reboot and never gets rebuilt. The result is the same: no clean traffic, no findings.
This guide removes that friction permanently. You will build a rooted Android 14 lab from a clean image and finish with a setup you can re-arm in under a minute, every session, for years. It is written to be followed once, top to bottom — each step states exactly what to run and what success looks like, so you never advance on a broken foundation.
Every command in this guide was executed on a live Android 14 device (Genymotion, x86_64).
What you will have at the end
- A rooted Genymotion Android 14 emulator (Magisk), with a working Google Play Store.
- Burp Suite's CA trusted by browsers (Chrome + Firefox) and apps — durably, across reboots.
- Frida + Objection configured to defeat SSL pinning, root detection, and Frida detection.
- A single command (
geny.sh) that re-arms the lab after every boot.
Prerequisites
- A Linux host (Kali or Ubuntu recommended) with hardware virtualization enabled in BIOS.
- Basic comfort with a terminal and
adb. - Burp Suite (Community or Professional) installed on the host.
- Authorization to test your target (see Scope and legality below).
How trust works on Android (read this first)
Certificate trust on Android is not a single switch. There are two trust stores, and three classes of client each read a different one. Misunderstanding this is the most common reason testers lose hours to ERR_CERT_AUTHORITY_INVALID:
| Client | Reads | Covered in |
|---|---|---|
| Chrome and most browsers | the user store | Part 5A |
| Firefox | its own bundled store | Part 5B |
| Apps | the system store, and most also pin on top | Part 5C (trust) + Parts 8–10 (pinning) |
Match the method to the client and interception is reliable. Get it backwards and nothing works.
Scope and legality. Only test applications you own or are explicitly authorized to test — your own app, a signed engagement, or an in-scope bug bounty program. For banking and production apps, test only against your own account. Rooting a device or intercepting traffic for an app or account you do not control may be a criminal offense. When in doubt, stop.
1. Host Tools and Requirements
Install the emulator backend, Android platform tools, and the Frida toolchain.
# ADB + VirtualBox (Genymotion's backend) + xz (to unpack frida-server)
sudo apt update
sudo apt install -y adb virtualbox xz-utils
# Frida CLI + Objection, isolated with pipx
sudo apt install -y pipx
pipx ensurepath # adds ~/.local/bin to PATH — restart your shell afterwards
pipx install frida-tools # provides: frida, frida-ps, frida-trace (pulls in the frida core)
pipx install objection # runtime exploration and one-command bypasses
Use
pipx, notpip. Objection and frida-tools are Python 3 only. On Kali/Debian a barepipmay resolve to the wrong interpreter and fail with "Could not find a version that satisfies the requirement."pipxalways uses Python 3 and isolates each tool. To keep them in one environment instead:pipx install frida-toolsthenpipx inject frida-tools objection.
Confirm the install and record the version — frida-server on the device must match it exactly:
frida --version # e.g. 17.15.1
Verify — the command prints a version such as
17.15.1. Note this number.
Choosing an emulator
| Option | Strengths | Limitations | Recommendation |
|---|---|---|---|
| Genymotion (Personal) | Fast, VirtualBox-backed, drag-and-drop installs, built-in GApps | Free for personal use only; images ship unrooted (rooted in Part 3) | Use this |
| Android Studio AVD | Free, official, Google Play images | Play images aren't rooted (use rootAVD); slower | Fallback |
| Physical device | Real hardware APIs; defeats emulator detection | Requires unlock/root; more setup | For hardened apps (Part 10) |
Note. Genymotion's Android 12+ images are locked
userbuilds —adb rootis refused and there is nosuout of the box. You root them yourself with Magisk in Part 3. This is identical to how a real device is rooted and is stable once complete.
2. Create and Boot the Device
- Install Genymotion Desktop (Personal edition, free) from genymotion.com.
- Create a device using a Pixel / Android 14 template.
- Allocate 8 GB RAM and 4 CPUs.
- Start the device.
Connect from the terminal and confirm ADB sees it:
adb devices -l
# 192.168.56.106:5555 device product:vbox86p model:Pixel_9
adb shell getprop ro.build.version.release # 14
adb shell getprop ro.product.cpu.abi # x86_64
Verify — the device is listed, the release is
14, and the ABI isx86_64. If nothing appears, runadb kill-server && adb start-server, thenadb connect 192.168.56.106:5555.
Note. Commands in this guide use a plain
adb, which targets the single connected device. If you run more than one device at once, add-s <serial>to each command (for exampleadb -s 192.168.56.106:5555 shell …) to select the target.
3. Root the Device with Magisk
A clean Genymotion Android 14 image is a locked user build with no root:
adb shell 'su -c id' # su: inaccessible or not found
adb root # adbd cannot run as root because the device is not rooted
Root is installed with Magisk — using Genymotion's own Magisk build. This is the detail that derails most attempts:
Warning. A generic
Magisk.apkor.zipwill not work on Genymotion, and neither willrootAVD. Genymotion images are system-as-root (no patchable boot orinit_bootpartition), so Genymotion ships a custom installer that establishes root through aninit.rcmechanism instead. Use only that file.
Step 1 — Download the installer. From Genymotion's official page, Install Magisk on Genymotion, download magisk_v30.7_genymotion_installer.zip (Android 12+). Save it to ~/tools/.
Step 2 — Flash it. With the device window focused, drag the zip file onto the device screen. Genymotion executes the installer with root privileges. When it completes, reboot:
adb reboot
Note. The CLI equivalent,
gmtool device flash, is license-gated and returns "A license is required to use this feature" on the Personal edition. The drag-and-drop method is the supported path on the free edition.
Step 3 — Verify root:
adb wait-for-device
adb shell 'su -c id' # uid=0(root) ... context=u:r:magisk:s0
adb shell pm list packages | grep magisk # package:com.topjohnwu.magisk
Verify —
su -c idreturnsuid=0(root) … context=u:r:magisk:s0, and the Magisk package is present. Root is now permanent across reboots.
Note.
adb rootstill does not work on auserbuild. To run a privileged command, wrap it:adb shell 'su -c "<command>"'. Several commands below follow this pattern.
Optional — Google Play. If your image has no Play Store, use Open GApps in the Genymotion toolbar and sign in. Play will not download apps until you complete Part 4.
4. Fix the Network (Play Store)
Genymotion bridges the VM to your host network, where it acquires a real IPv6 address that is not actually routable. Google services and the Play Store prefer IPv6, so every connection stalls for ~25 seconds and times out. The symptom is the Play Store stuck on "Downloading…" indefinitely, with gRPC DEADLINE_EXCEEDED … waiting_for_connection in the logs. IPv4 works correctly throughout. The fix is to disable IPv6.
Step 1 — Disable IPv6 now:
adb shell 'su -c "for c in all default wlan0 radio0 eth0; do sysctl -w net.ipv6.conf.$c.disable_ipv6=1; done"'
Step 2 — Make it permanent with a small Magisk module so it survives reboots:
M=/tmp/noipv6; rm -rf $M; mkdir -p $M
printf 'id=noipv6\nname=Disable IPv6\nversion=1.0\nversionCode=1\nauthor=lab\ndescription=Force IPv4 (Genymotion IPv6 is not routable)\n' > $M/module.prop
printf '#!/system/bin/sh\nuntil [ "$(getprop sys.boot_completed)" = 1 ]; do sleep 2; done\nsleep 3\nfor c in all default wlan0 radio0 eth0; do sysctl -w net.ipv6.conf.$c.disable_ipv6=1 2>/dev/null; done\n' > $M/service.sh
chmod 644 /service.sh
( && zip -qr /tmp/noipv6.zip . )
adb push /tmp/noipv6.zip /data/local/tmp/noipv6.zip
adb shell
Step 3 — Confirm connectivity:
adb shell 'toybox nc -w 6 google.com 443 </dev/null && echo CONNECTED'
Verify — the output is
CONNECTED. The Play Store now downloads apps normally.
Note. The VM reaches your host at
192.168.56.1(the VirtualBox host-only gateway), not10.0.2.2(which is the Android Studio AVD address). You will use192.168.56.1for the proxy in Part 6.
5. Trust Burp's CA (Browsers and Apps)
Recall the trust model: browsers read the user store; apps read the system store and usually pin. You will configure all three clients.
Step 1 — Export Burp's CA on the host. Find your listener port under Burp → Proxy → Proxy settings → Proxy listeners (commonly 8080):
BURP=127.0.0.1:8080 # your Burp listener
curl -s http://$BURP/cert -o burp.der
openssl x509 -inform der -in burp.der -out burp.pem
HASH=$(openssl x509 -subject_hash_old -noout -in burp.pem) # e.g. 9a5ba575
cp burp.pem "$HASH.0"
echo "Cert file = $HASH.0"
adb push "$HASH.0" /data/local/tmp/
Verify — the script prints a hash such as
9a5ba575. The-nooutflag is required; without it$HASHcaptures the entire PEM and every later command fails.
5A. Browsers — Chrome (user store)
adb shell 'su -c "
mkdir -p /data/misc/user/0/cacerts-added
cp /data/local/tmp/'"$HASH"'.0 /data/misc/user/0/cacerts-added/
chown system:system /data/misc/user/0/cacerts-added/'"$HASH"'.0
chmod 644 /data/misc/user/0/cacerts-added/'"$HASH"'.0
chcon u:object_r:keychain_data_file:s0 /data/misc/user/0/cacerts-added/'"$HASH"'.0
stop && start
"'
Verify — after Part 6, Chrome loads
https://example.comwith no warning and the request appears in Burp.
Note. Modern Chrome ships its own root store and ignores CAs added to the system store at runtime, but it honors the user store. Always use the user store for Chrome.
5B. Browsers — Firefox (its own store)
Firefox ignores the Android trust store entirely. Launch Firefox once to create its profile, then enable one preference.
GUI: open about:config, set security.enterprise_roots.enabled to true, and restart Firefox.
Scripted:
PKG=org.mozilla.firefox
PROF=$(adb shell "su -c 'ls /data/data/$PKG/files/mozilla/ | grep .default'" | tr -d '\r')
UID=$(adb shell "su -c 'stat -c %u /data/data/$PKG'" | tr -d '\r')
> /tmp/user.js
adb push /tmp/user.js /data/local/tmp/user.js
adb shell
Verify — after restarting Firefox,
https://example.comloads with the padlock.
5C. Apps — a durable Magisk CA module
On Android 14 the system trust store spans two locations: /system/etc/security/cacerts/ and the read-only APEX path /apex/com.android.conscrypt/cacerts/. Apps may read either, so your CA must be present in both.
Warning. A one-off
mount -t tmpfs …from a shell does not work here. That mount lands in a transient mount namespace — it never reaches the zygote-spawned app processes, and it disappears on the next framework restart. The reliable method is a Magisk module: Magisk's magic-mount runs before zygote, in the global namespace, and reapplies on every boot.
Step 1 — Build and install the module (covers both stores):
You can also install the zip through Magisk → Modules → Install from storage.
Step 2 — Verify it reached a running app's namespace (the check the tmpfs method fails):
adb wait-for-device; sleep 5
PID=$(adb shell "su -c 'pidof com.android.systemui'" | tr -d '\r')
adb shell "su -c 'ls /proc/$PID/root/system/etc/security/cacerts/$HASH.0 /proc/$PID/root/apex/com.android.conscrypt/cacerts/$HASH.0'"
Verify — both paths are listed (no "No such file"). Non-pinned apps now trust Burp, permanently. Pinned apps still require Frida (Part 8).
6. Route Traffic Through Burp
In Burp → Proxy → Proxy settings → Bind to address, select All interfaces so the VM can reach the listener.
Method 1 — ADB global proxy (recommended):
adb shell settings put global http_proxy 192.168.56.1:8080 # enable (host = 192.168.56.1)
adb shell settings put global http_proxy :0 # disable
Method 2 — Wi-Fi settings (GUI): Settings → Network & Internet → Wi-Fi → (long-press the network) → Modify → Advanced → Proxy: Manual, host 192.168.56.1, port your Burp listener. Useful when Method 1 misbehaves.
Confirm: open Chrome and visit https://example.com.
Verify — the request appears in Burp → Proxy → HTTP history. (Test Firefox only after 5B. An app failing here is pinning, addressed in Part 8 — not a proxy fault.)
| Symptom | Cause | Fix |
|---|---|---|
| Nothing in HTTP history | Burp bound to loopback only | Bind to All interfaces, re-set the proxy |
ERR_PROXY_CONNECTION_FAILED | Wrong host IP | Use 192.168.56.1 (not 10.0.2.2, not your Wi-Fi IP) |
| All connections time out, even with the proxy off | Broken IPv6 | Apply Part 4 |
| HTTPS fails in an app only | The app pins its certificate | Use Frida (Part 8) |
7. Automate the Proxy and the Lab
Add proxy shortcuts to ~/.zshrc or ~/.bashrc. These read your host IP automatically from the network interface, so the proxy keeps working when your IP changes:
export BURP_PORT=8080 # your Burp listener
export BURP_IFACE=wlan0 # the host interface the VM can reach (vboxnet0 for Genymotion's static 192.168.56.1)
# Auto-detect the host IP from $BURP_IFACE and point the device at Burp
alias proxy_on='adb shell settings put global http_proxy $(ip -4 addr show "$BURP_IFACE" | grep -oP "(?<=inet\s)\d+(\.\d+){3}"):$BURP_PORT'
alias proxy_off='adb shell settings put global http_proxy :0'
Note. Set
BURP_IFACEto the interface the VM actually reaches. Genymotion is bridged to your Wi-Fi, sowlan0works; or usevboxnet0, whose address is always the static192.168.56.1. Check your interfaces withip -4 addr. Bind Burp to All interfaces either way.
Then create a single helper to re-arm the non-persistent parts each session. Root, both certificates, and the IPv6 fix persist; only frida-server needs restarting after a boot. On Genymotion it must be started through su with setsid, because a plain nohup … & over adb shell su -c dies when the shell exits. Save as ~/tools/geny.sh:
#!/usr/bin/env bash
BURP_IFACE="${BURP_IFACE:-wlan0}"; BURP_PORT="${BURP_PORT:-8080}"
HOST_IP=$(ip -4 addr show "$BURP_IFACE" | grep -oP )
adb connect 192.168.56.106:5555 >/dev/null 2>&1
adb shell
adb push ~/tools/frida-server /data/local/tmp/frida-server >/dev/null
adb shell
adb shell
chmod +x ~/tools/geny.sh
Verify — running
~/tools/geny.shprints[ok] IPv6 disabled, frida-server running, proxy -> <your-host-ip>:8080.
8. Defeat SSL Pinning with Frida
Many apps pin their server certificate, rejecting even a trusted CA. Frida hooks the application at runtime and disables those checks. This part covers standard Java-layer pinning, which Objection clears in one command. Hardened apps are covered in Part 10.
Step 1 — Install frida-server on the device. Two rules: the version must match frida --version exactly, and the architecture must match the device (x86_64 on Genymotion). Derive the filename rather than hard-coding it:
VER=$(frida --version)
ABI=$(adb shell getprop ro.product.cpu.abi | tr -d '\r') # x86_64
wget -O frida-server.xz "https://github.com/frida/frida/releases/download/$VER/frida-server-$VER-android-$ABI.xz"
unxz frida-server.xz
mkdir -p ~/tools && mv frida-server ~/tools/frida-server
Step 2 — Start it (through su, detached):
adb push ~/tools/frida-server /data/local/tmp/frida-server
adb shell "su -c 'chmod 755 /data/local/tmp/frida-server; setsid /data/local/tmp/frida-server >/dev/null 2>&1 </dev/null &'"
frida-ps -U | head
Verify —
frida-ps -Ureturns a list of running processes. A version-mismatch error here is the most common failure; re-download to matchfrida --version.
Note. The older pattern
adb root; adb shell "/data/local/tmp/frida-server &"is for the Android Studio AVD. It fails on Magisk-rooted Genymotion becauseadb rootis refused and a bare&dies with the shell. Use thesu -c 'setsid … &'form.geny.shalready does this.
Step 3 — Bypass pinning with Objection:
objection -g com.example.app explore --startup-command "android sslpinning disable"
Verify — Objection reports pinning disabled, and the app's HTTPS traffic appears in Burp. (
com.example.appis a placeholder — list packages withadb shell pm list packages.)
Objection command reference (full)
Launching Objection from the shell. Use explore for an interactive session, run for a single command, or patchapk to embed the Frida gadget into an APK for use on a non-rooted device:
objection -g com.example.app explore # interactive REPL
objection -g com.example.app explore --startup-command "android sslpinning disable"
objection -g com.example.app explore -s "android root disable" # multiple startup cmds with ;
objection -g com.example.app run android sslpinning disable # one command, no REPL
objection -g com.example.app explore --startup-script hooks.js # load a Frida script on start
objection patchapk -s target.apk # repackage APK with Frida gadget (non-root)
All commands below run inside the explore REPL. <pkg> is shorthand for the target package (e.g. com.example.app).
Note. Hooks are jobs —
android hooking watch …keeps logging until youjobs kill <id>(orjobs listto see them). Replace every<pkg>and class/method name with the target's real identifiers, which you discover withandroid hooking search classes/search methods.
Ready-made bypass scripts
When Objection's generic bypass fails, load a community script with frida -U -f com.example.app -l script.js. The most comprehensive maintained suite is HTTP Toolkit's, covering Java, native, and Flutter pinning:
git clone https://github.com/httptoolkit/frida-interception-and-unpinning.git ~/tools/htk-unpin
# Edit ~/tools/htk-unpin/config.js: paste burp.pem into CERT_PEM, set PROXY_HOST=192.168.56.1, PROXY_PORT=8080
| Resource | Purpose | URL |
|---|---|---|
| HTTP Toolkit — frida-interception-and-unpinning | Broadest, maintained; Java + native + Flutter | https://github.com/httptoolkit/frida-interception-and-unpinning |
| Objection | android sslpinning disable / android root disable | https://github.com/sensepost/objection |
| Frida CodeShare | Searchable community scripts | https://codeshare.frida.re/ |
| Frida releases | frida-server builds (match your version) | https://github.com/frida/frida/releases |
| OWASP MASTG | Reference methodology | https://mas.owasp.org/MASTG/ |
| r0capture | Full TLS capture below the pinning layer | https://github.com/r0ysue/r0capture |
Note. The popular
pcipolloniCodeShare script does not disable pinning — it re-pins the app to your CA, loaded from a hard-coded device path. Without that file you getFileNotFoundException: /data/local/tmp/cert-der.crt. Either push the DER first (adb push burp.der /data/local/tmp/cert-der.crt) or use the HTTP Toolkit suite, which needs no such file.
9. Bypass Root and Frida Detection
Some apps refuse to run on a rooted device or terminate when they detect Frida. With root and Frida you defeat both.
Practice target — Allsafe, an intentionally vulnerable app with dedicated root-detection, Frida-detection, SSL-pinning, and insecure-storage challenges:
gh release download -R t0thkr1s/allsafe-android --pattern '*.apk' --dir ~/tools --clobber # or download from the Releases page
adb install -r ~/tools/allsafe.apk # package: infosecadventures.allsafe
Step 1 — Create a master root-detection bypass at ~/tools/root-bypass.js. This is not a one-app trick; it defeats the six common vectors at once — file checks (Java + native), command execution, PackageManager root-app detection, system properties (Java + native), the RootBeer library, and a fast app-only scan for custom isRooted()-style methods:
It covers the three classic vectors plus three more that defeat hardened apps: native (C/C++) checks via libc, PackageManager scans for Magisk/SuperSU, and property spoofing. For the rare app with a custom boolean flag, add its Class.method to CONFIG_EXTRA at the top.
Step 2 — Run it (spawn with -f so the hooks load before the checks execute):
frida -U -f infosecadventures.allsafe -l ~/tools/root-bypass.js
Verify — the console prints
[*] Java hooks installed,[*] Native hooks installed, and[+] MASTER root bypass active {...}. Open the Root Detection challenge and tap Check: it reports "Congrats, root is not detected!". (Objection alternative:android root disable.)
Note. For Frida detection, spawn early with
-f. If the app scans for the server, rename it and use a non-default port:mv frida-server fs; /data/local/tmp/fs -l 0.0.0.0:8888, then connect withfrida -H 127.0.0.1:8888. The literal namefrida-serverand port27042are the first things apps check.
10. Intercept Hardened Apps
Objection's one-liner handles roughly 80% of apps. Hardened applications — banking, Google, and anything built to resist analysis — stack multiple defenses. You bypass them in layers.
Authorization. This applies only to your own account on an app you are explicitly authorized to test. Intercepting a bank's traffic outside that boundary is a criminal offense.
| Layer | Mechanism | Countermeasure |
|---|---|---|
| Java pinning | OkHttp CertificatePinner, TrustManager | android-certificate-unpinning.js / Objection |
| Native pinning | Pins inside BoringSSL (libssl.so) — invisible to Java hooks | native-tls-hook.js (the key script) |
| HTTP/3 (QUIC) | UDP/443 traffic a normal proxy cannot read | BLOCK_HTTP3 = true (forces HTTP/2) |
| Flutter | Dart's own TLS stack, ignoring both Android stores | android-disable-flutter-certificate-pinning.js |
| Root detection | Refuses to run on a rooted device | android-disable-root-detection.js (Part 9) |
| Frida detection | Scans for the server, port, or maps | Spawn -f, rename the server, custom port |
| Emulator detection | Blocks Genymotion / AVD | Use a real rooted phone |
| Play Integrity / SafetyNet | Server-side device attestation | Not client-bypassable; may block the app |
Run the suite. With config.js edited (CERT_PEM, PROXY_HOST=192.168.56.1, PROXY_PORT=8080, BLOCK_HTTP3=true), arm the lab and load config.js first, then the hooks you need:
~/tools/geny.sh # IPv6 off, frida-server up, proxy on
cd ~/tools/htk-unpin
frida -U -f com.target.app \
-l config.js \
-l native-tls-hook.js \
-l android/android-certificate-unpinning.js \
-l android/android-certificate-unpinning-fallback.js
# add -l android/android-disable-root-detection.js if it detects root
# add -l android/android-disable-flutter-certificate-pinning.js for Flutter apps
# add -l native-connect-hook.js (and enable Burp "Support invisible proxying") for raw/gRPC sockets
Note. Keep Frida attached — closing the REPL removes the hooks and the app drops to "no connection." Always spawn with
-f(not-n) so hooks install before the app's pinning and detection code runs, and always loadconfig.jsfirst, or you will seeReferenceError: 'DEBUG_MODE' is not defined.
If the app still will not launch:
- Quits on a rooted device → root detection. Add
android-disable-root-detection.js; on Magisk, also add the app to the DenyList. - Quits only with Frida running → Frida detection. Spawn
-f, rename the server, use a custom port. - Blocks on the emulator entirely → use a real rooted phone (
frida-serverforarm64-v8a; everything else is identical). - Server rejects the rooted device → Play Integrity attestation, enforced server-side and not client-bypassable.
Verify — API calls appear in Burp → HTTP history, and the Frida console prints confirmations such as
== Hooked native TLS lib libssl.so ==. If history stays empty while the app works, traffic is on an uncovered channel: confirmBLOCK_HTTP3 = true(QUIC) or addnative-connect-hook.js(raw sockets).
11. Daily Quick-Start
Root, both certificates, the IPv6 fix, and the Firefox preference all persist. A fresh session is three steps:
# 1. Open Burp (bound to All interfaces) and start the Genymotion device.
# 2. Arm the lab — IPv6 off, frida-server up, proxy on:
~/tools/geny.sh
# 3. Browsers work immediately. For an app, disable pinning:
objection -g com.example.app explore --startup-command "android sslpinning disable"
# (For a hardened app, use the Part 10 suite instead.)
# When finished:
proxy_off
Note. Browsers work the moment the proxy is on — no Frida required. Step 3 is only needed for apps, because of pinning.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
adb devices empty | ADB server stale / not connected | adb kill-server && adb start-server; adb connect 192.168.56.106:5555 |
su: not found after flashing | Wrong Magisk zip | Use the Genymotion installer (Part 3), not a generic Magisk.zip |
gmtool flash → "A license is required" | Personal-edition CLI gate | Use the drag-and-drop flash (Part 3) |
| Play Store stuck on "Downloading…" | Broken bridged IPv6 | Disable IPv6 (Part 4) |
| All connections time out, even with the proxy off | Same IPv6 issue | Part 4 |
| Proxy set but no traffic | Burp on loopback / wrong host IP | Bind to All interfaces; use 192.168.56.1 |
| Cert added via tmpfs is gone after restart / apps ignore it | Wrong mount namespace, not persistent | Use the Magisk CA module (Part 5C); verify via /proc/<pid>/root/... |
Chrome: ERR_CERT_AUTHORITY_INVALID | CA only in the system store | Install into the user store (Part 5A) |
Firefox: SEC_ERROR_UNKNOWN_ISSUER | Firefox uses its own store | Enable security.enterprise_roots.enabled (Part 5B) |
frida-ps errors / "unable to connect" | Version mismatch or server died on reboot | Match frida-server to frida --version; re-run geny.sh |
frida-server & dies immediately | Bare & over adb su -c exits with the shell | Start with su -c 'setsid … </dev/null &' (Part 8) |
ReferenceError: 'DEBUG_MODE' | HTTP Toolkit hook run without config.js | Load config.js first (Parts 9–10) |
| Hardened app crashes on launch | Root or Frida detection | Apply Part 9; spawn -f; rename the server / use a custom port |
Summary
You now have a complete, reproducible Android pentesting lab built from a clean image: a Genymotion Android 14 device rooted with Magisk, a working Play Store, Burp's CA trusted durably by browsers and apps, and Frida with Objection ready to defeat SSL pinning and root or Frida detection. The single command ~/tools/geny.sh re-arms everything each session.
Two principles carry the entire setup. Root is the foundation — on modern Genymotion you install it yourself with the Genymotion-specific Magisk build, after which it is permanent. And trust is not a single switch — browsers read the user store, apps read the system and APEX stores and pin on top, so you trust durably with a Magisk module and strip pinning with Frida. Apply the right method to each client and HTTPS interception becomes routine.
Comments(0)
Sign in to join the conversation.
- Be the first to comment.