iOS
Recipes
-
Inject script into process on a USB device via REPL
Injecting a Frida instrumentation script on an iOS device connected via USB can be achieved through the following command. Here the -n switch (default option) specifies the process name to attach to (the associated app must be running before executing this command), and the -U switch specifies that a USB device is being targeted (therefore, this option is used for all iOS related commands).
$ frida -U -n Twitter -l demo1.js
-
List all running processes names and PIDs on a USB device
The following command lists all the running processes from an iOS device in a tabular format with PID and name columns. Remember, the -U specifies that a USB device is being queried.
$ frida-ps -U
-
List all installed apps on a USB device
The following command lists all installed apps on a USB device in a tabular format with PID, name and identifier columns.
$ frida-ps -Uai
-
List all running apps on a USB device
The following command lists all the running apps on a USB device in a tabular format with PID, name and identifier columns.
$ frida-ps -Ua
-
List all attached devices
The following command lists all the available Frida devices, including the ones attached via USB. Processes on these devices can be instrumented by Frida.
$ frida-ls-devices
-
Tracing native APIs
The following command can be used to trace a native API in a specific process. Function names can be specified using wildcard characters (as shown below), which can be particularly useful while exploring or discovering user-defined functions within the process.
$ frida-trace -U Twitter -i "*URL*"
-
Tracing Objective-C APIs
The following command can be used to trace an Objective-C API in a specific process. Notice the difference in switch, in this case it’s -m instead of -i. Objective-C APIs names, the Class names as well as the method types (class method or instance method) can all be specified using wildcard characters (as shown below). This can be particularly useful while exploring or discovering user-defined methods within a process.
$ frida-trace -U Twitter -m "-[NSURL* *HTTP*]"
-
Backtracing an Objective-C method call
The following command can be used to generate a backtrace for an Objective-C method call in a specific process.
Tip: Add the following code to the onEnter event-handler in the auto-generated JS of the desired API
log('\tBacktrace:\n\t' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress) .join('\n\t'));
-
Writing data to file
If you want to write some data to a file, you should
send()
it from the injected script and receive it in your Frida-based application, where you then write it to a file.Tip: The data that you
send()
should be JSON serializable.agent.js:
``` const data = { foo: 'bar' }; send(data); ```
app.py:
``` import frida def on_message(message, data): print(message['payload']) ```
-
Calling a native function
const address = Module.getExportByName('libsqlite3.dylib', 'sqlite3_sql'); const sql = new NativeFunction(address, 'char', ['pointer']); sql(statement);
Explanation here.
Data Structures
Tip: If things don’t seem to be working as expected you may be interacting with the wrong data type - run the following command to determine the actual type of the object that you’re dealing with!
console.log('Type of args[2] -> ' + new ObjC.Object(args[2]).$className)
-
Converting NSData to String
const data = new ObjC.Object(args[2]); data.bytes().readUtf8String(data.length());
Tip: 2nd argument (number of bytes) is not required if the string data is null-terminated.
-
Converting NSData to Binary Data
const data = new ObjC.Object(args[2]); data.bytes().readByteArray(data.length());
-
Iterating an NSArray
const array = new ObjC.Object(args[2]); /* * Be sure to use valueOf() as NSUInteger is a Number in * 32-bit processes, and UInt64 in 64-bit processes. This * coerces it into a Number in the latter case. */ const count = array.count().valueOf(); for (let i = 0; i !== count; i++) { const element = array.objectAtIndex_(i); }
-
Iterating an NSDictionary
const dict = new ObjC.Object(args[2]); const enumerator = dict.keyEnumerator(); let key; while ((key = enumerator.nextObject()) !== null) { const value = dict.objectForKey_(key); }
-
Unarchiving an NSKeyedArchiver
const parsedValue = ObjC.classes.NSKeyedUnarchiver.unarchiveObjectWithData_(value);
-
Reading a struct
If args[0] is a pointer to a struct, and let’s say you want to read the uint32 at offset 4, you can do it as shown below:
args[0].add(4).readU32();
Objective-C examples
Displaying an alert box on iOS 7
Displaying an alert box on iOS >= 8
This is an implementation of the following code.
Printing an NSURL argument
The following code shows how you can intercept a call to [UIApplication openURL:] and display the NSURL that is passed.