If you’ve ever tried to pentest an Android app, you know the frustration: you set up a Wi-Fi proxy, install a user certificate, and… nothing. The app either ignores your proxy entirely or refuses to connect because of certificate pinning and Android’s strict “User vs. System” CA store policies.

Most guides online are outdated or only cover half the story. After much trial and error, I’ve perfected a “Forensic Setup” that forces the Android Emulator to trust OWASP ZAP as a System Root CA and routes all traffic—even from system-level apps—through your proxy.

Here is how to build your own forensic mobile lab.

Prerequisites Link to heading

Before we dive in, ensure you have the following ready:

  • OWASP ZAP (Installed and running)
  • Android SDK Platform-Tools (adb) (Configured in your system PATH)
  • A specific Android Emulator (AVD): You must use a “Google APIs” image. Avoid “Google Play” images; they are production-signed and make writing to the system partition nearly impossible.
  • API Version Note: Newer versions (API 34 and above) sandbox network traffic more aggresively, which can interfere with this method. I recommend using API version 33 for the best results.

Step 1: Crafting the System-Compliant Certificate Link to heading

Android doesn’t just want a .cer file. It requires the certificate to be in PEM format and named after its subject hash.

  1. Export from ZAP: Go to Tools > Options > Network > Server Certificates and save your root CA as zap_root_ca.cer.
  2. The Terminal Magic: Run these commands to identify the hash and rename the file correctly:
# Get the subject hash
HASH=$(openssl x509 -inform PEM -subject_hash_old -in zap_root_ca.cer | head -1)

# Copy/Rename to the format Android expects (<hash>.0)
cp zap_root_ca.cer $HASH.0

Step 2: Breaking into the System Store Link to heading

To intercept HTTPS from modern apps, our certificate must live in /system/etc/security/cacerts/. This requires a writable system partition.

  1. Launch with Writable Access: Open your terminal and start the emulator manually:
emulator -avd <YOUR_AVD_NAME> -writable-system -no-snapshot-load
  1. Disable Verity: This is the crucial step that “unlocks” the system partition by disabling integrity checks.
adb root
adb disable-verity
adb reboot
  1. Injecting the CA: Once the device reboots, remount the file system and push your certificate:
adb root
adb remount
adb push <YOUR_HASH>.0 /system/etc/security/cacerts/
adb shell chmod 644 /system/etc/security/cacerts/<YOUR_HASH>.0
adb reboot

Step 3: Routing the “Unroutable” Traffic Link to heading

Some apps ignore standard Wi-Fi proxy settings. We bypass this by setting a global HTTP proxy at the Android settings database level.

adb shell settings put global http_proxy 10.0.2.2:8080

Note: 10.0.2.2 is the special Android alias for your host machine’s localhost.

Step 4: Freeze the Configuration (Critical) Link to heading

Now that the certificate is injected and the proxy is set, we need to ensure this state is “frozen” so thse changes remain permanent. To do this, we need to save a snapshot by closing the emulator using the GUI (the X button). This triggers a “Quickboot” save, capturing the system store and proxy settings into a permanent snapshot.

Shuting down the emulator!

From now on you MUST launch the emulator from the terminal (as described in the next step), and you should NEVER close it via the GUI again. Instead, kill the process via the terminal (using the it’s PID).

Killing the process prevents the emulator from saving session changes (like app data, temp files, or accidental setting changes), ensuring you always boot into the clean, forensic-ready state you just created.

Step 5: Automate with a Launch Script Link to heading

To simplify the workflow and enforce the “no-save” rule, use this Bash function in your ~/.bashrc:

launchemulator() {
  if [ -z "$1" ]; then
    echo "Usage: launchemulator <AVD_NAME>"
    emulator -list-avds
    return 1
  fi

  echo "Starting forensic emulator: $1"
  # -writable-system: REQUIRED to keep the custom cert active
  # -http-proxy: Forces the network gateway through ZAP
  # -dns-server: Prevents DNS loop issues
  emulator -avd "$1" \
    -writable-system \
    -http-proxy http://10.0.2.2:8080 \
    -dns-server 8.8.8.8 \
    -netdelay none -netspeed full >/dev/null 2>&1 &
  
  export EMULATOR_PID=$!
  adb wait-for-device root
  echo "Lab is ready. PID: $EMULATOR_PID"
  echo "To exit WITHOUT saving changes: kill -9 $EMULATOR_PID"
}

Step 6: The “Trust But Verify” Checklist Link to heading

Before starting your analysis, perform these checks:

  1. System Tab: Go to Settings > Security > Trusted credentials. Scroll through the System tab. You must see “OWASP Root CA” here.

  2. Global Proxy: Run adb shell settings get global http_proxy. It must return 10.0.2.2:8080.

  3. ZAP Connectivity: Open Chrome in the emulator and browse to any HTTPS site. The requests should immediately appear in ZAP’s History tab.

Conclusion Link to heading

Setting up a mobile lab is often the most tedious part of a pentest. By moving the ZAP certificate into the System store and freezing the state with a Quickboot snapshot, you create a robust, persistent environment for modern Android security research.

Happy hunting!