I am hooking a certain function in Frida which uses the code:
this.carrier.getId()
However, at this point in time this.carrier has not been set yet, which causes the app to crash.
So I am thinking of manually setting this member in the current function in the class. So that carrier will exist by the time the code takes place.
The problem is that I encounter a problem by doing that.
So far this is what I got:
Java.perform(function () {
var SignUpActivity = Java.use('com.app.features.authentication.SignUpActivity');
SignUpActivity.validatePhoneNumber.implementation = function() {
var Carrier = Java.use("com.app.Carrier");
this.carrier = Carrier.$new();
console.log(this.carrier) // This prints "[object Object]"
console.log(this.carrier.setId) // This prints "undefined"
this.carrier.setId(123); // crashes
};
});
Code of carrier:
package com.app;
import android.os.Parcel;
import android.os.Parcelable;
public class Carrier implements Parcelable {
private int id;
private String name;
private String officeTerminalAddress;
public Carrier() {
}
protected Carrier(Parcel parcel) {
this.id = parcel.readInt();
this.name = parcel.readString();
this.officeTerminalAddress = parcel.readString();
}
public int getId() {
return this.id;
}
public void setId(int i) {
this.id = i;
}
}
Looks like the common problem in Frida that the way to access fields is different in Frida.
Frida uses JavaScript code so it can't handle non-JavaScript objects directly. Therefore it wraps "native" objects (Android Java objects in this case) in JavaScript objects.
If you now call in Frida this.carrier
you are getting the Frida JavaScript wrapper, not the Java Carrier instance you are aiming.
Of course the Frida JavaScript wrapper does not has the methods you try to call, therefore this.carrier.setId(123);
will always fail.
To access a field you always have to call .value
on it to get the actual value:
So if you want this.carrier
you have to use this.carrier.value
.
In case there is a name collision with a method of the same name Frida by default assigns the name to the method. If you want to access the field instead add an underscore an the beginning of the field name.
If there would exist a method named carrier
you could access the field this way: this._carrier.value
This is also described on the Frida pages, e.g. here:
Note we use
this.m.value = 0
instead ofthis.m = 0
to set the field’s value. If there is also a method in this class called m, we need to usethis._m.value = 0
to set the value of field m. In general, when looking at the properties of objects it will be necessary to use.value
to access the values those fields refer to.
But in your case you can simplify everything by just using a local variable:
Java.perform(function () {
var SignUpActivity = Java.use('com.app.features.authentication.SignUpActivity');
SignUpActivity.validatePhoneNumber.implementation = function() {
const Carrier = Java.use("com.app.Carrier");
const c = Carrier.$new();
c.setId(123);
this._carrier.value = c;
};
});