iOS Frida Pentesting Skill
A comprehensive skill for iOS mobile security testing using Frida instrumentation framework.
When to Use This Skill
Use this skill when the user:
- Needs to perform iOS application security testing
- Wants to hook or trace Objective-C/Swift methods
- Needs to bypass jailbreak or Frida detection
- Wants to fuzz iOS applications
- Needs to inspect or manipulate iOS app memory
- Is doing iOS reverse engineering or dynamic analysis
- Needs to enumerate iOS app classes, methods, or exports
Quick Start
Prerequisites
- Jailbroken iOS device (or Corellium VM)
- Frida server running on the device
- Frida tools installed on your machine:
pip install frida frida-tools
Verify Connection
frida-ls-devices # List connected devices
frida-ps -Uia # List running processes
Core Tasks
1. Enumerate Classes and Methods
Use the bundled scripts to discover app internals:
# List all Objective-C classes
frida -U <app-bundle> -l scripts/enumerate-classes.js
# List methods for a specific class
frida -U <app-bundle> -l scripts/enumerate-methods.js
2. Hook Objective-C Methods
Intercept and modify method calls:
# Hook authentication methods
frida -U <app-bundle> -l scripts/hook-objc.js
The script hooks common patterns:
- Login/Authentication methods
- Data storage (NSUserDefaults)
- Crypto operations
- Network requests
3. Bypass Jailbreak Detection
Use LLDB + Frida combination for production builds:
# Forward SSH to device
iproxy 2222 22 &
ssh root@localhost -p 2222
# On device, spawn debugger
debugserver *:5678 --waitfor <BundleName>
# On macOS, attach LLDB
iproxy 1234 5678 &
lldb
(lldb) process connect connect://localhost:1234
(lldb) finish # Run until constructors complete
Then patch Swift detection functions:
(lldb) breakpoint set --name '*systemSanityCheck'
(lldb) c
(lldb) finish
(lldb) register write x0 0 # Force return false
(lldb) c
4. Trace Function Calls
Use frida-trace for quick tracing:
# Trace functions containing "log"
frida-trace -U <app> -i "*log*"
# Trace all Objective-C methods
frida-trace -U <app> -m "*[* *]"
# Trace specific class methods
frida-trace -U <app> -m "*[NE* *authentication*]"
5. Fuzz iOS Applications
Use the bundled fuzzer scripts:
# Simple standalone fuzzer
frida -U <app> -l scripts/simple-fuzzer.js
# Advanced fuzzer with crash monitoring
frida -U <app> -l scripts/advanced-fuzzer.js
For production fuzzing with fpicker:
# Compile fuzzer script
frida-compile scripts/myfuzzer.js -o harness.js
# Run with fpicker
fpicker -v --fuzzer-mode active -e attach -p <app> -D usb \
-o ./out/ -i ./in/ -f harness.js \
--standalone-mutator cmd --mutator-command "radamsa"
6. Memory Inspection
Scan and manipulate process memory:
frida -U <app> -l scripts/memory-scan.js
Available functions (use in Frida console):
findString(str)- Search for strings in memoryfindBytes(pattern)- Search for byte patternsdumpMemory(address, size)- Dump memory regionpatchMemory(address, [bytes])- Write to memorywatchMemory(address, size)- Monitor memory changesenumerateModules()- List loaded modulesfindPointers(address)- Find pointers to address
Script Reference
enumerate-classes.js
Lists all Objective-C classes in the target app.
Usage:
frida -U <app> -l scripts/enumerate-classes.js
Configuration:
- Set
filterClassvariable to filter by substring - Leave empty to list all classes
enumerate-methods.js
Lists all methods for a specific Objective-C class.
Usage:
frida -U <app> -l scripts/enumerate-methods.js
Configuration:
- Set
specificClassto target class name - Set
filterMethodto filter methods by substring
hook-objc.js
Hooks common Objective-C methods for security testing.
Pre-configured hooks:
LoginViewController.authenticate:AuthManager.validatePassword:NSUserDefaultsmethodsNSString.dataUsingEncoding:NSURLSession.dataTaskWithRequest:completionHandler:
To add custom hooks:
hookMethod("YourClass", "- yourMethod:")
hook-swift.js
Hooks Swift functions using mangled names.
Usage:
frida -U <app> -l scripts/hook-swift.js
Configuration:
- Set
MODULE_NAMEto the dylib name - Set
FUNCTION_NAMEto the mangled Swift symbol - Use
frida-traceto discover mangled names
simple-fuzzer.js
Standalone fuzzer without fpicker dependency.
Usage:
frida -U <app> -l scripts/simple-fuzzer.js
Configuration:
TARGET_MODULE- App binary nameTARGET_FUNCTION- Function to fuzzITERATIONS- Number of fuzz iterationsMAX_PAYLOAD_SIZE- Maximum payload size
Mutation strategies:
- Buffer overflow (long strings)
- Format string bugs
- Null bytes and boundary characters
- SQL injection patterns
- XSS payloads
- Path traversal
- Invalid Unicode
- Random binary data
advanced-fuzzer.js
Fuzzer with crash monitoring and signal handlers.
Features:
- Exception handler for crashes
- Hooks dangerous functions (abort, malloc, free)
- Timeout detection for hangs
- Detailed crash reporting with backtraces
memory-scan.js
Memory inspection and manipulation toolkit.
Exported functions:
findString(str) // Search for string
findBytes(pattern) // Search for byte pattern
dumpMemory(addr, size) // Dump memory region
patchMemory(addr, bytes) // Write to memory
watchMemory(addr, size) // Monitor changes
enumerateModules() // List modules
findPointers(addr) // Find pointers to address
getProtection(addr) // Get memory protection
changeProtection(addr, size, prot) // Change protection
Common Patterns
Bypass Authentication
// Hook authentication method
ObjC.classes.AuthManager["- isAuthenticated"].implementation = function() {
console.log("[!] Bypassing authentication!")
return 1 // Always return true
}
Intercept Network Requests
ObjC.classes.NSURLSession["- dataTaskWithRequest:completionHandler:"].implementation = function(request, handler) {
console.log("[+] Network request:", request.URL)
console.log("[+] Headers:", request.allHTTPHeaderFields)
return this.$super["- dataTaskWithRequest:completionHandler:"](request, handler)
}
Capture Sensitive Data
// Hook string encoding to capture data before encryption
ObjC.classes.NSString["- dataUsingEncoding:"].implementation = function(encoding) {
var str = this.toString()
console.log("[+] String being encoded:", str)
return this.$super["- dataUsingEncoding:"](encoding)
}
Read Keychain Data
// Hook SecItemCopyMatching
Interceptor.attach(Module.findExportByName(null, "SecItemCopyMatching"), {
onEnter: function(args) {
console.log("[+] Keychain query:", JSON.stringify(args[0].readUtf8String()))
},
onLeave: function(retval) {
console.log("[+] Keychain result:", retval)
}
})
Troubleshooting
Device Not Detected
# Check USB connection
frida-ls-devices
# For Corellium, ensure frida-gadget is in correct location
cp frida-gadget-*.dylib /Users/[user]/.cache/frida/gadget-ios.dylib
App Crashes on Attach
- Try LLDB-assisted approach for anti-instrumentation apps
- Use
--no-pauseflag:frida -U -f <app> --no-pause - Check for jailbreak detection and bypass it first
Swift Functions Not Found
# Discover mangled names
frida-trace -U <app> -i "*function_name*"
# Use the mangled name in your script
Module.findExportByName("<module>", "$s16App11ContentViewV13functionNameySS_tF")
Memory Scan Returns Nothing
- Ensure you're scanning readable ranges:
Process.enumerateRanges('r--') - Try different memory permissions:
r-x,rw-,rwx - Check if the data is in a different module
Best Practices
- Start with enumeration - Use
enumerate-classes.jsto understand the app structure - Trace before hooking - Use
frida-traceto find relevant functions - Test hooks incrementally - Hook one method at a time
- Save crash-inducing inputs - Check
/private/var/mobile/Library/Logs/CrashReporter/ - Use coverage feedback - AFL++ mode in fpicker for better fuzzing
- Monitor for hangs - Add timeouts to detect infinite loops
- Reset state between tests - Restart app after crashes
References
Logs and Crashes
iOS Crash Logs
# On device
/private/var/mobile/Library/Logs/CrashReporter/
# Via Settings
Settings → Privacy → Analytics & Improvements → Analytics Data
Enable Private Logging
# Edit logging config
vim /Library/Preferences/Logging/com.apple.system.logging.plist
# Add:
<key>Enable-Private-Data</key>
<true/>
# Restart logging
killall -9 logd
macOS Console
# View logs
log show --predicate 'process == "<app-name>"' --last 1h
# Check crash reports
/Library/Logs/DiagnosticReports/
~/Library/Logs/DiagnosticReports/
Notes
- iOS only stores 25 crashes per app - clean old reports regularly
- Frida hooks may prevent iOS crash report generation
- For production testing, use LLDB + Frida combination
- Swift ABI: small strings (≤15 bytes) inline in x0, large strings heap-backed at x1+32