1 https://www.jianshu.com/p/ca8381d3e094
[TOC]
环境:windows + 网易mumu模拟器
Android Studio 与 adb 安装及连接 去官网下载 windows平台的Android Studio 安装之后打开Android Studio在设置中可以找到SDK的位置,其\platform-tools目录下就有adb.exe 只需要将该目录路径添加到PATH环境变量中就可以在任意目录中使用adb
网易mumu的固定端口为7555 有以下指令可能会用到
1 2 3 4 5 6 adb connect 127.0 .0 .1 :7555 adb shell adb shell getprop ro.product.cpu.abi adb forward tcp:27042 tcp:27042 adb forward tcp:27043 tcp:27043 frida-ps -U
Frida 与 Frida-server 直接使用下面的命令行指令安装frida
1 2 pip install frida-tools #安装frida frida --version # 查看frida的版本号
然后去GitHub frida release 里面查找对应版本、对应模拟器平台的frida-server 然后在该文件路径下打开新的终端
1 2 3 4 5 adb push frida-server /data/local/tmp/ adb shell cd /data/local/tmp/ chmod 777 frida-server ./frida-server
Java层被动Hook 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.example.demo1;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.widget.Button;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 ); } } void fun (int x,int y) { Log.d("Demo1.sum" ,String.valueOf(x+y)); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function main ( ) { Java.perform(function ( ) { console .log('hello world' ); var MainActivity = Java.use('com.example.demo1.MainActivity' ); MainActivity.fun.implementation = function (x,y ) { console .log('x => ' ,x,'y => ' ,y); var ret_value = this .fun(1 ,2 ); return ret_value; } }) } setTimeout (main);
Overload问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package com.example.demo1;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.widget.Button;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 ); fun("hello" ,"world" ); } } void fun (int x,int y) { Log.d("Demo1.sum" ,String.valueOf(x+y)); } void fun (String a,String b) { Log.d("Demo1.String" ,a+b); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function main ( ) { Java.perform(function ( ) { console .log('hello world' ); var MainActivity = Java.use('com.example.demo1.MainActivity' ); MainActivity.fun.overload('int' ,'int' ).implementation = function (x,y ) { console .log('x => ' ,x,'y => ' ,y); var ret_value = this .fun(1 ,2 ); return ret_value; } MainActivity.fun.overload('java.lang.String' ,'java.lang.String' ).implementation = function (x,y ) { console .log('a => ' ,x,'b => ' ,y); var ret_value = this .fun('world' ,' hello' ); return ret_value; } }) } setTimeout (main);
Java层主动调用 Java层的函数分为两种:类函数与实例方法。类函数使用关键字static修饰过的静态函数,可以直接通过类去调用;而实例方法则没有关键字static修饰,需要先创建实例再去调用。对于frida来说,对于类函数使用Java.use()找到类直接调用即可,对于实例方法使用Java.choose(),这个函数可以在Java的堆中寻找指定类的实例,调用也稍微复杂但都是一个框架了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package com.example.demo1;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.widget.Button;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 ); } } void fun (int x,int y) { Log.d("Demo1.sum" ,String.valueOf(x+y)); } void fun (String a,String b) { Log.d("Demo1.String" ,a+b); } void secret () { Log.d("Demo1.secret" ,"this is secret func" ); } static void staticsecret () { Log.d("Demo1.staticsecret" ,"this is static secret func" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function main ( ) { Java.perform(function ( ) { console .log('hello world' ) var MainActivity = Java.use('com.example.demo1.MainActivity' ) MainActivity.staticsecret() Java.choose('com.example.demo1.MainActivity' , { onMatch: function (instance ) { console .log('instance found' ,instance) instance.secret() }, onComplete: function ( ) { console .log('search Complete' ) } }) }) } setTimeout (main);
native层Hook 这里使用的函数也是HOOK windwos平台下exe可执行文件的函数:Interceptor.attach() HOOK模板如下
1 2 3 4 5 6 7 8 Interceptor.attach(addr,{ onEnter(args){ }, onLeave(retval){ } })
因为每次程序加载的地址都不一样,这里使用base+offset的方式定位要hook的函数
使用objection的功能
1 2 3 4 5 6 7 frida-ps -U objection -g [进程名] explore memory list modules memory list exports [模块名]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 package com.example.demo2;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.widget.TextView;import com.example.demo2.databinding.ActivityMainBinding;public class MainActivity extends AppCompatActivity { static { System.loadLibrary("demo2" ); } private ActivityMainBinding binding; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); TextView tv = binding.sampleText; tv.setText(stringFromJNI()); while (true ){ try { Thread.sleep(1000 ); } catch (InterruptedException e){ e.printStackTrace(); } Log.d("Demo2.JNI " ,stringFromJNI()); } } public native String stringFromJNI () ; }
1 2 3 4 5 6 7 8 9 10 #include <jni.h> #include <string> extern "C" JNIEXPORT jstring JNICALLJava_com_example_demo2_MainActivity_stringFromJNI( JNIEnv* env, jobject ) { std ::string hello = "Hello from C++" ; return env->NewStringUTF(hello.c_str()); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function main ( ) { var base = Module.findBaseAddress('libdemo2.so' ) console .log('libdemo2.so address is => ' ,base) var stringFromJNI = base.add(0x7fa404604140 - 0x7fa4045f5000 ) Interceptor.attach(stringFromJNI,{ onEnter: function (args ) { console .log('jnienc pointer => ' ,args[0 ]) console .log('jobj pointer => ' ,args[1 ]) }, onLeave: function (retval ) { console .log('retval is ' ,Java.vm.getEnv().getStringUtfChars(retval,null ).readCString()) console .log('============' ) } }) } setTimeout (main);