Dynamic Analysis Methodology
Dynamic analysis involves testing the application at runtime to identify vulnerabilities that cannot be detected through static analysis alone. This includes bypassing security controls, manipulating application behavior, intercepting traffic, and extracting sensitive data.
Table of Contents
- Test Environment Setup
- Bypassing Security Protections
- Runtime Manipulation Techniques
- Hooking Strategies
- Traffic Interception Workflows
- Data Extraction Procedures
- Fuzzing Approaches
- Evidence Collection
Test Environment Setup
Device Preparation
Rooted Physical Device (Recommended)
# Verify device connection
adb devices
# Verify root access
adb shell su -c "id"
# Expected: uid=0(root) gid=0(root)
# Disable SELinux enforcement (if needed)
adb shell su -c "setenforce 0"
# Check SELinux status
adb shell getenforce
# Expected: PermissiveEmulator Setup
# Start emulator with writable system
emulator -avd <name> -writable-system
# For Google APIs images, get root
adb root
adb remountFrida Server Installation
# Download matching Frida server version
FRIDA_VERSION=$(frida --version)
ARCH="arm64" # or arm, x86, x86_64
# Push to device
adb push frida-server /data/local/tmp/frida-server
adb shell chmod 755 /data/local/tmp/frida-server
# Start Frida server
adb shell "su -c '/data/local/tmp/frida-server -D &'"
# Verify connection
frida-ps -UMCP Tool Verification
# In Claude Code, verify MCP tools are available:
# Test device connection
get_app_info("com.android.settings")
# Test Frida connection
pid = frida_spawn("com.android.settings")
frida_enumerate_classes(pid, "android.widget.*")Bypassing Security Protections
SSL/TLS Certificate Pinning Bypass
Method 1: Universal Frida Bypass (Most Apps)
# Using MCP tool
pid = frida_spawn("com.target.app")
frida_bypass_ssl(pid)The universal bypass hooks:
- TrustManagerImpl.checkTrustedRecursive
- TrustManagerImpl.verifyChain
- OkHttp3 CertificatePinner
- WebViewClient.onReceivedSslError
- HttpsURLConnection.setDefaultHostnameVerifier
- Various third-party libraries (Retrofit, Volley, etc.)
Method 2: Library-Specific Bypass
OkHttp3:
frida_run_script(pid, """
Java.perform(function() {
var CertificatePinner = Java.use('okhttp3.CertificatePinner');
CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function(hostname, peerCerts) {
console.log('[+] OkHttp3 pinning bypassed for: ' + hostname);
};
});
""")Flutter:
frida_run_script(pid, """
var flutter = Process.findModuleByName("libflutter.so");
if (flutter) {
var sslVerify = Module.findExportByName("libssl.so", "SSL_CTX_set_custom_verify");
if (sslVerify) {
Interceptor.attach(sslVerify, {
onEnter: function(args) {
var noop = new NativeCallback(function() { return 0; }, 'int', ['pointer', 'pointer']);
args[2] = noop;
}
});
console.log('[+] Flutter SSL pinning bypassed');
}
}
""")Root Detection Bypass
Method 1: Universal Root Bypass
pid = frida_spawn("com.target.app")
frida_bypass_root(pid)The universal bypass covers:
- File existence checks for su binaries
- Package manager queries for root apps
- Build.TAGS checks
- System property checks
- Native access() and stat() calls
Method 2: Targeted Root Bypass
RootBeer Library:
frida_run_script(pid, """
Java.perform(function() {
var RootBeer = Java.use('com.scottyab.rootbeer.RootBeer');
RootBeer.isRooted.implementation = function() {
console.log('[+] RootBeer.isRooted() bypassed');
return false;
};
RootBeer.detectRootManagementApps.implementation = function() {
return false;
};
RootBeer.checkForSuBinary.implementation = function() {
return false;
};
});
""")Anti-Tampering / Integrity Bypass
Debugger Detection Bypass
frida_run_script(pid, """
Java.perform(function() {
var Debug = Java.use('android.os.Debug');
Debug.isDebuggerConnected.implementation = function() {
console.log('[+] Debug.isDebuggerConnected() bypassed');
return false;
};
Debug.waitingForDebugger.implementation = function() {
console.log('[+] Debug.waitingForDebugger() bypassed');
return false;
};
});
""")Frida Detection Bypass
frida_run_script(pid, """
// Hide Frida from port scanning
Java.perform(function() {
var Socket = Java.use('java.net.Socket');
Socket.$init.overload('java.lang.String', 'int').implementation = function(host, port) {
if (port === 27042 || port === 27043) {
console.log('[+] Frida port scan blocked: ' + port);
throw Java.use('java.io.IOException').$new('Connection refused');
}
return this.$init(host, port);
};
});
// Hide Frida from process enumeration
var strstr = Module.findExportByName('libc.so', 'strstr');
Interceptor.attach(strstr, {
onEnter: function(args) {
this.needle = args[1].readCString();
},
onLeave: function(retval) {
if (this.needle && this.needle.indexOf('frida') !== -1) {
retval.replace(ptr(0));
}
}
});
""")Emulator Detection Bypass
frida_run_script(pid, """
Java.perform(function() {
var Build = Java.use('android.os.Build');
// Override emulator-specific Build fields
Build.FINGERPRINT.value = 'google/walleye/walleye:8.1.0/OPM1.171019.011/4448085:user/release-keys';
Build.MODEL.value = 'Pixel 2';
Build.MANUFACTURER.value = 'Google';
Build.BRAND.value = 'google';
Build.DEVICE.value = 'walleye';
Build.PRODUCT.value = 'walleye';
Build.HARDWARE.value = 'walleye';
// TelephonyManager
var TM = Java.use('android.telephony.TelephonyManager');
TM.getDeviceId.overload().implementation = function() {
return '355458061189396';
};
TM.getSubscriberId.implementation = function() {
return '310260000000000';
};
});
""")Runtime Manipulation Techniques
Method Hooking
Basic Method Hook
# Hook and log method calls
frida_hook_method(pid, "com.target.app.LoginManager", "authenticate")Modifying Method Arguments
frida_run_script(pid, """
Java.perform(function() {
var LoginManager = Java.use('com.target.app.LoginManager');
LoginManager.authenticate.implementation = function(username, password) {
console.log('[HOOK] Original credentials:');
console.log(' Username: ' + username);
console.log(' Password: ' + password);
// Modify arguments before passing to original method
var modifiedUsername = 'admin';
var modifiedPassword = 'admin123';
return this.authenticate(modifiedUsername, modifiedPassword);
};
});
""")Modifying Return Values
frida_run_script(pid, """
Java.perform(function() {
var SecurityManager = Java.use('com.target.app.SecurityManager');
// Force method to always return true
SecurityManager.isUserAuthorized.implementation = function(userId, permission) {
console.log('[HOOK] Authorization check bypassed');
return true; // Always authorized
};
// Force premium status
var UserProfile = Java.use('com.target.app.UserProfile');
UserProfile.isPremiumUser.implementation = function() {
console.log('[HOOK] Premium check bypassed');
return true;
};
});
""")Class Instantiation
Creating New Instances
frida_run_script(pid, """
Java.perform(function() {
var User = Java.use('com.target.app.model.User');
// Create new user instance
var fakeUser = User.$new();
fakeUser.setId(1337);
fakeUser.setUsername('hacker');
fakeUser.setRole('admin');
console.log('[+] Created fake user: ' + fakeUser.toString());
});
""")Accessing Existing Instances
frida_run_script(pid, """
Java.perform(function() {
// Find all instances of a class
Java.choose('com.target.app.session.SessionManager', {
onMatch: function(instance) {
console.log('[+] Found SessionManager instance');
console.log(' Session ID: ' + instance.getSessionId());
console.log(' User ID: ' + instance.getUserId());
console.log(' Token: ' + instance.getAuthToken());
// Modify the instance
instance.setAdminFlag(true);
},
onComplete: function() {
console.log('[+] Instance search complete');
}
});
});
""")Memory Manipulation
Searching Memory
# Search for strings in memory
frida_memory_search(pid, "password")
frida_memory_search(pid, "-----BEGIN RSA PRIVATE KEY-----")
frida_memory_search(pid, "secret_key")Hooking Strategies
Strategy 1: Authentication Bypass
// Complete authentication bypass strategy
frida_run_script(pid, """
Java.perform(function() {
console.log('[*] Authentication Bypass Strategy Loaded');
// 1. Hook login method
try {
var AuthService = Java.use('com.target.app.auth.AuthService');
AuthService.login.implementation = function(username, password) {
console.log('[AUTH] Login attempt: ' + username);
var result = this.login(username, password);
console.log('[AUTH] Login result: ' + result);
return result;
};
} catch (e) { console.log('AuthService not found'); }
// 2. Hook token validation
try {
var TokenValidator = Java.use('com.target.app.auth.TokenValidator');
TokenValidator.isValid.implementation = function(token) {
console.log('[AUTH] Token validation bypassed');
return true;
};
} catch (e) { console.log('TokenValidator not found'); }
// 3. Hook session checks
try {
var SessionManager = Java.use('com.target.app.session.SessionManager');
SessionManager.isSessionValid.implementation = function() {
console.log('[AUTH] Session validation bypassed');
return true;
};
} catch (e) { console.log('SessionManager not found'); }
// 4. Biometric bypass
try {
var BiometricPrompt = Java.use('android.hardware.biometrics.BiometricPrompt');
BiometricPrompt.authenticate.overload('android.os.CancellationSignal', 'java.util.concurrent.Executor', 'android.hardware.biometrics.BiometricPrompt$AuthenticationCallback').implementation = function(cancel, executor, callback) {
console.log('[AUTH] Biometric auth intercepted');
var AuthenticationResult = Java.use('android.hardware.biometrics.BiometricPrompt$AuthenticationResult');
var CryptoObject = Java.use('android.hardware.biometrics.BiometricPrompt$CryptoObject');
var result = AuthenticationResult.$new(CryptoObject.$new(null));
callback.onAuthenticationSucceeded(result);
console.log('[AUTH] Biometric bypassed');
};
} catch (e) { console.log('BiometricPrompt not found'); }
});
""")Strategy 2: Crypto Key Extraction
// Extract all cryptographic keys
frida_run_script(pid, """
Java.perform(function() {
console.log('[*] Crypto Key Extraction Strategy Loaded');
function bytesToHex(bytes) {
var hex = '';
for (var i = 0; i < bytes.length; i++) {
hex += ('0' + (bytes[i] & 0xFF).toString(16)).slice(-2);
}
return hex;
}
// 1. Hook SecretKeySpec creation
var SecretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');
SecretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function(keyBytes, algorithm) {
console.log('[CRYPTO] SecretKeySpec created');
console.log(' Algorithm: ' + algorithm);
console.log(' Key (hex): ' + bytesToHex(keyBytes));
return this.$init(keyBytes, algorithm);
};
// 2. Hook Cipher init with key
var Cipher = Java.use('javax.crypto.Cipher');
Cipher.init.overload('int', 'java.security.Key').implementation = function(mode, key) {
var modeStr = mode === 1 ? 'ENCRYPT' : mode === 2 ? 'DECRYPT' : mode;
console.log('[CRYPTO] Cipher.init');
console.log(' Mode: ' + modeStr);
console.log(' Key algorithm: ' + key.getAlgorithm());
var encoded = key.getEncoded();
if (encoded) {
console.log(' Key (hex): ' + bytesToHex(encoded));
}
return this.init(mode, key);
};
// 3. Hook KeyStore key retrieval
var KeyStore = Java.use('java.security.KeyStore');
KeyStore.getKey.implementation = function(alias, password) {
var key = this.getKey(alias, password);
console.log('[CRYPTO] KeyStore.getKey');
console.log(' Alias: ' + alias);
if (key) {
console.log(' Algorithm: ' + key.getAlgorithm());
}
return key;
};
});
""")Strategy 3: Network Traffic Analysis
// Comprehensive network monitoring
frida_run_script(pid, """
Java.perform(function() {
console.log('[*] Network Traffic Analysis Strategy Loaded');
// 1. Hook HttpURLConnection
var URL = Java.use('java.net.URL');
URL.openConnection.overload().implementation = function() {
var conn = this.openConnection();
console.log('[NET] URL.openConnection: ' + this.toString());
return conn;
};
// 2. Hook OkHttp Request/Response
try {
var RequestBuilder = Java.use('okhttp3.Request$Builder');
RequestBuilder.build.implementation = function() {
var request = this.build();
console.log('[NET] OkHttp Request');
console.log(' URL: ' + request.url().toString());
console.log(' Method: ' + request.method());
var headers = request.headers();
for (var i = 0; i < headers.size(); i++) {
console.log(' Header: ' + headers.name(i) + ': ' + headers.value(i));
}
return request;
};
} catch (e) { console.log('OkHttp not found'); }
});
""")Strategy 4: Data Leakage Detection
// Monitor all data storage operations
frida_run_script(pid, """
Java.perform(function() {
console.log('[*] Data Leakage Detection Strategy Loaded');
// 1. SharedPreferences writes
var SharedPrefsEditor = Java.use('android.app.SharedPreferencesImpl$EditorImpl');
SharedPrefsEditor.putString.implementation = function(key, value) {
console.log('[DATA] SharedPreferences.putString');
console.log(' Key: ' + key);
console.log(' Value: ' + value);
// Flag sensitive data
if (key.toLowerCase().indexOf('password') !== -1 ||
key.toLowerCase().indexOf('token') !== -1 ||
key.toLowerCase().indexOf('secret') !== -1) {
console.log(' [!] SENSITIVE DATA DETECTED');
}
return this.putString(key, value);
};
// 2. SQLite writes
var SQLiteDatabase = Java.use('android.database.sqlite.SQLiteDatabase');
SQLiteDatabase.insert.implementation = function(table, nullColumnHack, values) {
console.log('[DATA] SQLite INSERT');
console.log(' Table: ' + table);
console.log(' Values: ' + values.toString());
return this.insert(table, nullColumnHack, values);
};
// 3. File writes
var FileOutputStream = Java.use('java.io.FileOutputStream');
FileOutputStream.$init.overload('java.io.File').implementation = function(file) {
console.log('[DATA] FileOutputStream: ' + file.getAbsolutePath());
return this.$init(file);
};
// 4. Clipboard
var ClipboardManager = Java.use('android.content.ClipboardManager');
ClipboardManager.setPrimaryClip.implementation = function(clip) {
console.log('[DATA] Clipboard write');
var item = clip.getItemAt(0);
if (item) {
console.log(' Content: ' + item.getText());
}
return this.setPrimaryClip(clip);
};
});
""")Traffic Interception Workflows
Workflow 1: Proxy Setup with Burp Suite
# 1. Configure device proxy
setup_proxy("device-id", "192.168.1.100", 8080)
# 2. Install CA certificate
install_ca_cert("device-id", "/path/to/burp-ca.der")
# 3. Bypass SSL pinning
pid = frida_spawn("com.target.app")
frida_bypass_ssl(pid)
# 4. In Burp Suite:
# - Configure proxy listener on 192.168.1.100:8080
# - Enable invisible proxying
# - Add target scope
# 5. After testing, clear proxy
clear_proxy("device-id")Workflow 2: Traffic Capture without Proxy
# Start packet capture
capture_traffic_start("com.target.app")
# ... interact with application ...
# Stop capture
capture_traffic_stop()
# PCAP file saved for analysis with WiresharkData Extraction Procedures
Procedure 1: Complete Data Dump
# 1. Dump all storage types
databases = dump_databases("com.target.app")
prefs = dump_shared_prefs("com.target.app")
internal = dump_internal_storage("com.target.app")
external = dump_external_storage("com.target.app")
logs = get_logcat("com.target.app")
# 2. Analyze each dump for sensitive data
# Look for: credentials, tokens, PII, financial data, session infoProcedure 2: Runtime Credential Extraction
frida_run_script(pid, """
Java.perform(function() {
var credentials = [];
// Hook AccountManager
var AccountManager = Java.use('android.accounts.AccountManager');
AccountManager.getAccounts.implementation = function() {
var accounts = this.getAccounts();
for (var i = 0; i < accounts.length; i++) {
credentials.push({
type: 'Account',
name: accounts[i].name,
accountType: accounts[i].type
});
console.log('[CRED] Account: ' + accounts[i].name + ' (' + accounts[i].type + ')');
}
return accounts;
};
AccountManager.getPassword.implementation = function(account) {
var password = this.getPassword(account);
console.log('[CRED] Password for ' + account.name + ': ' + password);
return password;
};
});
""")Fuzzing Approaches
Approach 1: Intent Fuzzing
# Get list of exported components
components = list_exported_components("com.target.app")
# Fuzz each exported activity with various payloads
for activity in components['activities']:
# Path traversal
fuzz_intent_extra("com.target.app", activity, "file_path", [
"../../../etc/passwd",
"/data/data/com.target.app/../com.other.app/databases/secrets.db",
"file:///etc/passwd"
])
# SQL injection
fuzz_intent_extra("com.target.app", activity, "user_id", [
"1",
"1 OR 1=1",
"1' OR '1'='1"
])
# XSS (for WebView activities)
fuzz_intent_extra("com.target.app", activity, "url", [
"javascript:alert(document.cookie)",
"data:text/html,<script>alert(1)</script>"
])Approach 2: Content Provider Fuzzing
# Query with SQL injection payloads
providers = components['providers']
for provider in providers:
uri = f"content://{provider['authority']}"
# Basic query
query_content_provider(uri)
# SQL injection in selection
query_content_provider(f"{uri}/users?selection=1%20OR%201=1")
# Path traversal
query_content_provider(f"{uri}/../../../etc/passwd")Approach 3: Deep Link Fuzzing
# Test deep link schemes
deep_links = [
"targetapp://login?user=admin&password=test",
"targetapp://transfer?amount=1000&to=attacker",
"targetapp://webview?url=javascript:alert(1)",
"targetapp://file?path=../../../etc/passwd"
]
for link in deep_links:
launch_activity("com.target.app", ".DeepLinkActivity", data_uri=link)Evidence Collection
Collecting Screenshots
# Take screenshot during testing
get_screen_state() # Includes screenshot
# Or via ADB
# adb shell screencap -p /sdcard/screenshot.png
# adb pull /sdcard/screenshot.pngCapturing Evidence Package
# Create comprehensive evidence collection
evidence = {
'app_info': get_app_info("com.target.app"),
'components': list_exported_components("com.target.app"),
'databases': dump_databases("com.target.app"),
'shared_prefs': dump_shared_prefs("com.target.app"),
'internal_storage': dump_internal_storage("com.target.app"),
'external_storage': dump_external_storage("com.target.app"),
'logcat': get_logcat("com.target.app")
}Video Recording
# Record device screen during testing
adb shell screenrecord /sdcard/test_session.mp4
# After testing
adb pull /sdcard/test_session.mp4Quick Reference: Dynamic Analysis Checklist
- Device/emulator properly configured with root access
- Frida server running and connected
- MCP tools verified working
- SSL pinning bypassed
- Root detection bypassed
- Anti-tampering bypassed (if present)
- Traffic interception configured
- Crypto operations monitored
- Credential storage monitored
- All data storage types dumped
- Exported components fuzzed
- Deep links tested
- Content providers tested
- Evidence collected and documented