macOS Examples
Frida macOS Examples
Setup Requirements
Authorization
Frida uses task_for_pid to access target processes. Two authorization paths:
| Scenario | How authorization works |
|---|---|
| Running from Terminal.app (local user) | taskgate prompts for user authorization automatically |
| Running as root | No prompt needed |
| CI / headless environment | Sign the tool with com.apple.security.get-task-allow entitlement |
System Integrity Protection (SIP)
SIP may block Frida from attaching to system processes (e.g., Safari, system daemons).
- Check status:
csrutil status - To disable (requires booting into Recovery Mode):
csrutil disable - Reference: Apple HT204899
Note: Disabling SIP is only recommended in isolated development/testing environments.
Hook an Objective-C Method (Python + Frida Script)
Target: Any macOS app using NSApplication / NSApplicationDelegate
Demonstrates: ObjC.classes, Interceptor.attach, ObjC.Object wrapping, argument inspection
1import frida
2import sys
3
4def on_message(message, data):
5 print("[{}] => {}".format(message, data))
6
7def main(target_process):
8 session = frida.attach(target_process)
9
10 script = session.create_script("""
11 // Get the method object for -[NSApplicationDelegate applicationWillFinishLaunching:]
12 const appWillFinishLaunching = ObjC.classes.NSApplicationDelegate['- applicationWillFinishLaunching:'];
13
14 Interceptor.attach(appWillFinishLaunching.implementation, {
15 onEnter(args) {
16 // Objective-C method argument layout:
17 // args[0] = self (id)
18 // args[1] = _cmd (SEL)
19 // args[2] = first explicit parameter (NSNotification*)
20 const notification = new ObjC.Object(args[2]);
21
22 // Convert to JS string and log
23 const notificationStr = notification.absoluteString().toString();
24 console.log('Will finish launching with notification: ' + notificationStr);
25 }
26 });
27 """)
28 script.on("message", on_message)
29 script.load()
30 print("[!] Ctrl+D or Ctrl+Z to detach from instrumented program.\n\n")
31 sys.stdin.read()
32 session.detach()
33
34if __name__ == "__main__":
35 main("Safari")
ObjC argument convention (always applies):
| Index | Value |
|---|---|
args[0] | self — the receiver object (id) |
args[1] | _cmd — the selector (SEL) |
args[2] | First declared method parameter |
args[3] | Second declared method parameter |
| … | … |
Common macOS Frida Patterns
Enumerate Loaded ObjC Classes
1ObjC.enumerateLoadedClasses({
2 onMatch(name, owner) {
3 console.log(name + ' [' + owner + ']');
4 },
5 onComplete() {}
6});
Hook All Calls to -[NSObject description]
1const NSObject = ObjC.classes.NSObject;
2Interceptor.attach(NSObject['- description'].implementation, {
3 onLeave(retval) {
4 if (!retval.isNull()) {
5 console.log(new ObjC.Object(retval).toString());
6 }
7 }
8});
Intercept URL Requests (NSURLSession)
1const NSURLSession = ObjC.classes.NSURLSession;
2const dataTaskWithURL = NSURLSession['- dataTaskWithURL:completionHandler:'];
3
4Interceptor.attach(dataTaskWithURL.implementation, {
5 onEnter(args) {
6 const url = new ObjC.Object(args[2]);
7 console.log('[NSURLSession] dataTaskWithURL: ' + url.absoluteString().toString());
8 }
9});
Frida CLI Usage on macOS
1# List processes
2frida-ps
3
4# Attach to Safari by name
5frida -n Safari -l my_script.js
6
7# Spawn process and attach
8frida -f /Applications/Calculator.app/Contents/MacOS/Calculator -l my_script.js
9
10# Trace Objective-C messages matching a pattern
11frida-trace -n Safari -m '-[NSURL *]'
frida-trace -m flag syntax:
-m '-[ClassName methodName:]'— instance method-m '+[ClassName methodName:]'— class method-m '-[NSURL *]'— all instance methods on NSURL (wildcard)