该篇文章主要介绍当我们碰到参数或者返回值是一个对象时,如何通过frida反射调用该对象的方法(methods)与获取该对象的字段(fields)
添加测试frida反射调用的demo app
写一个测试类,其中包含字段(fields)int类型的count、String类型的plainText
及多个简单方法。其中display方法参数为ParametersTest对象,
在文中,我们要hook display方法并hook它的参数ParametersTest对象反射调用ParametersTest对象的所有方法及打印parametersTest的所有字段
public class ParametersTest {
private final int count = 523;//字段count
private final String plainText = "this is a test";//字段plainText
public int multiply(int val1,int val2){
return val1 * val2;
}
public byte multiply(byte val1,byte val2){
return (byte)(val1 * val2);
}
public short multiply(short val1,short val2){
return (short)(val1 * val2);
}
public long multiply(long val1,long val2){
return val1 * val2;
}
public float multiply(float val1,float val2){
return val1 * val2;
}
public double multiply(double val1,double val2){
return val1 * val2;
}
public String addMethod(String str1,String str2){
return str1 + str2;
}
public void addMethod(int[] initArray){
for(int i = 0; i < initArray.length;i++){
initArray[i] = initArray[i] + 1;
}
}
public void addMethod(byte[] byteArray){
for(int i = 0; i < byteArray.length;i++){
byteArray[i] = (byte)(byteArray[i] + 1);
}
}
public void addMethod(long[] longArray){
for(int i = 0; i < longArray.length; i++){
longArray[i] = longArray[i] + 1;
}
}
public void addMethod(float[] floatArray){
for(int i = 0; i < floatArray.length; i++){
floatArray[i] = floatArray[i] + 1;
}
}
public void addMethod(double[] doubleArray){
for(int i = 0; i < doubleArray.length; i++){
doubleArray[i] = doubleArray[i] + 1;
}
}
public void addMethod(String[] strArray){
String result = "";
for(int i = 0; i < strArray.length; i++){
result = result + strArray[i];
}
}
//display方法参数为ParametersTest对象
public void display(ParametersTest parametersTest){
int[] intArray = {1,2,3,4,5};
parametersTest.addMethod(intArray);
byte[] byteArray = {0x10,0x11,0x12,0x13};
parametersTest.addMethod(byteArray);
long[] longArray = {0x1,0x2,0x3,0x4};
parametersTest.addMethod(longArray);
String[] strArray = {"abcde","1222CDedd","12daer","cder"};
parametersTest.addMethod(strArray);
float[] floatArray = {0x1,0x2,0x3,0x4};
parametersTest.addMethod(floatArray);
double[] doubleArray = {0x1,0x2,0x3,0x4};
parametersTest.addMethod(doubleArray);
String str1 = "acerwe";
String str2 = "werwed";
parametersTest.addMethod(str1,str2);
int intVal1 = 3;
int intVal2 = 4;
int retInt = parametersTest.multiply(intVal1,intVal2);
byte byteVal1 = 0x1;
byte byteVal2 = 0x2;
byte retByte = parametersTest.multiply(byteVal1,byteVal2);
long longVal1 = 0x3;
long longVal2 = 0x4;
long retLong = parametersTest.multiply(longVal1,longVal2);
float floatVal1 = 0x3;
float floatVal2 = 0x4;
float retFloat = parametersTest.multiply(floatVal1,floatVal2);
short shortVal1 = 0x3;
short shortVal2 = 0x4;
short retShort = parametersTest.multiply(shortVal1,shortVal2);
double doubleVal1 = 0x3;
double doubleVal2 = 0x4;
double retDouble = parametersTest.multiply(doubleVal1,doubleVal2);
}
}
frida反射调用打印字段(fields)类型、名称、值
//hook display方法
parametersTestClass.display.overload("com.example.parameterstest.ParametersTest").implementation = function (val1) {
getReflectFields(val1);//打印所有字段(fields)类型、名称、值
getReflectMethod(val1)//hook ParametersTest对象的所有方法
this.display(val1);//调用display方法
}
function getReflectFields(val1) {
var clazz = Java.use("java.lang.Class");
var parametersTest = Java.cast(val1.getClass(),clazz);
//getDeclaredFields()获取所有字段
var fields = parametersTest.getDeclaredFields();
fields.forEach(function (field) {//依次打印字段的类型、名称、值
send("field type is: " + (field.getType()));
send("field name is: " + (field.getName()));
send("field value is: " + field.get(val1));
})
}
结果如下:
frida反射调用类中的方法
function getReflectMethod(val1) {
try{
var clazz = Java.use("java.lang.Class");
var parametersTest = Java.cast(val1.getClass(),clazz);
//getDeclaredMethods()获取所有方法
var methods = parametersTest.getDeclaredMethods();
methods.forEach(function (method) {
var methodName = method.getName();
var val1Class = val1.getClass();
var val1ClassName = Java.use(val1Class.getName());
var overloads = val1ClassName[methodName].overloads;
overloads.forEach(function (overload) {
var proto = "(";
overload.argumentTypes.forEach(function (type) {
proto += type.className + ", ";
});
if(proto.length > 1){
proto = proto.substr(0 ,proto.length - 2);
}
proto += ")";
overload.implementation = function () {
var args = [];
for(var j = 0; j < arguments.length; j++){
for(var i in arguments[j]){
var value = String(arguments[j][i]);
send(val1ClassName + "." + methodName + " and arguments value is: " + value);
}
args[j] = arguments[j] + "";
}
//打印方法参数
send(val1ClassName + "." + methodName + " and args is: " + args);
//调用方法
var retval = this[methodName].apply(this,arguments);
//打印方法返回值
send(methodName + " return value is: " + retval);
return retval;//返回方法返回值
}
})
})
}catch(e){
send("'" + val1 + "' hook fail: " + e);
}
}
结果如下