Set up a complete Android app penetration testing environment using Android Studio emulators with Magisk root, Frida, HTTP Toolkit, and LSPosed modules
---
name: android-studio-pentest-environment
description: Set up a complete Android app penetration testing environment using Android Studio emulators with Magisk root, Frida, HTTP Toolkit, and LSPosed modules
triggers:
- how do I set up an Android pentest lab
- configure Android emulator for security testing
- install Magisk and Frida on Android Studio AVD
- set up rootAVD for app testing
- create Android pentest environment
- configure HTTP proxy for Android app analysis
- install LSPosed modules for bypassing SSL pinning
- troubleshoot Android emulator root access
---
# Android Studio Pentest Environment Setup
> Skill by [ara.so](https://ara.so) — Security Skills collection.
This skill provides expertise in setting up a complete Android application penetration testing environment using Android Studio Virtual Device Manager (AVD) with root access via Magisk, Frida dynamic instrumentation, HTTP Toolkit for traffic interception, and LSPosed modules for runtime manipulation.
## What This Project Does
This project guides you through building a 2026-ready Android app penetration testing lab that includes:
- **Android Studio AVD** with Google APIs (API 36/Android 16)
- **Magisk (root)** via rootAVD automation
- **Frida** for dynamic instrumentation
- **HTTP Toolkit** for HTTPS traffic interception
- **LSPosed** with TrustMeAlready and JustTrustMe modules for SSL pinning bypass
- **Shamiko** for root hiding
- **ZygiskNext** as modern Zygisk replacement
## Prerequisites
### Install Android Studio and SDK
```bash
# macOS - Add to ~/.bash_profile or ~/.zshrc
export ANDROID_HOME="$HOME/Library/Android/sdk"
export PATH="$PATH:$ANDROID_HOME/platform-tools"
export PATH="$PATH:$ANDROID_HOME/tools"
export PATH="$PATH:$ANDROID_HOME/tools/bin"
export PATH="$PATH:$ANDROID_HOME/emulator"
# Linux
export ANDROID_HOME="$HOME/Android/Sdk"
export PATH="$PATH:$ANDROID_HOME/platform-tools"
# Windows (PowerShell $PROFILE)
$env:ANDROID_HOME = "$env:LOCALAPPDATA\Android\Sdk"
$env:Path += ";$env:ANDROID_HOME\platform-tools"
```
Apply the configuration:
```bash
source ~/.bash_profile # or ~/.zshrc
adb version # Verify installation
```
### Create Android Virtual Device
```bash
# List available system images
sdkmanager --list | grep system-images
# Download recommended image (Google APIs, not Google Play)
sdkmanager "system-images;android-36;google_apis;arm64-v8a"
# Create AVD via Android Studio GUI:
# Device: Pixel 9 Pro
# System Image: API 36 (Android 16), Google APIs, arm64-v8a
# RAM: 4096 MB
# Internal Storage: 16 GB
# VM Heap: 512 MB
# Boot option: Cold boot
```
## Root the Emulator with Magisk
### Method A: rootAVD (Recommended)
```bash
# Clone rootAVD (GitLab is now primary, GitHub is read-only)
git clone https://gitlab.com/newbit/rootAVD.git
cd rootAVD
# Download latest Magisk APK and rename to Magisk.zip
curl -L -o Magisk.zip https://github.com/topjohnwu/Magisk/releases/download/v28.1/Magisk-v28.1.apk
# List available AVDs
./rootAVD.sh ListAllAVDs
# Root the specific system image
./rootAVD.sh system-images/android-36.1/google_apis/arm64-v8a/ramdisk.img
# Cold boot the emulator (automatic if configured)
```
### Method B: Manual Magisk Patch (Fallback)
```bash
# Start emulator with writable system
emulator -avd Pixel_9_Pro_API_36 -writable-system &
adb root
adb remount
# Install Magisk APK
adb install Magisk-v28.1.apk
# Push ramdisk to device
adb push "$ANDROID_HOME/system-images/android-36/google_apis/arm64-v8a/ramdisk.img" /sdcard/Download/
# In Magisk app: Install → Select and Patch a File → choose ramdisk.img
# Download patched file back to host
adb pull /sdcard/Download/magisk_patched_*.img ./
# Replace ramdisk and restart
cp magisk_patched_*.img "$ANDROID_HOME/system-images/android-36/google_apis/arm64-v8a/ramdisk.img"
adb reboot
```
### Configure Magisk
```bash
# Open Magisk app and enable:
# - Zygisk (Settings → Zygisk)
# - Hide Magisk app (Settings → Hide Magisk → Random package name)
# Verify root
adb shell su -c "id"
# Expected: uid=0(root) gid=0(root)
```
## Install Frida
### Frida Server on Device
```bash
# Download Frida server matching your Frida tools version
FRIDA_VERSION="16.5.9"
curl -L -o frida-server.xz "https://github.com/frida/frida/releases/download/${FRIDA_VERSION}/frida-server-${FRIDA_VERSION}-android-arm64.xz"
unxz frida-server.xz
# Push to device
adb push frida-server /data/local/tmp/
adb shell "chmod 755 /data/local/tmp/frida-server"
# Start Frida server
adb shell "su -c '/data/local/tmp/frida-server &'"
# Verify
frida-ps -U
```
### Frida Tools on Host
```bash
# Install Frida CLI
pip install frida-tools==16.5.9
# Verify connection
frida-ps -U
# Should list running processes on emulator
```
### Frida Usage Examples
```python
# attach_script.py - Hook a function
import frida
import sys
def on_message(message, data):
print(f"[*] {message}")
package = "com.example.app"
device = frida.get_usb_device()
session = device.attach(package)
script_code = """
Java.perform(function() {
var MainActivity = Java.use('com.example.app.MainActivity');
MainActivity.checkRoot.implementation = function() {
console.log('[*] checkRoot() bypassed');
return false;
};
});
"""
script = session.create_script(script_code)
script.on('message', on_message)
script.load()
sys.stdin.read()
```
```bash
# Hook SSL pinning check
frida -U -f com.example.app -l ssl-pinning-bypass.js --no-pause
```
## Install LSPosed and Modules
### Install LSPosed (Zygisk version)
```bash
# Download LSPosed Zygisk release
curl -L -o LSPosed.zip https://github.com/LSPosed/LSPosed/releases/download/v1.9.2/LSPosed-v1.9.2-7024-zygisk-release.zip
# Flash via Magisk
adb push LSPosed.zip /sdcard/Download/
# In Magisk: Modules → Install from storage → select LSPosed.zip
adb reboot
```
### Upgrade to ZygiskNext
```bash
# Download ZygiskNext (modern Zygisk replacement)
curl -L -o ZygiskNext.zip https://github.com/Dr-TSNG/ZygiskNext/releases/download/v4.0.2/Zygisk-Next-4.0.2-291-release.zip
# Flash via Magisk
adb push ZygiskNext.zip /sdcard/Download/
# Magisk: Modules → Install → ZygiskNext.zip
# Disable built-in Zygisk in Magisk settings
adb reboot
```
### Install TrustMeAlready (SSL Pinning Bypass)
```bash
# Download TrustMeAlready module
curl -L -o TrustMeAlready.apk https://github.com/ViRb3/TrustMeAlready/releases/download/v1.11/TrustMeAlready-v1.11.apk
# Install APK
adb install TrustMeAlready.apk
# Activate in LSPosed:
# 1. Open LSPosed Manager
# 2. Modules → Enable TrustMeAlready
# 3. Select target apps or enable globally
# 4. Reboot
```
### Install JustTrustMe (Alternative)
```bash
# Download JustTrustMe
curl -L -o JustTrustMe.apk https://github.com/Fuzion24/JustTrustMe/releases/download/v.2/JustTrustMe.apk
adb install JustTrustMe.apk
# Activate in LSPosed similar to TrustMeAlready
```
## HTTP Traffic Interception
### Method A: HTTP Toolkit
```bash
# Install HTTP Toolkit
brew install --cask http-toolkit # macOS
# Or download from https://httptoolkit.com/
# Start HTTP Toolkit and select "Android Device via ADB"
# It will automatically:
# 1. Install HTTP Toolkit app on emulator
# 2. Configure system proxy
# 3. Install CA certificate
# Verify proxy is set
adb shell settings get global http_proxy
```
### Method B: Manual Proxy Setup
```bash
# Set up proxy (e.g., Burp Suite on 127.0.0.1:8080)
adb shell settings put global http_proxy 127.0.0.1:8080
# Install CA certificate
# 1. Export cert from Burp (DER format)
# 2. Convert to PEM and get hash
openssl x509 -inform DER -in burp.cer -out burp.pem
HASH=$(openssl x509 -inform PEM -subject_hash_old -in burp.pem | head -1)
# Push to system store
adb root
adb remount
adb push burp.pem "/system/etc/security/cacerts/${HASH}.0"
adb shell chmod 644 "/system/etc/security/cacerts/${HASH}.0"
adb reboot
```
## Install Shamiko (Root Hiding)
```bash
# Download Shamiko
curl -L -o Shamiko.zip https://github.com/LSPosed/LSPosed.github.io/releases/download/shamiko-281/Shamiko-v0.7.4-281-release.zip
# Flash via Magisk
adb push Shamiko.zip /sdcard/Download/
# Magisk: Modules → Install → Shamiko.zip
adb reboot
# Configure Shamiko whitelist mode
# Magisk: Shamiko → Whitelist mode → Add apps to hide root from
```
## Testing and Verification
### Verify Root Status
```bash
# Check root access
adb shell su -c "whoami"
# Expected: root
# Test with Magisk app
adb shell pm list packages | grep -i magisk
# Should show random package name if hidden
```
### Verify Frida
```bash
# List processes
frida-ps -U
# Test hook
frida -U -f com.android.settings -l test.js
# test.js content:
# Java.perform(() => {
# console.log('[*] Frida is working!');
# });
```
### Verify SSL Pinning Bypass
```bash
# Start HTTP Toolkit or Burp
# Launch target app
# Attempt HTTPS request
# Traffic should appear in proxy without certificate errors
```
## Common Patterns
### Install APK and Analyze
```bash
# Install APK
adb install target.apk
# List app info
adb shell pm list packages -f | grep target
adb shell dumpsys package com.example.target | grep version
# Pull APK for static analysis
adb shell pm path com.example.target
adb pull /data/app/com.example.target-xxx/base.apk
```
### Hook Function with Frida
```javascript
// hook_login.js
Java.perform(() => {
const LoginActivity = Java.use('com.example.app.LoginActivity');
LoginActivity.validateCredentials.implementation = function(username, password) {
console.log(`[*] Username: ${username}`);
console.log(`[*] Password: ${password}`);
return this.validateCredentials(username, password);
};
});
```
```bash
frida -U -f com.example.app -l hook_login.js --no-pause
```
### Bypass Root Detection
```javascript
// bypass_root.js
Java.perform(() => {
// Hook common root detection methods
const RootBeer = Java.use('com.scottyab.rootbeer.RootBeer');
RootBeer.isRooted.implementation = () => false;
const File = Java.use('java.io.File');
File.exists.implementation = function() {
const path = this.getAbsolutePath();
if (path.includes('su') || path.includes('magisk')) {
return false;
}
return this.exists();
};
});
```
### Extract Secrets from Memory
```python
# dump_strings.py
import frida
import sys
package = "com.example.app"
device = frida.get_usb_device()
pid = device.spawn([package])
session = device.attach(pid)
script = session.create_script("""
Java.perform(() => {
const String = Java.use('java.lang.String');
String.$init.overload('java.lang.String').implementation = function(str) {
if (str.includes('api_key') || str.includes('secret')) {
console.log('[*] Found secret: ' + str);
}
return this.$init(str);
};
});
""")
script.load()
device.resume(pid)
sys.stdin.read()
```
## Troubleshooting
### Magisk Not Showing Root
```bash
# Verify Magisk installation
adb shell ls -la /data/adb/magisk/
# Check Magisk daemon
adb shell su -c "magisk --version"
# Reinstall via rootAVD
cd rootAVD
./rootAVD.sh system-images/android-36.1/google_apis/arm64-v8a/ramdisk.img restore
./rootAVD.sh system-images/android-36.1/google_apis/arm64-v8a/ramdisk.img
```
### Frida Server Crashes
```bash
# Check architecture match
adb shell getprop ro.product.cpu.abi
# Should be arm64-v8a
# Kill existing server
adb shell "su -c 'killall frida-server'"
# Restart with debug output
adb shell "su -c '/data/local/tmp/frida-server -D'"
```
### LSPosed Not Working
```bash
# Verify Zygisk is enabled
adb shell su -c "magisk --sqlite 'SELECT * FROM settings WHERE key=\"zygisk\"'"
# Check LSPosed installation
adb shell ls -la /data/adb/lspd/
# Clear LSPosed cache
adb shell su -c "rm -rf /data/adb/lspd/cache"
adb reboot
```
### SSL Pinning Bypass Not Working
```bash
# Ensure modules are activated for target app
# LSPosed Manager → Modules → TrustMeAlready → Check target app
# Try alternative: disable pinning via Frida
frida -U -f com.example.app --codeshare akabe1/frida-multiple-unpinning
# Verify certificate installation
adb shell "su -c 'ls -la /system/etc/security/cacerts/'"
```
### Emulator Boot Loop After Root
```bash
# Restore from snapshot if created
# Android Studio → Device Manager → Snapshots → Restore
# Or restore original ramdisk
cd rootAVD
./rootAVD.sh system-images/android-36.1/google_apis/arm64-v8a/ramdisk.img restore
# Cold boot
emulator -avd Pixel_9_Pro_API_36 -no-snapshot-load
```
### ADB Not Finding Device
```bash
# Restart ADB server
adb kill-server
adb start-server
# Check emulator is running
emulator -list-avds
adb devices
# Connect manually if needed
adb connect 127.0.0.1:5555
```
## Environment Variables
Always use environment variables for sensitive configuration:
```bash
# Example: Frida script with API key
# frida_config.js
const API_KEY = Java.use('java.lang.System').getenv('TARGET_API_KEY');
```
```bash
# Set before running
export TARGET_API_KEY="your-key-here"
frida -U -f com.example.app -l frida_config.js
```
## References
- Android Studio: https://developer.android.com/studio
- rootAVD: https://gitlab.com/newbit/rootAVD
- Magisk: https://github.com/topjohnwu/Magisk
- Frida: https://frida.re/
- LSPosed: https://github.com/LSPosed/LSPosed
- HTTP Toolkit: https://httptoolkit.com/
Creator's repository · aradotso/security-skills