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