Frida
Frida is the dynamic instrumentation engine at the heart of most iOS mobile testing. With it you hook methods at runtime, bypass SSL pinning and jailbreak detection, and trace crypto or network calls — no recompilation needed.
Installing Frida
Host side (macOS or Parrot):
pip3 install frida-tools
frida --version
Device side (jailbroken):
# Install the frida server/tweak from Cydia/Sileo: "Frida" package
# Or via SSH after iproxy:
iproxy 2222 22
ssh root@localhost -p 2222
apt update && apt install -y frida # on palera1n/Dopamine-style jailbreaks
# Start the server (some jailbreaks auto-start it)
frida-server -D
# Run in foreground with logging
frida-server -l 127.0.0.1
Simulator:
- No device server needed. Run Frida on the host and target the simulator process directly.
Basic Usage
# List processes on a connected USB device
frida-ps -U
# List applications (user apps)
frida-ps -Uai
# Attach to a running process by name or PID
frida -U com.example.app
# Spawn and attach (use when the app needs cold-start hooks)
frida -U -f com.example.app
# Spawn, attach, and run an inline JS script
frida -U -f com.example.app -l hook.js
For the simulator, drop -U and use the process name directly:
frida-ps
frida -f com.example.app
Common JS Snippets
Save these as .js files and pass with -l, or type interactively in the Frida REPL.
Intercepting an Objective-C method
if (ObjC.available) {
var cls = ObjC.classes.NSString;
Interceptor.attach(cls["- stringWithFormat:"].implementation, {
onEnter(args) {
console.log("stringWithFormat called");
// args[2] is self, args[3] is the format string (ObjC method ABI)
console.log(ObjC.Object(args[3]).toString());
}
});
}
Hook any method by class name and selector
// Generic logger: enumerate methods on a class and log invocations
var cls = ObjC.classes.SomeAPIClient;
var methods = ObjC.enumerateMethods("SomeAPIClient").SomeAPIClient;
methods.forEach(function (m) {
try {
Interceptor.attach(cls[m].implementation, {
onEnter(args) {
console.log("[+] " + m);
},
onLeave(retval) {
console.log(" -> " + retval);
}
});
} catch (e) {}
});
Logging arguments and return values of an Objective-C method
Interceptor.attach(ObjC.classes.NSURLSession["- dataTaskWithURL:"].implementation, {
onEnter(args) {
var url = ObjC.Object(args[2]);
console.log("URL: " + url.absoluteString().toString());
}
});
Reading/writing instance variables
var inst = ObjC.classes.ViewController.alloc().init();
var ivars = inst.$ivars;
console.log(ivars._username);
Bypassing Jailbreak Detection
Jailbreak checks often look for Cydia paths, fork/system results, or dlopen of suspicious libraries. A blunt bypass: hide known jailbreak files from FileManager and neutralize common checks.
if (ObjC.available) {
var fm = ObjC.classes.NSFileManager["- fileExistsAtPath:"];
Interceptor.attach(fm.implementation, {
onEnter(args) {
var p = ObjC.Object(args[2]).toString();
if (p.indexOf("/Applications/Cydia.app") === 0 ||
p.indexOf("/bin/bash") === 0 ||
p.indexOf("/usr/sbin/sshd") === 0) {
console.log("blocking check: " + p);
this.block = true;
}
},
onLeave(retval) {
if (this.block) retval.replace(0); // return NO/false
}
});
}
More robust: install frida-ios-hook scripts or use Objection's ios jailbreak disable wrapper.
Tracing Calls
frida-trace generates a tracer with zero scripting — you just name the class/selector patterns.
# Trace all NSURLSession methods
frida-trace -U -f com.example.app -m "*[*NSURLSession* *]"
# Trace a specific selector
frida-trace -U -f com.example.app -m "-[*MyAPI *]"
# Trace C functions too
frida-trace -U -f com.example.app -i "strlen"
# Simulator: drop -U
frida-trace -f com.example.app -m "*[*NSURLSession* *]"
Each traced method produces a JS file in __handlers__/ that you can edit live to add logging — useful for capturing arguments mid-run.
SSL Pinning Bypass (quick)
# Objection one-liner (see the Objection page)
objection -g com.example.app explore
# then: ios sslpinning disable
Or with a Frida script from the community, e.g. frida-ios-hook/RNCryptor or SSL Kill Switch 2 on jailbroken devices. On a non-jailbroken device you must inject a gadget into the IPA (see the Objection page).
Frida with the Gadget (non-jailbroken)
For stock devices, embed FridaGadget.dylib in the IPA and launch via idevicedebug:
# Extract IPA, drop gadget into Payload/App.app/
# Add FridaGadget to the app's load commands / use optool, then:
codesign -f -s - --deep Payload/App.app
# Rebuild the IPA and install
ideviceinstaller -i patched.ipa
# Then attach on the host
frida -U -f com.example.app
Gotchas
- Frida's
-fspawn flag does not work for all apps on newer iOS; attach to a running process instead. - The gadget approach requires a decrypted IPA for App Store apps (use
frida-ios-dumpon a jailbroken device). - Frida 16+ is the current series; older scripts referencing
Interceptor.attachwith different arg offsets will need updating. - Keep
frida-serverandfrida-toolsversions roughly in sync.