demo
frida-rpc通过调用已加载到内存中的函数,直接获取到结果:
import frida
rdev = frida.get_remote_device()
session = rdev.attach("大姨妈")
scr = """
rpc.exports = {
encrypt(j2, str){
var res;
Java.perform(function () {
var Crypt = Java.use("com.yoloho.libcore.util.Crypt");
res = Crypt.encrypt_data(j2, str);
});
return res;
}
}
"""
script = session.create_script(scr)
script.load()
sign = script.exports.encrypt(0,"38a6b024user/login8GGjp1eHdaK4e22QpCp0kfg==")
print(sign)
解释:在最外层使用rpc.exports导出了encrypt方法的定义,所以在script.exports里就能调用encrypt方法。
类型的处理
在执行frida-rpc时,会涉及到参数类型的处理和转换:
在python中给frida的JavaScript脚本传入参数时,一般有如下几种情况:
-
字符串/整型/浮点型等直接传递
import frida rdev = frida.get_remote_device() session = rdev.attach("大姨妈") scr = """ rpc.exports = { encrypt:function(v1,v2,v3,v4,v5){ console.log(v1,typeof v1); var v6 = parseInt(v5); console.log(v6,typeof v6); } } """ script = session.create_script(scr) script.load() # 调用 script.exports.encrypt(100, "wupeiqi", 19.2, -10, "-1")
-
列表/字典 直接传递
import frida rdev = frida.get_remote_device() session = rdev.attach("大姨妈") scr = """ rpc.exports = { encrypt:function(v1,v2){ console.log(v1,typeof v1, v1[0], v1[1]); console.log(v2,typeof v2, v2.name, v2.age); for(let key in v1){ console.log(key, v1[key] ) } for(let key in v2){ console.log(key, v2[key] ) } } } """ script = session.create_script(scr) script.load() script.exports.encrypt([11, 22, 33], {"name": 123, "age": 456})
-
字节,无法直接传递,需转换为列表
import frida rdev = frida.get_remote_device() session = rdev.attach("大姨妈") # com.yoloho.dayima scr = """ rpc.exports = { encrypt:function(v1){ console.log(v1, typeof v1); // 转换为java的字节数组 var bs = Java.array('byte', v1); console.log(JSON.stringify(bs)) } } """ script = session.create_script(scr) script.load() arg_bytes = "武沛齐".encode('utf-8') byte_list = [i for i in arg_bytes] script.exports.encrypt(byte_list)
-
某个类的对象,无法直接传递,可以将参数传入,然后在JavaScript调用frida api构造相关对象。
构造StringBuilder对象:
import frida
rdev = frida.get_remote_device()
session = rdev.attach("大姨妈")
scr = """
rpc.exports = {
encrypt:function(v1,v2){
const StringBuilder = Java.use('java.lang.StringBuilder');;
var obj = StringBuilder.$new();
obj.append(v1);
obj.append(v2);
var result = obj.toString();
console.log(result);
}
}
"""
script = session.create_script(scr)
script.load()
script.exports.encrypt("武沛齐", "666")
构造TreeMap对象:
import frida
rdev = frida.get_remote_device()
session = rdev.attach("大姨妈")
scr = """
rpc.exports = {
encrypt:function(v4){
var TreeMap = Java.use("java.util.TreeMap");
var v4_obj = TreeMap.$new();
for(let key in v4){
v4_obj.put(key,v4[key])
}
console.log(v4_obj)
console.log( v4_obj.get("name") )
console.log( v4_obj.get("age") )
var keyset = v4_obj.keySet();
var it = keyset.iterator();
while(it.hasNext()){
var keystr = it.next().toString();
var valuestr = v4_obj.get(keystr).toString();
console.log(keystr, valuestr);
}
}
}
"""
script = session.create_script(scr)
script.load()
script.exports.encrypt( {"name": "root", "age": "18"})
-
JavaScript相当于中介,用于连接python与java,可以完成一些数据的转换工作:
import frida rdev = frida.get_remote_device() session = rdev.attach("大姨妈") # com.yoloho.dayima scr = """ rpc.exports = { encrypt:function(bytesList){ // 先处理拼接好的数据(字节数组) var bArr = []; for(var i=0; i<bytesList.length; i+=2){ var item = (parseInt(bytesList[i],16) << 4) + parseInt(bytesList[i+1],16); bArr.push(item); } console.log(bArr); // 转换为java的字节数组 var bs = Java.array('byte', bArr); } } """ script = session.create_script(scr) script.load() arg_bytes = "wupeiqi".encode('utf-8') byte_list = [i for i in arg_bytes] script.exports.encrypt(byte_list)
【PS:Android 逆向进阶专栏地址:https://blog.csdn.net/dafan0/category_12682484.html】