主要学习内容:
Java.choose(className, callback)
在内存中扫描 Java 堆,枚举 Java 对象(className)实例。比如可以使用 java.lang.String 扫描内存中的字符串。callbacks 提供两个参数:onMatch(instance) 和 onComplete,分别是找到匹配对象和扫描完成调用。
代码清单 MainActivity.java
package com.roysue.demo02;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
while(true){
try{
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
fun(50, 30);
Log.d("rOysue.String", fun("LoWeRcAsE Me!!!!!!!"));
}
}
void fun(int x, int y){
Log.d("rOysue.sum", String.valueOf(x+y));
}
String fun(String x){
return x.toLowerCase();
}
void secret(){
Log.d("rOysue.secret", "this is secret func");
}
static void staticSecret(){
Log.d("rOysue.secret", "this is static secret func");
}
}
原书代码 3.js
function main(){
console.log("Script loaded successfully")
Java.perform(function(){
console.log("Inside java perform function")
var MainActivity = Java.use('com.roysue.demo02.MainActivity')
MainActivity.staticSecret()
Java.choose('com.roysue.demo02.MainActivity',{
onMatch: function (instance) {
console.log("instance found:", instance);
instance.secret()
},
onComplete: function () {
console.log("search Complete");
}
})
})
}
setImmediate(main)
可修改代码 3.js
function main(){
console.log("Script loaded successfully")
Java.perform(function x(){
console.log("Inside java perform function")
var MainActivity = Java.use('com.roysue.demo02.MainActivity')
MainActivity.fun.overload('java.lang.String').implementation = function (str) {
//打印参数
console.log("original call : str:" + str);
//修改结果
var ret_value = "sakura";
return ret_value;
};
Java.choose('com.roysue.demo02.MainActivity',{
onMatch: function (x) {
console.log("find instance :" + x);
console.log("result of secret func:" + x.secret());
},
onComplete: function () {
console.log("end");
}
});
});
}
setImmediate(main)
在代码清单脚本中,可以发现静态的staticSecret()函数和Hook使用的方式大同小异,都是Java.use这个API去获取MainActivity类,在获取对应的类对象后通过“.”连接符连接staticSecret方法名,最终以和Java中一样的方式直接调用静态方法staticSecret()函数;动态方法secret需要先通过Java.choose这个API从内存中获取相应的类的实例对象,然后才能通过这个实例对象去调用动态的secret函数。