转载:看雪论坛 堂前燕 :https://bbs.pediy.com/thread-252319.htm
apk 和 Python脚本 链接:https://pan.baidu.com/s/1KX1fY16NgaYB1FnCrpu0lQ 提取码:t38k
上次记录了下xposed hook java层的学习,这次记录下frida
例子是在上次写的apk上稍加改动,添加几个简单的native方法;
MainActivity
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button bt=(Button)findViewById(R.id.bt1);bt.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {HookGoal h=new HookGoal(0);h.editnum(1);Log.i("jni str",h.strtest("abcdefg"));DiyClass[] array={new DiyClass(1),new DiyClass(2)};Log.i("jni array","jni调用前 参数数组 成员0: "+array[0].getData()+" 成员1: "+array[1].getData());DiyClass[] myarray=h.arraytest(array);Log.i("jni array","jni调用后 返回新数组 成员0: "+myarray[0].getData()+" 成员1: "+myarray[1].getData());h.show();TextView t=(TextView)findViewById(R.id.sample_text);//t.setText("ooo");t.setText(h.sayhello());//Log.i("jni ","");Toast.makeText(MainActivity.this,"HOOKGOAL",Toast.LENGTH_LONG).show();}});}
}
类文件
abstract class person {public int age = 0;public void eat(String food) {}
}public class HookGoal {static {System.loadLibrary("native-lib");}private static String TAG = "HookGoal:";private int hookGoalNumber;public HookGoal(int number) {hookGoalNumber = number;Log.i(TAG, "HookGoal hookGoalNumber:" + hookGoalNumber);}public void func0() {Log.i(TAG, "welcome");}private void func1() {new person() {@Overridepublic void eat(String food) {Log.i(TAG, "eat " + food);}}.eat("apple");}private static void func2(String s) {Log.i(TAG, "func2 " + s);}private void func3(DiyClass[] arry) {for (int i = 0; i < arry.length; i++)Log.i(TAG, "DiyClass[" + i + "].getData:" + arry[i].getData());}private class InnerClass {private int innerNumber;public InnerClass(String s) {innerNumber = 0;Log.i(TAG, "InnerClass 构造函数 " + s);Log.i(TAG, "InnerClass innerNumber:" + innerNumber);}private void innerFunc(String s) {Log.i(TAG, "InnerClass innerFunc " + s);}}public native String sayhello();public native String strtest(String s);public native DiyClass[] arraytest(DiyClass[] array);public native void editnum(int n);public void show() {Log.i(TAG,"hookGoalNumber:"+hookGoalNumber);func1();func2("私有静态方法");DiyClass[] arry = {new DiyClass(0), new DiyClass(0), new DiyClass(0)};func3(arry);InnerClass inner = new InnerClass("私有内部类");inner.innerFunc("内部类方法调用");}}public class DiyClass{private int data;public DiyClass(int data){this.data=data;}public int getData() {return data;}public void setData(int data) {this.data = data;}
}
native方法,动态注册
int add(int a,int b){return a+b;
}static jstring say(JNIEnv *env, jobject) {LOGI("native 函数say()返回字符串my jni hhh");string hello = "my jni hhh";return env->NewStringUTF(hello.c_str());
}
static jstring mystr(JNIEnv *env, jobject,jstring s) {char buf[256];env->GetStringUTFRegion(s,0,env->GetStringLength(s),buf);LOGI("GetStringUTFRegion 截取jstring保存到本地buf中:%s",buf);const char* ptr_c=env->GetStringUTFChars(s,NULL);LOGI("GetStringUTFChars 返回const char* 类型:%s",ptr_c);env->ReleaseStringUTFChars(s,ptr_c);const jchar *wc=env->GetStringChars(s, NULL);LOGI("GetStringChars 返回const jchar* 类型");env->ReleaseStringChars(s,wc);jstring js=env->NewStringUTF(buf);
/* jstring NewStringUTF(const char* bytes) 返回jstring类型访问java.lang.String对应的JNI类型jstring时,不能像访问基本数据类型一样直接使用,因为它在Java是一个引用类型,所以在本地代码中只能通过GetStringUTFChars这样的JNI函数来访问字符串的内容*/LOGI("NewStringUTF(buf) 返回jstring类型:%s",env->GetStringUTFChars(js,NULL));return env->NewString(wc,env->GetStringLength(s));
}
static void edit(JNIEnv *env, jobject obj,jint n) {jint x=add(n,n);LOGI("edit()内调用了add(),原参数:%d",n);jclass clazz=env->GetObjectClass(obj);jfieldID numberid=env->GetFieldID(clazz,"hookGoalNumber","I");env->SetIntField(obj,numberid,x);LOGI("edit()内设置hookGoalNumber字段为:%d",x);}
static jobjectArray myarray(JNIEnv *env, jobject obj,jobjectArray array){jclass diyclass=env->FindClass("com/example/goal/DiyClass");jmethodID initid=env->GetMethodID(diyclass,"<init>","(I)V");jmethodID getdataid=env->GetMethodID(diyclass,"getData","()I");jobject a=env->GetObjectArrayElement(array,0);jobject a1=env->GetObjectArrayElement(array,1);jint d=env->CallIntMethod(a,getdataid);jint d1=env->CallIntMethod(a1,getdataid);jobject diy=env->NewObject(diyclass,initid,d);jobject diy2=env->NewObject(diyclass,initid,d1);jobjectArray myarray=env->NewObjectArray(2,diyclass,0);env->SetObjectArrayElement(myarray,0,diy2);env->SetObjectArrayElement(myarray,1,diy);LOGI("myarray()使用array参数,返回交换元素位置的新数组");return myarray;
// return env->NewObjectArray(2,diyclass,diy2);}static const char *className = "com/example/goal/HookGoal";static JNINativeMethod gJni_Methods_table[] = {{"editnum", "(I)V", (void*)edit},{"sayhello", "()Ljava/lang/String;",(void*)say},{"strtest", "(Ljava/lang/String;)Ljava/lang/String;",(void*)mystr},{"arraytest","([Lcom/example/goal/DiyClass;)[Lcom/example/goal/DiyClass;",(void*)myarray}};static int jniRegisterNativeMethods(JNIEnv* env, const char* className,const JNINativeMethod* gMethods, int numMethods)
{jclass clazz;clazz = (env)->FindClass( className);if (clazz == NULL) {return -1;}int result = 0;if ((env)->RegisterNatives(clazz, gJni_Methods_table, numMethods) < 0) {result = -1;}(env)->DeleteLocalRef(clazz);return result;
}jint JNI_OnLoad(JavaVM* vm, void* reserved){JNIEnv* env = NULL;jint result = -1;if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {return result;}jniRegisterNativeMethods(env, className, gJni_Methods_table, sizeof(gJni_Methods_table) / sizeof(JNINativeMethod));return JNI_VERSION_1_4;
}
开始 frida hook
首先是 java 层 hook
setImmediate(function () {Java.perform(function () {console.log("start");//java层hookvar hookgoal = Java.use("com.example.goal.HookGoal");var clazz = Java.use("java.lang.Class");var obj = Java.use("java.lang.Object");var Exception = Java.use("java.lang.Exception");var str = Java.use("java.lang.String");//hook 构造方法hookgoal.$init.overload("int").implementation = function (number) {send("HookGoal构造函数的参数number:" + number);send("HookGoal构造函数的参数修改为666");return this.$init(666);};//hook 静态变量TAGvar reflectField = Java.cast(hookgoal.class, clazz).getDeclaredField("TAG");reflectField.setAccessible(true);reflectField.set("java.lang.String", "frida hooking");send("修改HookGoal的静态变量TAG为:frida hooking");//实例化对象way1var newhg = hookgoal.$new(0);send("new HookGoal instance newhg: " + newhg);// 实例化对象way2var newhg1 = hookgoal.$new.overload("int").call(hookgoal, 0);send("new HookGoal instance newhg1: " + newhg1);//hook匿名内部类,修改参数var nminner = Java.use("com.example.goal.HookGoal$1");nminner.eat.overload("java.lang.String").implementation = function (s) {var arg = arguments[0];send("eat参数获取 way1:" + arg);send("eat参数获取 way2:" + s);//修改参数return this.eat("is hooking");};var diy = Java.use("com.example.goal.DiyClass");hookgoal.func2.implementation = function (s) {//func2为静态方法var arg = arguments[0];send("func2()参数获取:" + s);//调用成员方法func0()在静态方法内只能通过创建的实例访问newhg.func0();send("func2()内调用func0() 通过创建实例newhg调用");newhg1.func0();send("func2()内调用func0() 通过创建实例newhg1调用");//修改实例的hookGoalNumber值,前面hook构造函数时已经将值改为666//修改字段值 通过反射得到字段,//var num1 = Java.cast(newhg1.getClass(), clazz).getDeclaredField("hookGoalNumber");var num1 = Java.cast(hookgoal.class, clazz).getDeclaredField("hookGoalNumber");num1.setAccessible(true);send("实例newhg1的hookGoalNumber:" + num1.get(newhg1));num1.setInt(newhg1, 777);send("修改实例newhg1的hookGoalNumber:" + num1.get(newhg1));send("实例newhg的hookGoalNumber:" + num1.get(newhg));// 反射调用方法var func = hookgoal.class.getDeclaredMethod("func0", null);send("func0:" + func);//var funcs = hookgoal.class.getDeclaredMethods();//for(var i=0;i<funcs.length;i++)// send(""+i+" "+funcs[i]);//invoke(instance,args)调用成员方法func.invoke(newhg1, null);send("func2()内调用func0() way2 通过反射调用");//调用DiyClass内的getData()var d = diy.$new(666);var x = d.getData();send("func2()内调用DiyClass下的getData() 通过创建实例d调用 返回:" + x);//修改func2的参数return this.func2("is hooking");};//修改func3参数hookgoal.func3.implementation = function (array) {//在成员方法func3内调用func0()this.func0();send("func3()内调用func0() way2 成员方法中直接调用其他成员方法");//修改数组参数send("func3参数:" + array);var a = Java.array("com.example.goal.DiyClass", [diy.$new(111), diy.$new(222), diy.$new(333)]);send("func3参数修改:" + a);return this.func3(a);};var inner = Java.use("com.example.goal.HookGoal$InnerClass");//hook内部类inner.$init.overload("com.example.goal.HookGoal", "java.lang.String").implementation = function (clas, arg) {send("innerClass构造函数的参数:" + arg);return this.$init(clas, "frida is hooking");};//hook 内部类方法inner.innerFunc.implementation = function (s) {send("frida hook 前innerFunc()的参数:" + arguments[0]);var num = inner.class.getDeclaredField("innerNumber");num.setAccessible(true);//内部类成员方法中修改成员属性,way1 通过this.xxx.value 访问、修改send("通过this.innerNumber.value获取值:" + this.innerNumber.value);this.innerNumber.value = 1;send("通过this.innerNumber.value设置值后:" + this.innerNumber.value);//way2 先通过反射得到字段,send("反射方式 innerNumber修改前:" + num.get(this));num.setInt(this, 2);send("反射方式 innerNumber修改后:" + num.get(this));return this.innerFunc("frida is hooking");};
native 层 hook
//so层hook//导出函数//var exports = Module.enumerateExportsSync("libnative-lib.so");//for(var i=0;i<exports.length;i++){// send("name:"+exports[i].name+" address:"+exports[i].address);// }//遍历模块找基址Process.enumerateModules({onMatch: function (exp) {if (exp.name == 'libnative-lib.so') {send('enumerateModules find');send(exp.name + "|" + exp.base + "|" + exp.size + "|" + exp.path);send(exp);return 'stop';}},onComplete: function () {send('enumerateModules stop');}});//通过模块名直接查找基址var soAddr = Module.findBaseAddress("libnative-lib.so");send("soAddr:" + soAddr);// hook导出函数 通过函数名send("findExportByName add():" + Module.findExportByName("libnative-lib.so", "_Z3addii"));//send("findExportByName edit():"+Module.findExportByName("libnative-lib.so", "_ZL4editP7_JNIEnvP8_jobjecti"))// Interceptor.attach(Module.findExportByName("xxx.so", "xxxx"), {// onEnter: function (args) {// send("open(" + Memory.readCString(args[0]) + "," + args[1] + ")");// },// onLeave: function (retval) {//// }// });//say(JNIEnv *env, jobject)//edit(JNIEnv *env, jobject,int)//mystr(JNIEnv *env, jobject,jstring s)//myarray(JNIEnv *env, jobject obj, jobjectArray array)// arm64-v8a 下地址//var fadd = 0xED7C;//var fsay=0xF12C;//var fedit=0xF04C;//var fmystr=0xF328;//var fmyarray=0xF4DC;//下面为x86模拟器中地址偏移 arm真机下thumb指令下地址+1var fadd = 0x8AD0;var fsay = 0x8FA0;var fedit = 0x8E70;var fmystr = 0x9200;var fmyarray = 0x9420;//armeabi-v7a//var fadd = 0x839C;var faddptr = new NativePointer(soAddr).add(fadd);//得到内存地址send("函数add() faddptr:" + faddptr);//调用add(5,6)var funadd = new NativeFunction(faddptr, "int", ['int', 'int']);var t = funadd(5, 6);send("调用native 方法fun():" + t);Interceptor.attach(faddptr, {onEnter: function (args) {send("onEnter add()");x = args[0];y = args[1];args[0] = ptr(x * 2);args[1] = ptr(y * 2);send("hook add()修改参数为原来的两倍 args[0]:" + args[0].toInt32() + " args[1]:" + args[1].toInt32());},onLeave: function (retval) {send("onLeave add()");//retval.replace(678);//send("add()修改返回值为:"+retval.toInt32())}});var fsayptr = new NativePointer(soAddr).add(fsay);Interceptor.attach(fsayptr, {onEnter: function (args) {send("onEnter say()");},onLeave: function (retval) {send("onLeave say()");//jstring类型无法直接输出显示,可以类型转换到java.lang.Stringvar s = Java.cast(retval, str);send("say() 原返回值:" + s);//调用env下的方法,构造jstring类型var env = Java.vm.getEnv();var jstring = env.newStringUtf("frida hook native");retval.replace(ptr(jstring));send("修改say()返回值:" + Java.cast(jstring, str));}});var feditptr = new NativePointer(soAddr).add(fedit);Interceptor.attach(feditptr, {onEnter: function (args) {send("onEnter edit()");send("edit() env:" + args[0] + " jobject:" + args[1] + " jint:" + args[2].toInt32());//参数修改使用new NativePointer(s) 简写ptr(s)args[2] = ptr(4);send("hook edit() 修改后的参数jint:" + args[2]);},onLeave: function (retval) {send("onLeave edit()");}});var fmystrptr = new NativePointer(soAddr).add(fmystr);send("fmystrptr:" + fmystrptr);Interceptor.attach(fmystrptr, {onEnter: function (args) {send("onEnter mystr()");send("mystr() env:" + args[0] + " jobject:" + args[1] + " jstring:" + args[2]);var s = Java.cast(args[2], str);send("mystr() jstring参数:" + s);//send("mystr:"+Memory.readUtf16String(args[2],7));//send("mystr:"+Memory.readUtf8String(args[2],7));},onLeave: function (retval) {send("onLeave mystr()");var env = Java.vm.getEnv();var jstring = env.newStringUtf("frida hook native");send("修改返回值jstring:" + jstring);retval.replace(ptr(jstring));}});// Java.choose("com.example.goal.DiyClass",{// onMatch:function(instance){// send("DiyClass instance:"+instance);// },// onComplete:function(){//// }//// });var fmyarrayptr = ptr(soAddr).add(fmyarray);//var fmyarrayptr = new NativePointer(soAddr).add(fmyarray);send("fmyarrayptr:" + fmyarrayptr);//var argptr;Interceptor.attach(fmyarrayptr, {onEnter: function (args) {send("onEnter myarray()");send("mystr() env:" + args[0] + " jobject:" + args[1] + " jobjectArray:" + args[2]);send("jobjectArray参数:" + args[2].toString());//可以在onEnter中通过this.xxx保存变量 在onLeave中通过this.xxx读取this.argptr = args[2]//jstring 不同于wchar_t* (jchar*) 与 char*//send("mystr:"+Memory.readUtf16String(args[2],7));//send("mystr:"+Memory.readUtf8String(args[2],7));},onLeave: function (retval) {send("onLeave myarray()");send("argptr:" + this.argptr);var env = Java.vm.getEnv();var cla = env.findClass("com/example/goal/DiyClass");send("clazz:" + cla);var initid = env.getMethodId(cla, "<init>", "(I)V");send("initid:" + initid);var setid = env.getMethodId(cla, "setData", "(I)V");send("setid:" + setid);var getid = env.getMethodId(cla, "getData", "()I");send("getid:" + getid);//frida 中env 方法参考frida-java/lib/env.js 本人能力有限,有些方法确实搞不懂//调用env中的allocObject()方法创建对象,未初始化,var obj1 = env.allocObject(cla);send("obj1:" + obj1);var obj2 = env.allocObject(cla);send("obj2:" + obj2);var rtarray = env.newObjectArray(2, cla, ptr(0));send("env.newObjectArray:" + rtarray);//获取DiyClass类中public void setData(int data)方法var nvmethod = env.nonvirtualVaMethod("void", ["int"]);//NativeType CallNonvirtual<type>Method(JNIEnv *env, jobject obj,jclass clazz, jmethodID methodID, ...);//设置obj1中data值nvmethod(env, obj1, cla, setid, 11);//设置obj2中data值nvmethod(env, obj2, cla, setid, 22);send("env.nonvirtualVaMethod(JNIEnv,jobject,jclass,jmethodid,args):" + nvmethod);//设置数组中的元素env.setObjectArrayElement(rtarray, 0, obj1);env.setObjectArrayElement(rtarray, 1, obj2);send("env.newObjectArray:" + rtarray);send("原retval:" + retval);retval.replace(ptr(rtarray));send("修改后retval:" + retval);// //堆中分配空间// var memo=Memory.alloc(4);// //写入数据// Memory.writeInt(memo,0x40302010);// // 读取数据// console.log(hexdump(memo, {// offset: 0,// length: 64,// header: true,// ansi: true// }));}});});
});
写好的 js 放到 python 执行
import frida, sysdef on_message(message, data):if message['type'] == 'send':print("[*] {0}".format(message['payload']))else:print(message)jscode = """
<js代码放到这里>"""
# 启动时hook //在测试时出现了问题
# devices=frida.get_usb_device()
# pid=devices.spawn(['com.example.goal']) #以挂起方式创建进程 真机报错frida.PermissionDeniedError: unable to access process
#找到原因了,我的是Android8.0 使用了Magisk,默认开启了Magisk Hide选项与zygote64冲突。
#解决方法:Magisk -->设置-->Magisk下 去掉勾选Magisk Hide #模拟器报错Failed to spawn: the connection is closed
# session=devices.attach(pid)
# devices.resume(pid) #创建完脚本, 恢复进程运行
# script=session.create_script(jscode)# 命令行frida -U -f com.example.goal --no-pause -l <hook.js># 运行中hook
process = frida.get_usb_device().attach('com.example.goal')
script = process.create_script(jscode)
script.on('message', on_message)
print('[*] Running test')
script.load()
sys.stdin.read()
也可以使用 frida 命令行 打开 .js (打印使用 console.log() )
frida -U <进程名或pid> -l <js文件>
代码中涉及到的一些点大部分给出了注释,当然你只能这里看到一丢丢的 frida 方法的使用,更多的方法还要请参考官方文档、源代码···
例如native层会用到大量frida JavaScript API 的Memory 操作,
frida中的env方法与jni开发中的方法并不完全相同,请参考源码frida-java/lib/env.js,
代码中涉及到的地址偏移请根据实际情况修改
hook 前 log 输出
4513-4513/com.example.goal I/frida hooking: HookGoal hookGoalNumber:0
4513-4513/com.example.goal I/jni test: edit()内调用了add(),原参数:1
4513-4513/com.example.goal I/jni test: edit()内设置hookGoalNumber字段为:2
4513-4513/com.example.goal I/jni test: GetStringUTFRegion 截取jstring保存到本地buf中:abcdefg
4513-4513/com.example.goal I/jni test: GetStringUTFChars 返回const char* 类型:abcdefg
4513-4513/com.example.goal I/jni test: GetStringChars 返回const jchar* 类型
4513-4513/com.example.goal I/jni str: abcdefg
4513-4513/com.example.goal I/jni array: jni调用前 参数数组 成员0: 1 成员1: 2
4513-4513/com.example.goal I/jni test: myarray()使用array参数,返回交换元素位置的新数组
4513-4513/com.example.goal I/jni array: jni调用后 返回新数组 成员0: 2 成员1: 1
4513-4513/com.example.goal I/frida hooking: hookGoalNumber:2
4513-4513/com.example.goal I/frida hooking: eat apple
4513-4513/com.example.goal I/frida hooking: func2 私有静态方法
4513-4513/com.example.goal I/frida hooking: DiyClass[0].getData:0
4513-4513/com.example.goal I/frida hooking: DiyClass[1].getData:0
4513-4513/com.example.goal I/frida hooking: DiyClass[2].getData:0
4513-4513/com.example.goal I/frida hooking: InnerClass 构造函数 私有内部类
4513-4513/com.example.goal I/frida hooking: InnerClass innerNumber:0
4513-4513/com.example.goal I/frida hooking: InnerClass innerFunc 内部类方法调用
4513-4513/com.example.goal I/jni test: native 函数say()返回字符串my jni hhh
hoo k后 log 输出
4513-4513/com.example.goal I/frida hooking: HookGoal hookGoalNumber:666
4513-4513/com.example.goal I/jni test: edit()内调用了add(),原参数:4
4513-4513/com.example.goal I/jni test: edit()内设置hookGoalNumber字段为:16
4513-4513/com.example.goal I/jni test: GetStringUTFRegion 截取jstring保存到本地buf中:abcdefg
4513-4513/com.example.goal I/jni test: GetStringUTFChars 返回const char* 类型:abcdefg
4513-4513/com.example.goal I/jni test: GetStringChars 返回const jchar* 类型
4513-4513/com.example.goal I/jni str: frida hook native
4513-4513/com.example.goal I/jni array: jni调用前 参数数组 成员0: 1 成员1: 2
4513-4513/com.example.goal I/jni test: myarray()使用array参数,返回交换元素位置的新数组
4513-4513/com.example.goal I/jni array: jni调用后 返回新数组 成员0: 11 成员1: 22
4513-4513/com.example.goal I/frida hooking: hookGoalNumber:16
4513-4513/com.example.goal I/frida hooking: eat is hooking
4513-4513/com.example.goal I/frida hooking: welcome
4513-4513/com.example.goal I/frida hooking: welcome
4513-4513/com.example.goal I/frida hooking: welcome
4513-4513/com.example.goal I/frida hooking: func2 is hooking
4513-4513/com.example.goal I/frida hooking: welcome
4513-4513/com.example.goal I/frida hooking: DiyClass[0].getData:111
4513-4513/com.example.goal I/frida hooking: DiyClass[1].getData:222
4513-4513/com.example.goal I/frida hooking: DiyClass[2].getData:333
4513-4513/com.example.goal I/frida hooking: InnerClass 构造函数 frida is hooking
4513-4513/com.example.goal I/frida hooking: InnerClass innerNumber:0
4513-4513/com.example.goal I/frida hooking: InnerClass innerFunc frida is hooking
4513-4513/com.example.goal I/jni test: native 函数say()返回字符串my jni hhh
hook 脚本的输出
[*] Running test
start
[*] 修改HookGoal的静态变量TAG为:frida hooking
[*] HookGoal构造函数的参数number:0
[*] HookGoal构造函数的参数修改为666
[*] new HookGoal instance newhg: com.example.goal.HookGoal@4a854cb4
[*] HookGoal构造函数的参数number:0
[*] HookGoal构造函数的参数修改为666
[*] new HookGoal instance newhg1: com.example.goal.HookGoal@4a854f70
[*] enumerateModules find
[*] libnative-lib.so|0x7d0b0000|221184|/data/app-lib/com.example.goal-1/libnative-lib.so
[*] {'name': 'libnative-lib.so', 'base': '0x7d0b0000', 'size': 221184, 'path': '/data/app-lib/com.example.goal-1/libnative-lib.so'}
[*] enumerateModules stop
[*] soAddr:0x7d0b0000
[*] 函数add() nativeptr:0x7d0b8ad0
[*] 调用native 方法fun():11
[*] findExportByName add():0x7d0b8ad0
[*] fmystrptr:0x7d0b9200
[*] fmyarrayptr:0x7d0b9420
[*] HookGoal构造函数的参数number:0
[*] HookGoal构造函数的参数修改为666
[*] onEnter edit()
[*] edit() env:0xb83a6e50 jobject:0xf7c00025 jint:1
[*] hook edit() 修改后的参数jint:0x4
[*] onEnter add()
[*] hook add()修改参数为原来的两倍 args[0]:8 args[1]:8
[*] onLeave add()
[*] onLeave edit()
[*] onEnter mystr()
[*] mystr() env:0xb83a6e50 jobject:0xf7d00025 jstring:0x3d300029
[*] mystr() jstring参数:abcdefg
[*] onLeave mystr()
[*] 修改返回值jstring:0xc5b00035
[*] onEnter myarray()
[*] mystr() env:0xb83a6e50 jobject:0xf8000025 jobjectArray:0x3d600029
[*] jobjectArray参数:0x3d600029
[*] onLeave myarray()
[*] argptr:0x3d600029
[*] clazz:0x26800045
[*] initid:0x881d1ea8
[*] setid:0x881d1f20
[*] getid:0x881d1ee8
[*] obj1:0x1e000049
[*] obj2:0x1e00004d
[*] env.newObjectArray:0x1dc00051
[*] env.nonvirtualVaMethod(JNIEnv,jobject,jclass,jmethodid,args):0xb4d88bb0
[*] env.newObjectArray:0x1dc00051
[*] 原retval:0x2f900041
[*] 修改后retval:0x1dc00051
[*] eat参数获取 way1:apple
[*] eat参数获取 way2:apple
[*] func2()参数获取:私有静态方法
[*] func2()内调用func0() 通过创建实例newhg调用
[*] func2()内调用func0() 通过创建实例newhg1调用
[*] 实例newhg1的hookGoalNumber:666
[*] 修改实例newhg1的hookGoalNumber:777
[*] 实例newhg的hookGoalNumber:666
[*] func0:public void com.example.goal.HookGoal.func0()
[*] func2()内调用func0() way2 通过反射调用
[*] func2()内调用DiyClass下的getData() 通过创建实例d调用 返回:666
[*] func3()内调用func0() way2 成员方法中直接调用其他成员方法
[*] func3参数:com.example.goal.DiyClass@4a8596b4,com.example.goal.DiyClass@4a8596bc,com.example.goal.DiyClass@4a8596c4
[*] func3参数修改:com.example.goal.DiyClass@4a859a08,com.example.goal.DiyClass@4a859a78,com.example.goal.DiyClass@4a859ae8
[*] innerClass构造函数的参数:私有内部类
[*] frida hook 前innerFunc()的参数:内部类方法调用
[*] 通过this.innerNumber.value获取值:0
[*] 通过this.innerNumber.value设置值后:1
[*] 反射方式 innerNumber修改前:1
[*] 反射方式 innerNumber修改后:2
[*] onEnter say()
[*] onLeave say()
[*] say() 原返回值:my jni hhh
[*] 修改say()返回值:frida hook native
frida功能十分强大,在这里我作为初学者简单的记录了下学习经历,当然这仅仅是一些常规操作,是基础,日后的学习应该是在实战中,实践出真知。
合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下
我在学习的过程之中也遇到了各种各样的坑,困惑过,苦恼过。解决问题绝对是一种很棒的学习方式,
希望各位能够提出自己的问题,大家一起交流,共同成长!
同时文中难免会有错误,欢迎各位坛友指出,不胜感激!
(打好基础,改日实战一番!)