Frida Scripting Basics for Pentesters | Part 1

Frida is an open-source dynamic instrumentation toolkit used for debugging, reverse engineering, and security testing of software applications. It allows developers and security researchers to inject scripts and manipulate the behavior of applications at runtime. Frida supports various platforms, including Android, iOS, Windows, macOS, and Linux.


In this blogpost we are going to learn about basic of frida scripting using JavaScript programming language which uses JavaScript APIs as documented by Frida Docs. These APIs allow us to interact with the internals of the target process, manipulate memory, and hook into functions.

For this I am going to use a simple application 📲 which I developed for the demonstration purpose.

📁Download the App

⬇️ Following template will be used throughout the blog to write the fridascripts for the intended actions.

if(Java.available){

	Java.perform(function(){
		try{
		//Do Something
		console.log("[+] In the Java.perform");
		
		}
		catch(error){
		
		console.log("[-] An Error Occured");
		
		}
	});
}
else{

console.log("[-] Java is not available");
}

➡️ Java.available is a property that Frida provides to check whether a Java Virtual Machine (VM) is available in the current process(Target application). It returns a boolean(true/false) value indicating whether the current process has a Java VM loaded.

➡️ Java.perform

When you’re dealing with Frida scripts, the JavaScript code you write is executed in the context of the Frida runtime, which is separate from the Java runtime where the target application is running. The Java.perform function is used to switch the context of your script to the Java VM of the target process.

Once you’re inside the Java VM context using Java.perform, you can access and interact with Java classes, methods, and objects as if you were writing Java code. This is crucial for hooking and modifying the behavior of Java methods within the target application.


📱 Inside the application fridalearn.apk we have two buttons. One to generate a random string and one to generate a random number.

targets

Lets look at the MainActivity.java file for the the application.

package com.example.fridalearn;

import  android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    private TextView textView2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = findViewById(R.id.textview);
        textView2 = findViewById(R.id.textView3);

				//PART 1

        Button generateButton = findViewById(R.id.generateButton);
        generateButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Instantiate the RandomString class
                RandomString randomStringGenerator = new RandomString();

                // Generate a random string
                String randomString = randomStringGenerator.generateRandomString(10);

                // Display the random string in the TextView
                textView.setText(randomString);
            }
        });

				
				//PART 2

        Button generateButton1 = findViewById(R.id.button);
        generateButton1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Instantiate the RandomNumberGenerator class
                RandomNumberGenerator randomNumberGenerator = new RandomNumberGenerator();
                
				// Generate a random number
				int randomNumber = randomNumberGenerator.generate7DigitRandomNumber();

                // Convert the int to String before setting it as text
                String randomNumberString = String.valueOf(randomNumber);

                // Display the random string in the TextView
                textView2.setText(randomNumberString);
            }
        });

    }
}

👉 We will first look at the Random Number Generation part of the code. (PART 2)

The second part of the code is where we have a onclick listener for “Generate Random Number” button which will:

  • Instantiate the RandomNumberGenerator class
  • Generate a random number with the help of generate7DigitRandomNumber method of RandomNumberGenerator class
  • Convert the Int value returned from method generate7DigitRandomNumber to String before setting it as text
  • Display the random string in the TextView

The generate7DigitRandomNumber method looks like this ⬇️

targets

📢The generate7DigitRandomNumber simply generate random numbers with SecureRandom class between 1000000 to 9999999


😎 Now let’s bring in Frida to hook the RandomNumberGenerator class present in the application and change the implementation to display our own number instead of the random number.

Here is the Frida Script to do that:

if (Java.available) { 
    Java.perform(function () {
        try {

            console.log("[+] In the Java.perform");

            // Target the class

            var targetClass = Java.use('com.example.fridalearn.RandomNumberGenerator'); 

            // Change the implementation

            targetClass.generate7DigitRandomNumber.implementation = function () {
                console.log("[+] Inside the implementation");

                var number = 1337;

                return number;
            };
        } catch (error) {
            console.log("[-] An Error Occurred");
            console.error(error);
        }
    });
} else {
    console.log("[-] Java is not available");
}

📍Here we are doing the following thing:

  • Check if the target application has java runtime available with Java.available
  • Then we set up a context that will let our fridascript understand and modify Java objects, classes, and methods with Java.perform
  • Java.use is used to interact with and modify the java classes and their methods within the target application. Java.use(‘com.example.fridalearn.RandomNumberGenerator’); is telling the fridascript that we want to work with the application class com.example.fridalearn.RandomNumberGenerator
  • Once hooked into the class using Java.use we then change the implementation of the method generate7DigitRandomNumber to replace the original implementation of a method with custom logic. In our custom implementation we have declared variable number with value 1337 and then simply returned it.

👻 Lets run the fridascript and see what happens…

targets

✅ We were successfully able to change the implementation of the method generate7DigitRandomNumber with the help fridascript.


Now let’s look at the first part (PART 1) of the code in MainActivity.java. Here we have a onclick listener for “Generate Random String” button which will:

  • Instantiate the RandomString class
  • Generate a random string with the help of generateRandomString method of RandomString class
  • Display the random string in the TextView

The generateRandomString method looks like this ⬇️

targets

So basically the generateRandomString method of RandomString class will generate the a string of 10 random characters.

The class generateRandomString has two methods with same name but takes different types of parameters as an arguments. 🤔

😀 We need to make use of overload function.

 The overload function is used when hooking into methods that have multiple 
 implementations (overloaded methods). 
 It allows you to specify which version of the method you want to hook based 
 on the method's parameter types.

Since methods can take different types of parameters (e.g., int, string, boolean), the overload function helps us to choose which version of generateRandomString we want to hook into. In this case we have to hook the method which deals with method that takes (int) type parameter.

Here is the Fridascript to inject JavaScript and change the implementation of generateRandomString to generate our own string:

if (Java.available) { 
    Java.perform(function () {
        try {
            console.log("[+] In the Java.perform");

            // Target the class

            var targetClass = Java.use('com.example.fridalearn.RandomString'); 

            // Change the implementation

            targetClass.generateRandomString.overload('int').implementation = function () {
                console.log("[+] Inside the implementation");

                var message = 'i_am_batman';

                return message;
            };
        } catch (error) {
            console.log("[-] An Error Occurred");
            console.error(error);
        }
    });
} else {
    console.log("[-] Java is not available");
}

✅Once we ran the fridascript, we are able to successfully change the implementation of generateRandomString as shown below.

targets

✌️ That’s it for this blog. Hope you have learned something 🙂

You can always check more about Frida usage by visiting their official document: https://frida.re/docs/android/

Resources


Shubham Golam
Shubham Golam
Security Consultant