x32x01
ADMINISTRATOR
- by x32x01 ||
Frida is a dynamic instrumentation toolkit that is used by researchers to perform android hooking (intercepting IPC and modifying it to make a function perform the desired function). Frida uses javascript to perform hooking since Android’s native code and javascript both run on JIT compilation techniques, it can intercept its inter-process communication, add the code specified in a script and completely change the function’s implementation. Some of its use cases in real life are:
Table of Content
Root Detection Bypass
Application developers sometimes hard code a detection logic per which an application successfully detects the presence of various SU binaries and stops execution of the application. One such example is demonstrated below. As you can see the app gives a popup of restriction and exits as soon user hits ok.
Now, we’ll try and remove this restriction using Frida. First, it is recommended you install a Frida server in the device
we’ll launch the server onto the device.
Now, we’ll first install frida with the command:
After a successful install, we can see all the running process in the device on which frida server is running by the command:
As you can see that our app is running here. We have to bypass root detection here. We can either try and reverse engineer the jar files, create our own javascript code and bypass root detection or we can rely on code already created by a large community of developers on codeshare frida repo.
Weblink to the site is: https://codeshare.frida.re/browse Here, we can see an antiroot script by dzonerzy. We’ll run it with the following command:
Now, press y to trust the project.
Now, all that’s left to do is press “%resume” to resume the execution with our hooked code!
And just like that, we can see that root detection has been successfully bypassed!
Hooking different methods in java
Now, a class might have multiple methods and each of these methods have a specific purpose. For example, the onCreate() method defines the implementation of activity as soon as the activity is created (or launched). So, what is, we can hook this function and change the behaviour of the activity when it is created. For the demonstration purpose, I’ll just print some custom text in my console as soon as the activity is called but the possibilities are limitless. Typically you won’t have access to the source code, hence, what we’ll do is extract the apk first and then decompile it to view source code. To pull the apk we’ll first know it’s the path and then pull it.
Now, as explained in part 1 of this series. we’ll decompile it using apktool and then use dex2jar to convert it in jar format, and finally use jd-gui to view the decompiled source code like below. Here is the MainActivity class decompiled.
Here we see the following things:
Explanation:
To launch this script we type in the following command:
As you can see now, the hook is successfully installed, activity launches and our custom output is now displayed and the hook is successfully installed
Hooking a defined method: Unlike the onCreate method that is present in the native libraries, some methods are custom created. For example, if you inspect the code of diva, you’ll see a function startChallenge() that is launching challenges in the application. I’m not putting the code in here but you can refer to the decompiled code in the above step. Now, we’ll observe that startChallenge is launching activities present in the project. And since it is launching an activity, it has an “android.view.VIEW” argument passed in its code. Now in the code below, every time a user hits a button to start any challenge, we’ll just force him to call our hook and our defined output would be displayed (that is MainActivity.startChallenge() is now started). Needless to say, we can change this by any implementation we want.
To call this script, without having to input %resume this time, we can type in the command with –no-pause filter:
And sure enough, every time a button is pressed, our custom input is displayed.
Hooking exit() method: We can also tamper the exit method in android just like we tampered onCreate method. Here, I’m using a demonstration application that I custom coded (link here). It has a button that is performing an exit function. You can see a sample screenshot below:
Now, here we see the exit button. As the name states, on pressing it, application exits.
We create a hook down below that will stop the exit. Here, “java.lang.System” is the package that has exit function and so we’ll overload it using “sysexit.exit.overload().implementation.” Now, whenever a user clicks on exit, our send method will be called and exit will be stopped.
Let’s fire this script up and sure enough, we can see that the process is not terminated when the exit button is clicked. If it had been terminated frida must have thrown a process terminated error and closed the console.
Hooking return value: We have hooked methods till now, but a return variable can also be hooked and its output be tampered with. In article 3 of this series, I had already demonstrated this using Objection tool but today we’ll do this using Frida and our manual code. In the application that I custom coded which is mentioned above, there is a simple program to display output of 10 and 50. We’ll hook this return value and output 100. The code to do this is pretty straightforward:
Let’s first run the program without loading our hook. We can see that the program outputs 60 which is the correct answer.
Now, we’ll fire up our script and see what changes happen in the application now.
And sure enough, the output gets tampered and 100 is returned now!
SSLPinning Bypass
Frida is most commonly used to bypass SSLPinning in android so that researchers and pen testers can intercept its network calls and conduct a traffic analysis. For the demo of this attack, I downloaded an application named “Certificate Pinning Demo”. For the demonstration of this attack, you must have your burp suite configured with your device. Now, when I pin the client and send an HTTPS request, it throws an SSL error.
And sure enough, no communication is intercepted in burp suite as well.
Now, on the codeshare repository here, akabe1 has put a great script to perform SSLPinning bypass. We’ll use this script to perform the attack. Note that applications might have different code of pinning, so these codes need to be modified as and when required.
Type %resume once the script gets loaded.
And finally, when we now send a request to sslabs.com in pinned mode, we are able to get an HTTP 200 response code!
Surely, we are now able to intercept communication in burp suite as well.
Hooking in Python
Python coders can customize a whole fridascript to run in python environment using the python’s frida package and API. This would make performing multiple processes in hooks easier. Here, I’ll create a hook on startChallenge function as above.
Now, every time user clicks on any button to start the challenge, the execution stops and our custom output is printed instead.
We, run this script using the command below:
Let’s Play a Game!
All the examples demonstrated till now are very basic. There are advanced hooking techniques to perform various different functions whose references I’ll mention at the end. One such challenge I found was on 11×256’s blog. In example #1, we have to intercept the APK, see what’s happening behind the white screen, change its implementation and modify its behaviour. finally, we’ll check logcat to see if our hook worked and the sum of our custom defined integers is thrown or not.
Follow the link here and download the sample apk.
First, after running the application in the emulator we saw just a plain white screen. That means something must probably be happening in the background.
We’ll use drozer to see activities here:
As you can see, my_activity is present. This means this is the activity responsible for the full white front screen.
Now, we’ll use objection to watch what this class is actually doing.
Here, observe that fun() is being called. This has two int parameters, so, presumably, these two integers are getting performed a mathematical operation on.
Now, we write a code in javascript:
This code does nothing but defines fun() function and specifies 2 and 5 as our own integers on which some mathematical function will be performed. but before that, the script also intercepts and displays the original call and obviously the original integers!
Let’s fire it up using frida:
As we can see, the original call had two integers namely, 50 and 30.
Let’s quickly check logcat and see what is happening in the background.
As we can see in the screenshot down below, a mathematical Sum of type Double is being repeatedly called. This is similar to the behaviour of the app we just installed that was calling a method called fun after every second. Hence, it is safe to conclude that fun() is adding two integers. Original numbers to be added were 50 and 30, which we not only intercepted and dumped but also changed to 2 and 5 and the sum of 2 and 5 is now being called as evident in logcat.
References
Hooking is a pentester’s best buddy and reverse engineer’s most handy tool. It has numerous applications and to write custom scripts to perform various functions like sniffing crypto APIs, decrypting AES etc, a tester needs to have complete knowledge of javascript, reverse engineering APKs and java. To get good at frida and hooking (dynamic instrumentation), I’ll mention the following references:
- Spy on Crypto APIs
- Modify function’s output
- Bypass AES encryption
- Bypass SSLPinning and Root detection
- Trace private application code
- Bypass various software sided locks (like applock)
Table of Content
- Root detection bypass
- Hooking different kinds of methods used in Java
- Native methods – onCreate, onStart etc.
- exit()
- user defined methods
- variable
- SSLPinning bypass
- Implementing hooking in python
- Playing a game!
Root Detection Bypass
Application developers sometimes hard code a detection logic per which an application successfully detects the presence of various SU binaries and stops execution of the application. One such example is demonstrated below. As you can see the app gives a popup of restriction and exits as soon user hits ok.
we’ll launch the server onto the device.
Code:
adb connect 192.168.27.105
adb shell "/tmp/frida-server &"
Code:
pip install frida
pip install frida-tools
After a successful install, we can see all the running process in the device on which frida server is running by the command:
Code:
frida-ps -U
Weblink to the site is: https://codeshare.frida.re/browse
Code:
frida -U --codeshare dzonerzy/fridantiroot -f in.<package company>.<package name>
Now, press y to trust the project.
Now, a class might have multiple methods and each of these methods have a specific purpose. For example, the onCreate() method defines the implementation of activity as soon as the activity is created (or launched). So, what is, we can hook this function and change the behaviour of the activity when it is created. For the demonstration purpose, I’ll just print some custom text in my console as soon as the activity is called but the possibilities are limitless. Typically you won’t have access to the source code, hence, what we’ll do is extract the apk first and then decompile it to view source code. To pull the apk we’ll first know it’s the path and then pull it.
Code:
adb shell pm path jakhar.aseem.diva
adb pull /data/app/jakhar.aseem.diva-dxAm4hRxYY4VgIq2X5zU6w==/base.apk
- We can see that onCreate has a Bundle parameter
- It’s creating a view of the main page
Code:
console.log("Script loaded!");
Java.perform(function(){
var mainapp = Java.use("jakhar.aseem.diva.MainActivity");
mainapp.onCreate.implementation = function(){
console.log("My script called!");
var ret = this.onCreate.overload("android.os.Bundle").call(this);
};
send("Hooks installed");
});
Explanation:
- Any implementation of the hook is put inside perform(function(){ //<code>
- The activity we want to hook (main activity) is put inside use(“jakhar.aseem.diva.MainActivity”), and assign a variable to it. Here, mainapp
- Now, onCreate.implementation sets a definition of the function.
- Here, we can insert any code we cant to run in the onCreate method. I just inserted log function to output “My script called!” every time onCreate is called.
- New variable ret calls this newly formed implementation function. overload method is used to add this code to the existing piece of code. Here, “os.Bundle” is input as a parameter since in the original function a bundle object is used.
- Finally, the call method is used to call the current method using “this” pointer.
- send() function outputs the text in double-quotes on the current frida command line.
Code:
frida -U -l mainactivityhook.js -f jakhar.aseem.diva
As you can see now, the hook is successfully installed, activity launches and our custom output is now displayed and the hook is successfully installed
Code:
console.log("Hooked startChallenge() function");
Java.perform(function(){
var newstart = Java.use("jakhar.aseem.diva.MainActivity");
newstart.startChallenge.overload("android.view.View").implementation = function(v){
//enter any implementation of startChallenge you want
//for demo I'm just sending an alert on frida console
send("MainActivity.startChallenge() is now started");
var ret = this.startChallenge.overload("android.view.View").call(this);
};
});
Code:
frida -U -l main_startchallenge.js -f jakhar.aseem.diva
And sure enough, every time a button is pressed, our custom input is displayed.
Code:
console.log("Hooking on exit function");
Java.perform(function(){
var sysexit = Java.use("java.lang.System");
sysexit.exit.overload("int").implementation = function(var_0) {
send("I've stopped java.lang.System.exit() now!");
};
});
Code:
frida -U -l avoidexit.js -f com.example.harshitrajpal --no-pause
Code:
console.log(“Hook for implementation of method”);
Java.perform(function myFunc() {
var myClass = Java.use(“com.example.harshitrajpal.MainActivity”);
myClass.returnValue.implementation = function(){
//we will manipulate the return value here
var ret = 100;
return ret;
}
});
Code:
frida -U -l retValueHook.js -f com.example.harshitrajpal --no-pause
Frida is most commonly used to bypass SSLPinning in android so that researchers and pen testers can intercept its network calls and conduct a traffic analysis. For the demo of this attack, I downloaded an application named “Certificate Pinning Demo”. For the demonstration of this attack, you must have your burp suite configured with your device. Now, when I pin the client and send an HTTPS request, it throws an SSL error.
Code:
frida -U --codeshare akabe1/frida-multiple-unpinning -f com.osfg.certificatepinning
Type %resume once the script gets loaded.
Python coders can customize a whole fridascript to run in python environment using the python’s frida package and API. This would make performing multiple processes in hooks easier. Here, I’ll create a hook on startChallenge function as above.
Code:
jscode = """
console.log("Hooked startChallenge() function");
Java.perform(function(){
var newstart = Java.use("jakhar.aseem.diva.MainActivity");
newstart.startChallenge.overload("android.view.View").implementation = function(v){
//enter any implementation of startChallenge you want
//for demo I'm just sending an alert on console
send("MainActivity.startChallenge() is now started");
console.log("You clicked...but in vain!");
var ret = this.startChallenge.overload("android.view.View").call(this);
};
});
"""
import frida,sys
process = frida.get_usb_device().attach("jakhar.aseem.diva")
script = process.create_script(jscode)
print("*** Running Hook on startChallenge() now!")
script.load()
sys.stdin.read()
Now, every time user clicks on any button to start the challenge, the execution stops and our custom output is printed instead.
Code:
python3 startChallenge.py
All the examples demonstrated till now are very basic. There are advanced hooking techniques to perform various different functions whose references I’ll mention at the end. One such challenge I found was on 11×256’s blog. In example #1, we have to intercept the APK, see what’s happening behind the white screen, change its implementation and modify its behaviour. finally, we’ll check logcat to see if our hook worked and the sum of our custom defined integers is thrown or not.
Follow the link here and download the sample apk.
Code:
run app.activity.info -a com.example.a11x256.frida_test
As you can see, my_activity is present. This means this is the activity responsible for the full white front screen.
Code:
objection --gadget com.example.a11x256.frida_test explore
android hooking watch class com.example.a11x256.frida_test --dump-args --dump-return --dump-backtrace
Here, observe that fun() is being called. This has two int parameters, so, presumably, these two integers are getting performed a mathematical operation on.
Now, we write a code in javascript:
Code:
console.log("Script loaded successfully ");
Java.perform(function x() { //Silently fails without the sleep from the python code
console.log("Inside java perform function");
//get a wrapper for our class
var my_class = Java.use("com.example.a11x256.frida_test.my_activity");
//replace the original implmenetation of the function `fun` with our custom function
my_class.fun.implementation = function (x, y) {
//print the original arguments
console.log("original call: fun(" + x + ", " + y + ")");
//call the original implementation of `fun` with args (2,5)
var ret_value = this.fun(2, 5);
return ret_value;
}
});
This code does nothing but defines fun() function and specifies 2 and 5 as our own integers on which some mathematical function will be performed. but before that, the script also intercepts and displays the original call and obviously the original integers!
Code:
frida -U -l 11x256.js -f com.example.a11x256.frida_test
As we can see, the original call had two integers namely, 50 and 30.
Code:
adb logcat | grep frida_test
As we can see in the screenshot down below, a mathematical Sum of type Double is being repeatedly called. This is similar to the behaviour of the app we just installed that was calling a method called fun after every second. Hence, it is safe to conclude that fun() is adding two integers. Original numbers to be added were 50 and 30, which we not only intercepted and dumped but also changed to 2 and 5 and the sum of 2 and 5 is now being called as evident in logcat.
Hooking is a pentester’s best buddy and reverse engineer’s most handy tool. It has numerous applications and to write custom scripts to perform various functions like sniffing crypto APIs, decrypting AES etc, a tester needs to have complete knowledge of javascript, reverse engineering APKs and java. To get good at frida and hooking (dynamic instrumentation), I’ll mention the following references: