Methods

Calling and using methods in Frida from Java

A method is a function that belongs to a class. In Java all the functions are attached to classes. We have two different kind of methods. The static ones, that can be called from a Class, and the non-static that can only be used from an instance of an object. If you need any more information about this, check the following link: https://www.geeksforgeeks.org/difference-between-static-and-non-static-method-in-java/.

The following code snippet shows how to call a static method:

var BasicTypes = Java.use("com.blog.testfrida.examples.BasicTypes");
BasicTypes.divideFloat(23,3);

To call a non-static method, we need to get first an object, so we need first to get the class reference in Frida:

var Person = Java.use("com.blog.testfrida.complexobjects.Person");

Then we create an object from that class. This special method is called constructor:

var personInstance = Person.$new();
personInstance.setId(1);

The following code shows how to send parameters to a method:

var String = Java.use("java.lang.String");
personInstance.setName(String.$new("Peter Griffin"));

Note that the parameters sent have to be javascript encapsulated objects

Overridden methods

In Java there is a possibility to generate overridden methods. Basically it means that two or more methods have the same name and different parameters (in quantity and type). As an example the following java code snippet is valid:

public static int multiply(int val1, int val2) {
return val1 * val2;
}
public static byte multiply(byte val1, byte val2) {
return (byte) (val1 * val2);
}

If you want to use an overridden method, the syntax does not change, as Frida solves the method by the argument types, so in the previous example the snippet code to call the multiply operation would be the following one:

var BasicTypes = Java.use("com.blog.testfrida.examples.BasicTypes");
console.log(BasicTypes.multiply(3,5));

The difference in the syntax comes when you want to modify a method with overridden options. The naive approach would be the following one:

var BasicTypes = Java.use("com.blog.testfrida.examples.BasicTypes");
console.log(BasicTypes.multiply(3,5));
BasicTypes.multiply.implementation = function (val1, val2) {
console.log("it works");
return val1 * val2;
}

If that code is executed, you'll see in the Frida cli console the following error:

Error: multiply(): has more than one overload, use .overload() to choose from:
.overload('long', 'long')
.overload('byte', 'byte')
.overload('short', 'short')
.overload('int', 'int')
.overload('float', 'float')
at throwOverloadError (frida/node_modules/frida-java-bridge/lib/class-factory.js:1054)
at frida/node_modules/frida-java-bridge/lib/class-factory.js:714
at /examples.js:164

which states that you should define which of the overridden methods you want to modify. As an example we'll modify the multiplication of two ints:

BasicTypes.multiply.overload('int','int').implementation = function (val1, val2) {
return val1 * val2;
}

Once you start to write Frida scripts, you will eventually find the need to modify or rewrite an overridden method. Not all the types of attributes are written as clear as the basic types. The following table can help to search for the types:

Java Type

Frida Type

int

int

byte

byte

short

short

long

long

float

float

double

double

char

char

<Object> (eg. String)

<package>.<Object> (eg. java.lang.String)

int[]

[I

byte[]

[B

short[]

[S

long[]

[J

float[]

[F

double[]

[D

char[]

[C

<Object>[]

[L<package>.<Object> (eg. [Ljava.lang.String)

Note that the object array starts with a "L" char.

If you wander where those weird data types comes from, they are inherited by the dex specification (Java code is transformed in dex format when the application is compiled). Primitives are represented by a single letter. They are actually stored in the dex file, in string form. They are specified in the dex-format.html document (https://android.googlesource.com/platform/dalvik/+/gingerbread/docs/dex-format.html in the AOSP repository).

As an example the following script lists all the overridden methods with their signatures:

function listOverritenMethods(className, func) {
var Class = Java.use(className);
var overloadedMethods = Class[func].overloads;
for (i in overloadedMethods) {
if (overloadedMethods[i].hasOwnProperty('argumentTypes')) {
var parameterString = "(";
for (j in overloadedMethods[i].argumentTypes) {
parameterString = parameterString + overloadedMethods[i].argumentTypes[j].className + ",";
}
parameterString = parameterString.slice(0,-1) + ")";
console.log(func + parameterString);
}
}
}
Java.perform(function () { listOverritenMethods("com.blog.testfrida.examples.BasicTypes","multiply") });