Skip to main content

Mobile VAPT Notes (Android Environment & Setup)

3926 words
Edwin Tok | Shiro
Author
Edwin Tok | Shiro
「 ✦ OwO ✦ 」
Table of Contents

Mobile VAPT Notes (Android)
#


Android Environment Setup
#

ADB Setup - Modernized
#

Enable Developer Options & USB Debugging:
#

# On Android device:
# 1. Settings > About Phone
# 2. Tap "Build Number" 7 times to enable Developer Options
# 3. Settings > Developer Options > USB Debugging (Enable)
# 4. Settings > Developer Options > Install via USB (Enable - Android 14+)

# Verify connection:
adb devices
# Expected output: <device_id>    device

# If unauthorized:
adb kill-server
adb start-server
adb devices
# Accept RSA fingerprint on device

# OPSEC: Clear ADB keys after assessment
adb shell rm /data/misc/adb/adb_keys

ADB over WiFi Setup (Android 11+):
#

# Method 1: Wireless Debugging (Android 11+) - Preferred
# 1. Enable "Wireless Debugging" in Developer Options
# 2. Tap "Pair device with pairing code"
# 3. Note IP:PORT displayed

# Pair device:
adb pair <DEVICE_IP>:<PAIRING_PORT>
# Enter 6-digit pairing code when prompted

# Connect for debugging:
adb connect <DEVICE_IP>:<DEBUG_PORT>

# Verify connection:
adb devices
# Should show: <DEVICE_IP>:<PORT>    device

# Method 2: Traditional WiFi ADB (requires USB initially)
adb tcpip 5555
adb connect <DEVICE_IP>:5555
# Disconnect USB cable after successful connection

# OPSEC: Use non-standard ports to avoid detection
adb tcpip 8443
adb connect <DEVICE_IP>:8443

# Disconnect when done:
adb disconnect

Emulator Setup:
#

# Android Studio AVD Manager (current approach):
# 1. Create AVD with Android 14/15 (API 34/35)
# 2. Select system image: "Google APIs" (contains Play Store/Services)
# 3. Enable hardware acceleration (HAXM/KVM)

# Start emulator with writable system:
emulator -avd <AVD_NAME> -writable-system -no-snapshot-load -no-audio -no-boot-anim

# For testing without Google Play Services (root-friendly):
# Use "Google APIs" or "AOSP" images instead of "Google Play" images

# Enable root on emulator (Android 11+):
adb root
adb disable-verity  # Disable Android Verified Boot
adb reboot
# After reboot:
adb root
adb remount

# Verify writable system:
adb shell mount | grep system
# Should show: /system type ext4 (rw,...)

# OPSEC: Use emulator snapshots for quick reversion
emulator -avd <AVD_NAME> -no-snapshot-load  # Fresh start
# Take snapshot: emulator -avd <AVD_NAME> -snapshot <NAME>

Essential ADB Commands:
#

# Device information:
adb devices -l                                    # Detailed device list
adb shell getprop ro.build.version.release       # Android version
adb shell getprop ro.build.version.sdk           # SDK/API level
adb shell getprop ro.product.manufacturer        # Device manufacturer
adb shell getprop ro.product.model               # Device model
adb shell getprop ro.serialno                    # Device serial

# Package management (modern):
adb install app.apk                              # Install APK
adb install -r app.apk                           # Reinstall keeping data
adb install -g app.apk                           # Grant all permissions
adb install --bypass-low-target-sdk-block app.apk  # Android 14+ bypass
adb uninstall <package_name>                     # Uninstall app
adb uninstall -k <package_name>                  # Uninstall keeping data

# List packages:
adb shell pm list packages                        # All packages
adb shell pm list packages -3                     # Third-party only
adb shell pm list packages -s                     # System packages
adb shell pm list packages -e                     # Enabled packages
adb shell pm list packages -d                     # Disabled packages
adb shell pm list packages | grep -i <keyword>    # Search packages

# Get package details:
adb shell pm path <package_name>                  # APK path
adb shell pm dump <package_name>                  # Full package info
adb shell dumpsys package <package_name> | grep -A 5 "permission"  # Permissions

# File operations:
adb push <local_file> <remote_path>              # Upload file
adb pull <remote_path> <local_file>              # Download file
adb shell ls -la /data/data/<package_name>       # List app data
adb shell run-as <package_name> ls /data/data/<package_name>  # Non-root access

# Process management:
adb shell am force-stop <package_name>           # Stop app
adb shell am kill <package_name>                 # Kill app process
adb shell am start -n <package>/<activity>       # Start activity
adb shell am start -a android.intent.action.VIEW -d "<url>"  # Launch URL

# Get running processes:
adb shell ps -A | grep <package_name>            # Modern ps syntax
adb shell pidof <package_name>                   # Get PID

# Logging (improved filtering):
adb logcat                                        # All logs
adb logcat -s <TAG>                              # Specific tag
adb logcat | grep -i <package_name>              # Filter by package
adb logcat *:E                                   # Errors only
adb logcat -v time *:W                           # Warnings with timestamps
adb logcat -c                                    # Clear buffer
adb logcat -G 16M                                # Increase buffer size

# OPSEC: Filter sensitive information
adb logcat | grep -vE '(password|token|secret|key|api)'

# Network proxy (system-wide):
adb shell settings put global http_proxy <IP>:<PORT>
adb shell settings put global global_http_proxy_host <IP>
adb shell settings put global global_http_proxy_port <PORT>
adb shell settings delete global http_proxy      # Remove proxy
adb shell settings delete global global_http_proxy_host

# Screen operations:
adb shell screencap -p /sdcard/screen.png        # Screenshot
adb pull /sdcard/screen.png                      # Pull screenshot
adb shell screenrecord /sdcard/demo.mp4          # Record screen (max 180s)
adb shell input text "Hello%sWorld"              # Input text (space = %s)
adb shell input keyevent 3                       # Home button
adb shell input keyevent 4                       # Back button
adb shell input tap 500 1000                     # Tap coordinates
adb shell input swipe 500 1000 500 100 300       # Swipe (duration ms)

# Battery and performance:
adb shell dumpsys battery                         # Battery status
adb shell dumpsys batterystats --reset            # Reset battery stats
adb shell settings put global window_animation_scale 0  # Disable animations
adb shell settings put global transition_animation_scale 0
adb shell settings put global animator_duration_scale 0

Burp Proxy & Certificate Setup
#

Configure Burp Suite
#

Burp Suite Configuration:
#

# In Burp Suite Professional/Community:
# 1. Proxy > Proxy Settings > Proxy Listeners
# 2. Add new listener or edit existing:
#    - Bind to port: 8080 (or non-standard like 8443 for OPSEC)
#    - Bind to address: All interfaces (0.0.0.0)
#    - Request handling: Enable "Support invisible proxying" for non-proxy-aware apps
#    - TLS Protocols: Enable TLS 1.2 and 1.3 only

# 3. Advanced settings:
#    - Enable HTTP/2 support (for modern apps)
#    - Enable WebSocket support
#    - Configure upstream proxy if needed for OPSEC

# OPSEC: Use loopback with port forwarding instead of binding to all interfaces
# This prevents network exposure
adb forward tcp:8080 tcp:8080
# Then bind Burp to 127.0.0.1:8080 only

Configure Android Device Proxy:
#

# Method 1: Manual WiFi Proxy (User Space - Limited)
# Settings > Network & Internet > Wi-Fi > [Network] > Edit
# Advanced options > Proxy > Manual
# Hostname: <BURP_IP>
# Port: 8080
# Bypass: Leave empty or add exclusions

# Method 2: Global Proxy via ADB (Requires root on Android 11+)
adb shell settings put global http_proxy <BURP_IP>:8080

# For Android 11+, use both settings:
adb shell settings put global http_proxy <BURP_IP>:8080
adb shell settings put global global_http_proxy_host <BURP_IP>
adb shell settings put global global_http_proxy_port 8080

# Verify proxy settings:
adb shell settings get global http_proxy
adb shell settings list global | grep proxy

# Remove proxy:
adb shell settings delete global http_proxy
adb shell settings delete global global_http_proxy_host
adb shell settings delete global global_http_proxy_port

# Method 3: Per-App Proxy using iptables (Root required - Stealthiest)
# Redirect specific app traffic to Burp
adb shell su -c "iptables -t nat -A OUTPUT -p tcp -m owner --uid-owner <APP_UID> -j DNAT --to-destination <BURP_IP>:8080"

# Get app UID:
adb shell dumpsys package <package_name> | grep userId

# Clear iptables rules:
adb shell su -c "iptables -t nat -F"

# Method 4: ProxyDroid app (Root - deprecated but still useful)
# Install ProxyDroid APK and configure per-app proxy rules

Install Burp CA Certificate
#

Method 1: User Certificate
#

# Export Burp CA certificate:
# Burp > Proxy > Proxy Settings > Import/Export CA Certificate
# Export: Certificate in DER format
# Save as: cacert.der

# Transfer to device:
adb push cacert.der /sdcard/Download/burp-cert.der

# Install via Settings:
# Settings > Security > Encryption & credentials > Install a certificate
# Select "CA certificate" (on Android 11+)
# Or Settings > Security > Install from storage (older Android)
# Navigate to Download folder and select burp-cert.der
# Name it "Burp Suite CA" or similar

# Verify installation:
# Settings > Security > Trusted credentials > User tab
# Should see "PortSwigger CA" certificate

# LIMITATION: User certificates don't work for apps targeting API 24+ (Android 7+)
# that don't explicitly trust user certificates

Method 2: System Certificate
#

# Step 1: Export and convert certificate
# Export Burp CA in DER format from Burp Suite
openssl x509 -inform DER -in cacert.der -out cacert.pem

# Generate certificate hash (Android uses subject_hash_old):
CERT_HASH=$(openssl x509 -inform PEM -subject_hash_old -in cacert.pem | head -1)
echo "Certificate hash: $CERT_HASH"

# Rename certificate file:
cp cacert.pem "${CERT_HASH}.0"

# Step 2: Install on device (Android 10-13)
adb root
adb remount
adb push "${CERT_HASH}.0" /system/etc/security/cacerts/
adb shell chmod 644 /system/etc/security/cacerts/${CERT_HASH}.0
adb shell chown root:root /system/etc/security/cacerts/${CERT_HASH}.0
adb reboot

# Step 3: Install on Android 14+ (different path)
# Android 14 moved CA certificates location
adb root
adb remount
adb push "${CERT_HASH}.0" /apex/com.android.conscrypt/cacerts/
adb shell chmod 644 /apex/com.android.conscrypt/cacerts/${CERT_HASH}.0
adb shell chown root:root /apex/com.android.conscrypt/cacerts/${CERT_HASH}.0
adb reboot

# Verify installation:
adb shell ls -la /system/etc/security/cacerts/ | grep $CERT_HASH
# Or for Android 14+:
adb shell ls -la /apex/com.android.conscrypt/cacerts/ | grep $CERT_HASH

# Alternative verification:
adb shell "su -c 'ls /system/etc/security/cacerts/ | wc -l'"
# Count should increase by 1 after installation

Method 3: Magisk Module
#

# For Magisk-rooted devices (recommended approach in 2025)

# Option A: MagiskTrustUserCerts module
# 1. Download from: https://github.com/NVISOsecurity/MagiskTrustUserCerts
# 2. Install in Magisk Manager: Modules > Install from storage
# 3. Reboot device
# 4. Install Burp certificate as USER certificate (Method 1)
# 5. Module automatically moves user certs to system trusted store

# Option B: Manual Magisk module creation
mkdir -p magisk-burp-cert/system/etc/security/cacerts
cp ${CERT_HASH}.0 magisk-burp-cert/system/etc/security/cacerts/

cat > magisk-burp-cert/module.prop << 'EOF'
id=burp_cert
name=Burp Suite CA Certificate
version=1.0
versionCode=1
author=Security Tester
description=Installs Burp Suite CA certificate as system trusted
EOF

# Create zip and install via Magisk
cd magisk-burp-cert
zip -r ../burp-cert-magisk.zip .
# Install burp-cert-magisk.zip in Magisk Manager

# OPSEC: Remove module after assessment to avoid persistence

Method 4: Certificate Injection via Frida (No Reboot)
#

// burp_cert_inject.js - Runtime certificate injection
Java.perform(function() {
    console.log("[*] Injecting Burp CA certificate...");
    
    // Hook TrustManagerFactory to accept Burp certificate
    var TrustManagerFactory = Java.use('javax.net.ssl.TrustManagerFactory');
    var TrustManager = Java.use('javax.net.ssl.X509TrustManager');
    var X509Certificate = Java.use('java.security.cert.X509Certificate');
    
    // Create custom trust manager that accepts all certificates
    var CustomTrustManager = Java.registerClass({
        name: 'com.custom.TrustManager',
        implements: [TrustManager],
        methods: {
            checkClientTrusted: function(chain, authType) {
                console.log('[*] checkClientTrusted - bypassed');
            },
            checkServerTrusted: function(chain, authType) {
                console.log('[*] checkServerTrusted - bypassed');
                // Optionally log certificate details
                if (chain && chain.length > 0) {
                    console.log('[*] Server cert: ' + chain[0].getSubjectDN());
                }
            },
            getAcceptedIssuers: function() {
                return Java.array('java.security.cert.X509Certificate', []);
            }
        }
    });
    
    // Hook TrustManagerFactory.init
    TrustManagerFactory.init.overload('java.security.KeyStore').implementation = function(keyStore) {
        console.log('[*] TrustManagerFactory.init() hooked');
        this.init(keyStore);
        
        // Replace trust managers
        var tmf = this;
        var getTrustManagers = tmf.getTrustManagers();
        for (var i = 0; i < getTrustManagers.length; i++) {
            getTrustManagers[i] = CustomTrustManager.$new();
        }
    };
    
    console.log("[*] Certificate injection complete");
});
# Use Frida script (no device modification needed):
frida -U -f <package_name> -l burp_cert_inject.js --no-pause

# OPSEC advantage: No persistent changes to device
# Useful when root access is temporary or not desired

Method 5: Network Security Config Override (Android 7+)
#

# For apps using Network Security Configuration
# Decompile APK and modify network_security_config.xml

apktool d app.apk -o app_decompiled

# Edit res/xml/network_security_config.xml:
cat > app_decompiled/res/xml/network_security_config.xml << 'EOF'
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
            <!-- Trust user-installed certificates -->
            <certificates src="system" />
            <certificates src="user" />
        </trust-anchors>
    </base-config>
    <!-- Allow cleartext traffic for all domains -->
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">*</domain>
    </domain-config>
</network-security-config>
EOF

# Ensure AndroidManifest.xml references it:
# <application android:networkSecurityConfig="@xml/network_security_config">

# Recompile and sign:
apktool b app_decompiled -o app_modified.apk
java -jar uber-apk-signer.jar --apks app_modified.apk

# Install modified APK:
adb install app_modified-aligned-debugSigned.apk

Advanced Certificate Pinning Bypass
#

# Using Objection (easier than manual Frida):
objection -g <package_name> explore

# Inside objection console:
android sslpinning disable

# Using Frida with comprehensive bypass script:
frida -U -f <package_name> -l ssl-pinning-bypass.js --no-pause

# Using HTTP Toolkit (GUI-based alternative):
# Download from: https://httptoolkit.com/android/
# Install HTTP Toolkit app on device
# One-click SSL pinning bypass with automatic certificate trust

# OPSEC: Test multiple bypass methods as apps may detect common approaches

Troubleshooting Common Issues:
#

# Issue 1: "Certificate not trusted" despite system installation
# Solution: Check app's network security config
apktool d app.apk
cat app_decompiled/res/xml/network_security_config.xml
# If present, modify to trust user certificates (see Method 5)

# Issue 2: App not routing through proxy
# Solution A: Check for bypass rules
adb shell settings get global http_proxy_exclusion_list

# Solution B: Use iptables redirection (root)
APP_UID=$(adb shell dumpsys package <package_name> | grep userId= | cut -d= -f2 | cut -d' ' -f1)
adb shell su -c "iptables -t nat -A OUTPUT -p tcp -m owner --uid-owner $APP_UID --dport 443 -j REDIRECT --to-port 8080"

# Issue 3: Certificate hash mismatch on Android 14+
# Solution: Use subject_hash instead of subject_hash_old for some devices
openssl x509 -inform PEM -subject_hash -in cacert.pem | head -1

# Issue 4: Burp not intercepting QUIC/HTTP3 traffic
# Solution: Block QUIC protocol to force HTTP/2
adb shell su -c "iptables -A OUTPUT -p udp --dport 443 -j DROP"
adb shell su -c "ip6tables -A OUTPUT -p udp --dport 443 -j DROP"

# Clear rule:
adb shell su -c "iptables -D OUTPUT -p udp --dport 443 -j DROP"

Frida Installation and Setup
#

Frida Server Installation
#

Determine Device Architecture:
#

# Method 1: Using ADB
adb shell getprop ro.product.cpu.abi
# Common outputs:
# arm64-v8a    -> Use frida-server-*-android-arm64
# armeabi-v7a  -> Use frida-server-*-android-arm
# x86_64       -> Use frida-server-*-android-x86_64
# x86          -> Use frida-server-*-android-x86

# Method 2: Get all supported ABIs
adb shell getprop ro.product.cpu.abilist
# Example: arm64-v8a,armeabi-v7a,armeabi

# Method 3: Check Android version for compatibility
adb shell getprop ro.build.version.release  # Android version
adb shell getprop ro.build.version.sdk      # API level

Download and Install Frida Server:
#

# Get latest Frida version:
pip3 show frida | grep Version
# Or check: https://github.com/frida/frida/releases

# Current stable version (as of 2025): 16.5.x
FRIDA_VERSION="16.5.2"

# Download appropriate architecture (most common: arm64)
wget https://github.com/frida/frida/releases/download/${FRIDA_VERSION}/frida-server-${FRIDA_VERSION}-android-arm64.xz

# Alternative: Use curl
curl -LO https://github.com/frida/frida/releases/download/${FRIDA_VERSION}/frida-server-${FRIDA_VERSION}-android-arm64.xz

# Extract:
unxz frida-server-${FRIDA_VERSION}-android-arm64.xz

# Rename for convenience:
mv frida-server-${FRIDA_VERSION}-android-arm64 frida-server

# Push to device:
adb push frida-server /data/local/tmp/frida-server

# Set permissions:
adb shell chmod 755 /data/local/tmp/frida-server

# Verify file:
adb shell ls -la /data/local/tmp/frida-server
adb shell file /data/local/tmp/frida-server  # Check if binary is correct architecture

Start Frida Server - Multiple Methods:
#

# Method 1: Standard startup (requires root)
adb shell su -c "/data/local/tmp/frida-server &"

# Method 2: Daemonize with explicit binding (recommended)
adb shell su -c "/data/local/tmp/frida-server -D -l 0.0.0.0:27042 &"
# -D: Daemonize (run in background)
# -l: Listen address and port

# Method 3: Start without root (limited functionality)
# Only works with debuggable apps (android:debuggable="true")
adb shell "/data/local/tmp/frida-server &"

# Method 4: Start with custom port (OPSEC)
adb shell su -c "/data/local/tmp/frida-server -l 127.0.0.1:27043 &"

# Method 5: Persistent startup via init script (root)
adb shell su -c "cat > /data/local/tmp/frida-start.sh << 'EOF'
#!/system/bin/sh
/data/local/tmp/frida-server -D -l 0.0.0.0:27042
EOF"
adb shell su -c "chmod 755 /data/local/tmp/frida-start.sh"

# Verify Frida server is running:
adb shell ps -A | grep frida-server
# Or:
adb shell su -c "ps -A | grep frida"

# Check listening ports:
adb shell su -c "netstat -tlnp | grep frida"
# Or modern syntax:
adb shell su -c "ss -tlnp | grep frida"

# Expected output: tcp 0 0 0.0.0.0:27042 0.0.0.0:* LISTEN <pid>/frida-server

# Forward Frida port (if not using network):
adb forward tcp:27042 tcp:27042

# List forwarded ports:
adb forward --list

# Remove port forwarding:
adb forward --remove tcp:27042

Stop/Restart Frida Server:
#

# Stop Frida server:
adb shell su -c "killall frida-server"
# Or get PID and kill:
adb shell su -c "pkill -9 frida-server"

# Verify stopped:
adb shell ps -A | grep frida-server
# Should return nothing

# Restart Frida server:
adb shell su -c "killall frida-server; /data/local/tmp/frida-server -D &"

# OPSEC: Cleanup after testing
adb shell su -c "killall frida-server"
adb shell rm /data/local/tmp/frida-server
adb shell rm /data/local/tmp/frida-start.sh

Frida Tools Installation - Host Machine
#

# Install/Update Frida tools:
pip3 install frida-tools

# Upgrade to specific version:
pip3 install frida-tools==12.4.4  # Match server version

# Verify installation:
frida --version
frida-ps --version

# Install in virtual environment (recommended):
python3 -m venv frida-env
source frida-env/bin/activate  # Linux/Mac
# frida-env\Scripts\activate   # Windows
pip3 install frida-tools

# Additional useful tools:
pip3 install objection          # Higher-level Frida tool
pip3 install frida-compile      # Compile Frida scripts
pip3 install r2frida            # Radare2 + Frida integration

# Verify connection to device:
frida-ps -U    # List processes via USB
# Should show running processes on device

# If connection fails, troubleshoot:
adb devices                      # Ensure device connected
adb forward --list               # Check port forwarding
adb shell su -c "ps -A | grep frida"  # Verify server running

# Connect via network (if device on same network):
frida-ps -H <DEVICE_IP>:27042
# Or set environment variable:
export FRIDA_DEVICE_HOST=<DEVICE_IP>:27042
frida-ps -H

List Frida Applications and Processes:
#

# List all running processes:
frida-ps -U

# List running apps with identifiers:
frida-ps -Uai
# Output: PID  Name        Identifier
#         1234 Chrome      com.android.chrome

# List installed applications:
frida-ps -Uai | grep -v "PID"
# Useful for finding package names

# List processes with details:
frida-ps -Uai --json | jq '.'
# Requires jq: sudo apt install jq

# Filter specific app:
frida-ps -Uai | grep -i <app_name>

# List system processes:
frida-ps -U | grep system_server

# OPSEC: Check for anti-Frida processes
frida-ps -U | grep -iE "(frida|xposed|magisk)"

Frida Automation Scripts
#

Automated Startup Script:
#

#!/bin/bash
# frida-setup.sh - Automated Frida server deployment

FRIDA_VERSION="16.5.2"
ARCH="arm64"  # Change based on device
DEVICE_ID=""  # Leave empty for default device

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

echo -e "${GREEN}[*] Starting Frida Setup${NC}"

# Check if device is connected
if [ ! -z "$DEVICE_ID" ]; then
    ADB_CMD="adb -s $DEVICE_ID"
else
    ADB_CMD="adb"
fi

DEVICE_CHECK=$($ADB_CMD devices | grep -w "device" | wc -l)
if [ $DEVICE_CHECK -eq 0 ]; then
    echo -e "${RED}[!] No device connected${NC}"
    exit 1
fi

echo -e "${GREEN}[*] Device connected${NC}"

# Check if frida-server exists
if [ ! -f "frida-server-${FRIDA_VERSION}-android-${ARCH}" ]; then
    echo -e "${YELLOW}[*] Downloading Frida server v${FRIDA_VERSION}${NC}"
    wget -q "https://github.com/frida/frida/releases/download/${FRIDA_VERSION}/frida-server-${FRIDA_VERSION}-android-${ARCH}.xz"
    unxz "frida-server-${FRIDA_VERSION}-android-${ARCH}.xz"
fi

# Stop existing Frida server
echo -e "${YELLOW}[*] Stopping existing Frida server${NC}"
$ADB_CMD shell su -c "killall frida-server" 2>/dev/null

# Push Frida server
echo -e "${GREEN}[*] Pushing Frida server to device${NC}"
$ADB_CMD push "frida-server-${FRIDA_VERSION}-android-${ARCH}" /data/local/tmp/frida-server

# Set permissions
$ADB_CMD shell chmod 755 /data/local/tmp/frida-server

# Start Frida server
echo -e "${GREEN}[*] Starting Frida server${NC}"
$ADB_CMD shell su -c "/data/local/tmp/frida-server -D -l 0.0.0.0:27042 &"

# Wait for server to start
sleep 2

# Verify server is running
if $ADB_CMD shell su -c "ps -A | grep frida-server" | grep -q frida; then
    echo -e "${GREEN}[+] Frida server started successfully${NC}"
else
    echo -e "${RED}[!] Failed to start Frida server${NC}"
    exit 1
fi

# Forward port
echo -e "${GREEN}[*] Setting up port forwarding${NC}"
$ADB_CMD forward tcp:27042 tcp:27042

# Test connection
echo -e "${GREEN}[*] Testing Frida connection${NC}"
if frida-ps -U >/dev/null 2>&1; then
    echo -e "${GREEN}[+] Frida setup complete!${NC}"
    echo -e "${GREEN}[*] Listing installed apps:${NC}"
    frida-ps -Uai | head -10
else
    echo -e "${RED}[!] Frida connection test failed${NC}"
    exit 1
fi
# Make executable and run:
chmod +x frida-setup.sh
./frida-setup.sh

Frida Health Check Script:
#

#!/bin/bash
# frida-check.sh - Verify Frida environment

echo "[*] Checking Frida environment..."

# Check Frida tools installation
if command -v frida &> /dev/null; then
    echo "[+] Frida tools installed: $(frida --version)"
else
    echo "[!] Frida tools not found. Install: pip3 install frida-tools"
    exit 1
fi

# Check device connection
if adb devices | grep -q "device$"; then
    echo "[+] Device connected"
    DEVICE_INFO=$(adb shell getprop ro.product.model)
    echo "    Model: $DEVICE_INFO"
    ANDROID_VER=$(adb shell getprop ro.build.version.release)
    echo "    Android: $ANDROID_VER"
else
    echo "[!] No device connected"
    exit 1
fi

# Check Frida server on device
if adb shell su -c "ps -A | grep frida-server" | grep -q frida; then
    echo "[+] Frida server running"
    FRIDA_PID=$(adb shell su -c "pidof frida-server")
    echo "    PID: $FRIDA_PID"
else
    echo "[!] Frida server not running"
    echo "    Start with: adb shell su -c '/data/local/tmp/frida-server -D &'"
    exit 1
fi

# Check port forwarding
if adb forward --list | grep -q "27042"; then
    echo "[+] Port forwarding active"
else
    echo "[!] Port forwarding not set. Setting up..."
    adb forward tcp:27042 tcp:27042
fi

# Test Frida connection
if frida-ps -U >/dev/null 2>&1; then
    echo "[+] Frida connection successful"
    APP_COUNT=$(frida-ps -Uai | grep -v PID | wc -l)
    echo "    Visible apps: $APP_COUNT"
else
    echo "[!] Cannot connect to Frida server"
    exit 1
fi

echo ""
echo "[*] Frida environment is ready!"

Advanced Frida Configuration
#

Network-based Frida (Remote Device):
#

# On device, start Frida server with network binding:
adb shell su -c "/data/local/tmp/frida-server -l 0.0.0.0:27042 &"

# On host, connect via network (no USB needed):
frida-ps -H <DEVICE_IP>:27042

# Set as default device:
export FRIDA_DEVICE_HOST=<DEVICE_IP>:27042

# Spawn app remotely:
frida -H <DEVICE_IP>:27042 -f com.example.app -l script.js

# OPSEC: Use SSH tunnel for encrypted connection
ssh -L 27042:localhost:27042 user@device-ip
frida-ps -H localhost:27042

Frida with Multiple Devices:
#

# List all connected devices:
adb devices -l

# Specify device for Frida:
frida-ps -U --device <DEVICE_ID>

# Or set environment variable:
export ANDROID_SERIAL=<DEVICE_ID>
frida-ps -U

# Example with multiple devices:
frida -U --device emulator-5554 -f com.example.app
frida -U --device 192.168.1.100:27042 -f com.example.app

Frida Server as System Service (Persistent):
#

# Create systemd-style service for Magisk
adb shell su -c "mkdir -p /data/adb/service.d"

adb shell su -c "cat > /data/adb/service.d/frida-server.sh << 'EOF'
#!/system/bin/sh
# Wait for boot to complete
while [ \"\$(getprop sys.boot_completed)\" != \"1\" ]; do
    sleep 1
done

# Start Frida server
/data/local/tmp/frida-server -D -l 0.0.0.0:27042 &
EOF"

adb shell su -c "chmod 755 /data/adb/service.d/frida-server.sh"

# Reboot to test:
adb reboot

# After reboot, verify:
adb shell su -c "ps -A | grep frida"

# OPSEC Warning: Persistent Frida server may be detected by apps
# Use only in controlled environments

Troubleshooting Common Frida Issues:
#

# Issue 1: "Failed to spawn: unable to find process with name"
# Solution: Check if app is installed and package name is correct
frida-ps -Uai | grep -i <app_name>

# Issue 2: "Unable to connect to remote frida-server"
# Solution A: Check if server is running
adb shell su -c "ps -A | grep frida-server"

# Solution B: Restart server
adb shell su -c "killall frida-server; /data/local/tmp/frida-server -D &"

# Solution C: Check port forwarding
adb forward --list
adb forward tcp:27042 tcp:27042

# Issue 3: "Process terminated" when spawning
# Solution: App may have anti-Frida detection
# Use early instrumentation or patch detection

# Issue 4: Version mismatch error
# Solution: Ensure frida-tools and frida-server versions match
pip3 show frida | grep Version
adb shell /data/local/tmp/frida-server --version
# If mismatch, reinstall matching versions

# Issue 5: SELinux denials (Android 11+)
# Solution: Set SELinux to permissive temporarily
adb shell su -c "setenforce 0"
# Check status:
adb shell getenforce
# Reset to enforcing:
adb shell su -c "setenforce 1"

# Issue 6: "Operation not permitted" errors
# Solution: Check if Magisk is hiding root from shell
# Unhide root in Magisk settings or use su directly:
adb shell su -c "whoami"  # Should return "root"

OPSEC Best Practices:
#

# 1. Rename frida-server to avoid detection
adb push frida-server /data/local/tmp/srv
adb shell chmod 755 /data/local/tmp/srv
adb shell su -c "/data/local/tmp/srv -D &"

# 2. Use random port instead of 27042
RANDOM_PORT=$((27000 + RANDOM % 1000))
adb shell su -c "/data/local/tmp/frida-server -l 0.0.0.0:$RANDOM_PORT &"
adb forward tcp:$RANDOM_PORT tcp:$RANDOM_PORT
frida-ps -H localhost:$RANDOM_PORT

# 3. Clean up after testing
adb shell su -c "killall frida-server"
adb shell rm /data/local/tmp/frida-server
adb forward --remove-all

# 4. Check for anti-frida strings in app
strings app.apk | grep -iE "(frida|xposed|substrate)"

# 5. Use Frida in spawn mode to inject early
frida -U -f com.example.app -l script.js --no-pause
# This loads script before app initialization