基本の書き方
Java.perform(function () {
var MainActivity = Java.use('com.example.MainActivity');
// メソッドをオーバーライド
MainActivity.methodName.overload('java.lang.String', 'int', 'boolean').implementation = function (arg1, arg2, arg3) {
console.log('method 呼び出し');
};
});
.overload(...)でフックすると、引数違いの同名のメソッドがあっても、特定の1つだけを指定でき、この引数のパターンのメソッドだけをフックせよ、という命令になる。
以下書き方は、それよりゆるい書き方。
["methodName"]で書くと、オーバーロードがあるかはFridaが判断するので、
もしメソッドがオーバーバーロードしている場合、どれがフック対象なのかわからなくなる。
ただし、メソッド名が、$を含むラムダ式など特殊な場合、上記書き方だとエラーになる場合があるらしい。
Jadxなどで見た場合、ラムダ用のメソッド名は、通常被らないようにユニークな名前($1, $2...)が振られる。そのため、この書き方でもFridaが迷うことなく実行できる。
Java.perform(function () {
// フックしたい対象のクラスのパスを指定する
var cls = Java.use("com.example.MainActivity");
// 対象のメソッド名を指定する
// 引数名は自由で良いが、順番と数は合わせる必要があり
cls["onCreateHoge"].implementation = function (arg1, arg2, arg3, arg4) {
console.log("対象のメソッドをフックしました。");
// 横取りした処理を元に戻す
return cls["onCreateHoge"](arg1, arg2, arg3, arg4);
}
});
EditTextを扱いたい
android.widget.EditText などの部品を扱いたい場合、
EditTextのインスタンス作成には、Contextが必要になる。
Contextとは「アプリの現在の状態」や「リソースへのアクセス権」を持つオブジェクト。
しかし、我々はFridaで外からスクリプトを注入しているので、そのままではアプリが内部で持っているContextオブジェクトにアクセスできない。
それを取得するために、Androidシステムの内部クラスで、アプリのメインプロセスを管理している中心部のandroid.app.ActivityThreadを取得する必要がある。
EditTextのインスタンス生成から実施しているコードは下記。
Java.perform(function () {
var MainActivity = Java.use("com.example.MainActivity");
var EditText = Java.use("android.widget.EditText");
var ActivityThread = Java.use("android.app.ActivityThread");
var JavaString = Java.use("java.lang.String");
var BufferType = Java.use("android.widget.TextView$BufferType");
MainActivity["method"].implementation = function (arg1) {
var context = ActivityThread.currentApplication().getApplicationContext();
var myEditText = EditText.$new(context);
var text = JavaString.$new("new text");
myEditText.setText.overload('java.lang.CharSequence', 'android.widget.TextView$BufferType').call(myEditText, text, BufferType.NORMAL.value);
return MainActivity["method"](myEditText);
}
});
そもそも引数がEditText型なので、いちいちインスタスを新たに作成しなくてもいいのでは?というコード
Java.perform(function () {
var MainActivity = Java.use("com.example.MainActivity");
MainActivity["method"].implementation = function (arg1) {
arg1.setText.overload('java.lang.CharSequence', 'android.widget.TextView$BufferType')
.call(arg1, "new text");
return MainActivity["method"](arg1);
}
});