macOS Examples

Frida macOS Examples

Setup Requirements

Authorization

Frida uses task_for_pid to access target processes. Two authorization paths:

ScenarioHow authorization works
Running from Terminal.app (local user)taskgate prompts for user authorization automatically
Running as rootNo prompt needed
CI / headless environmentSign 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).

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):

IndexValue
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: