How to use Frida in iOS devices: command line, Frida Gadget and scripts (JavaScript and Python).
Frida
It’s a dynamic code instrumentation toolkit. It lets you inject snippets of JavaScript or your own library into native apps on Windows, macOS, GNU/Linux, iOS, Android, and QNX. Frida also provides you with some simple tools built on top of the Frida API. These can be used as-is, tweaked to your needs, or serve as examples of how to use the API.
Commands (via USB)
Show all the applications of the device
frida-ps -Uai
Starts the Frida Gadget
frida -U APP_NAME
Script injection
frida -U -l SCRIPT.js APP_NAME
Tracing native APIs (partial method name with wildcards allowed)
frida-trace -U APP_NAME -i "METHOD_NAME"$
Tracing Objective-C metods (partial method and class name with wildcards allowed)
$ frida-trace -U APP_NAME -m "-[CLASS_NAME METHOD_NAME]"
Execute Objective-C commands from terminal
frida -q -U APP_NAME -e "COMMAND"
JavaScript API
Get instance object
var instance = ObjC.chooseSync(ObjC.classes.CLASS_NAME)[0];
Call method
instance.METHOD_NAME();
Dump the entire view hierarchy of a window
w = ObjC.classes.UIWindow.keyWindow()
desc = w.recursiveDescription().toString()
Application installation path
ObjC.classes[CLASS_NAME].$moduleName;
Class methods
ObjC.classes[CLASS_NAME].$ownMethods;
Mapping each instance variable name to its current value
ObjC.classes[CLASS_NAME].$ivars;
Javascript
Call method (inside onEnter or onLeave)
var obj = new ObjC.Object(arg[0]);
obj.METHOD_NAME();
Print class and method
this._className = ObjC.Object(args[0]).toString();
this._methodName = ObjC.selectorAsString(args[1]);
console.log('Detected call to:');
console.log(' ' + this._className + ' --> ' + this._methodName);
Modify return value
returnValue.replace(ptr(NEW_VALUE));
Scripts
The following scripts can be found in my Github Trelis24
start_frida.py
Python script that given a script and a app bundle, it starts the app, inject de script and resume the execution.
find_classes.js
Search for classes
- If no strings are specified in “search_class” array, the script will print all the classes.
- If one or more strings are specified in “search_class array”, the script will only print classes which contains the strings in their name.
find_methods.js
Search for methods
- If no strings are specified in “search_class” nor “search_method” arrays, the script will print the methods of all the classes (frida server might stop running if there are a lot of classes).
- If one or more strings are specified in “search_class array”, the script will print the methods of the classes which contains the strings in their name.
- If one or more strings are specified in “search_method” array, the script will print the classes which contains the strings in the name of one or more of their methods.
- If one or more strings are specified in “search_method” and “search_class” array, the script will print only the classes and methods that meet with the search criteria.
hooking.js
Hooks into methods
- Given one or more classes in “search_class”, it hooks into all their methods.
- Given one or more methods in “search_method”, it hooks into all methods of any classes that meet with the search criteria.
- Given a class and a method, it hooks into the method of this class.
- Neither class nor method full name is needed in order to hook. If a partial string is given, the script will hook into all the methods that have the string in their name.
replace.js
Replace methods return values
- Given an especific class, method and value it replaces the return value of the method.
- Method format: for example: “- isJailbroken:”
- Data must be in the same array position (classNmes, methodNames, returnValues). For example: [‘class1’,’class2’][‘method1’,’method2’][‘retvalue1’,’retvalue2’]
- If returnValues of a method is left empty, the method will be hooken but the script will not modify the return value.
PoC
In this section, I will use DVIA iOS application in order to show how can frida and my scripts be used. Specifically I will analise jailbreak detection test 1. The objective is to bypass the jailbreak detection control.
Commands
List applications. The ones with a PID are currently active:
With frida-trace, hooking into all methods whose name has the substring “jail”:
With frida-trace, hooking into all methods of the class JailbreakDetectionVC:
With frida-trace, hooking into an specific method an class:
In order to detect which methods are called, one way is to hook into all methods of a class. In the following image you can see how the view was loaded first and then the method “jailbreakTest1Tapped:” and “isJailbroken” are called:
Of course, in the device the following message is shown:
Scripts
Due to the jailbreak detection control only shows an alert text box and it does not terminate the application execution, I will execute the scripts via terminal. Otherwise, I would have used the python script in order to inject the scripts before the applications terminates.
Find classes
First of all, you should look for classes of your interest. In this example, I have looked for the string “jail” (find_classes.js):
var search_class = ['jail'];
The only class with the substring “jail” is “JailbreakDetectionVC”:
Find methods
An other way to find classes is to look into their methods. The only drawback is that depending of the string, a lot of results can be found. I have looked for the string “jail” in the methods (find_methods.js):
var search_class = [''];
var search_method = ['jail'];
The class “JailbreakDetectionVC” is in the list, however there are a lot more classes I am not interested in:
Now that I have detected the class, let’s print all its methods (find_methods.js):
var search_class = ['JailbreakDetectionVC'];
var search_method = [''];
There are a total of 7 methods:
Hooking
Now that I know the class, I can hook into the methods in order to understand how are they called (hooking.js):
var search_class = ['JailbreakDetectionVC'];
var search_method = [''];
...
onEnter:
...
//print_arguments(args);
In the code below, I have commented the line “print_arguments(args);”, which prints the arguments send into the methods, because it prints information not needed for this example.
After the script execution, it shows:
- Calls “jailbreakTest1Tapped:”
- Calls “isJailbroken”
- “isJailbroken” returns 0x1
- “jailbreakTest1Tapped:” returns 0x1035a9d10
I can deduce that “isJailbroken” might be de method which checks if the device is jailbroken due to it returns a “false”. However, if you want to be sure, static analysis can always be done. Check my post about bypassing Jailbreak with IDA.
Replace
Finally, I will try to replace the return value of “isJailbroken” so it always returns “false” (replace.js):
var classNames = ['JailbreakDetectionVC'];
var methodNames = ['- isJailbroken'];
var returnValues = ['0x0'];
The script hooks into the method. When isJailbroken returns the 0x1, frida intercepts it, changes the value to 0x0 and resume the execution:
After changing the return value from 0x1 to 0x0, the alert textbox is: