android上的简单hook

cydia substrate目前也支持android了,cydia substrate是一个代码修改平台。它可以修改任何主进程的代码,官方网址:http://www.cydiasubstrate.com/

准备活动

在正式学习之前,需要做如下准备:
1. root你的手机
2. 下载官方的apk,并且安装进手机,点击运行,点击按钮,允许操作。
3. 更新sdk

更新sdk

打开sdkmanager


http://asdk.cydiasubstrate.com/addon.xml
添加完成之后,在extra下回多了一个选项,点击勾选下载
android上的简单hook_第1张图片
下载完成之后,会在sdk/extra目录下生成我们需要的文件:
android上的简单hook_第2张图片

API介绍

在正式开始之前,我们先来学习下cydia中重要的api。

  • MS.hookClassLoad
//该方法实现在指定的类被加载的时候发出通知
void hookClassLoad(String name, MS.ClassLoadHook hook);
参数 描述
name 包名+类名,使用java的.符号
hook MS.ClassLoadHook的一个实例,当这个类被加载的时候,它的 classLoaded 方法会被执行。

- MS.hookMethod

//该API允许开发者提供一个回调函数替换原来的方法,这个回调函数是一个实现了MS.MethodHook接口的对象,是一个典型的匿名内部类。它包含一个invoked函数
void hookMethod(Class _class, Member member, MS.MethodHook hook, MS.MethodPointer old);
参数 描述
_class 加载的目标类,为classLoaded传下来的类参数
member 通过反射得到的需要hook的方法(或构造函数)。不能够hook字段
hook MS.MethodHook的一个实例,其包含的invoked方法会被调用,用以代替member中的代码

创建android工程

添加jar文件

将SDK中的substrate-api.jar

更改AndroidManifest.xml

  • 添加cydia.permission.SUBSTRATE权限
  • 添加meta标签,name为cydia.permission.SUBSTRATE,value为自己接下来创建的类名.Main

这里由于不需要acitivity,所以讲manifest中额activity相关配置全部删除。如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.rectnativetest">


    <application>
        <meta-data android:name="com.saurik.substrate.main" android:value=".Main"/>
    </application>

    <uses-permission android:name="cydia.permission.SUBSTRATE"/>
</manifest>

创建Main.java

接下来就是创建Main.java,并且需要包含一个static void initialize()方法。

// 当插件被加载的时候,该方法中的代码就会运行
static void initialize() {}

获取目标类的实例

这里我们按照官网上给出的栗子,hook类android.content.res.Resources

MS.hookClassLoad("android.content.res.Resources", new MS.ClassLoadHook() { 
      public void classLoaded(Class<?> resources) { 

      } 
}); 

通过MS.MethodHook更改源代码

这里更改android.content.res.Resources类的getColor方法的返回值,将其返回红色。

Method getColor;
 try {
    getColor = resources.getMethod("getColor", Integer.TYPE);
      } catch (NoSuchMethodException e) {
            getColor = null;
      }

 if (getColor != null) {
     final MS.MethodPointer old = new MS.MethodPointer();
     MS.hookMethod(resources, getColor, new MS.MethodHook() {
        public Object invoked(Object resources, Object... args)
 throws Throwable
   {
      int color = (Integer) old.invoke(resources, args);
      return color & ~0x0000ff00 | 0x00ff0000;
   }
 }, old);
}

运行,安装当前组件,重启手机,效果如下:
android上的简单hook_第3张图片
android上的简单hook_第4张图片

可以发现整个手机系统都已经改变为红色的字体了。

Hook登录方法

这里,我自己写了一个简单应用,只有登录功能,逻辑如下:

 if (name.equals("zhangsan") && pass.equals("123")) {
 return true;
  } else {
 return false;
  }

这里只有用户名为zhangsan以及密码为123,时候,才返回true,即表示登录成功,否则返回false。

同样在Main类的initialize方法里,增加一个hookClassLoad方法,来hook当前登录的activity

MS.hookClassLoad("reacthello.myapplication.MainActivity", new MS.ClassLoadHook() {
            public void classLoaded(Class<?> resources) {
                Method checkLogin;
                try {
                    checkLogin = resources.getMethod("checkLogin", new Class[]{String.class,String.class});
                } catch (NoSuchMethodException e) {
                    checkLogin = null;
                }

                if (checkLogin != null) {
                    final MS.MethodPointer old = new MS.MethodPointer();

                    MS.hookMethod(resources, checkLogin, new MS.MethodHook() {
                        public Object invoked(Object resources, Object... args)
                                throws Throwable
                        {
                            return true;
                        }
                    }, old);
                }
            }
        });

这里的checklogin是刚才登录逻辑的判断,这里,在hook之后横返回true,也就是无论如何都会登录成功,效果如下:
android上的简单hook_第5张图片

更改系统Imei的值

现在大家应该都已经知道了可以通过hookClassLoad和hookMethod来更改指定方法运行的代码,以及返回值。现在我们来更改一下手机系统的IMEI值。
首先,需要知道如何通过代码获取IMEI值

android.telephony.TelephonyManager.getDeviceId();

代码:

MS.hookClassLoad("android.telephony.TelephonyManager", new MS.ClassLoadHook() {
            public void classLoaded(Class<?> resources) {
                Method getDeviceId;
                try {
                    getDeviceId = resources.getMethod("getDeviceId",null);
                } catch (NoSuchMethodException e) {
                    getDeviceId = null;
                }

                if (getDeviceId != null) {
                    final MS.MethodPointer old = new MS.MethodPointer();

                    MS.hookMethod(resources, getDeviceId, new MS.MethodHook() {
                        public Object invoked(Object resources, Object... args)
                                throws Throwable
                        {
                            String imei = (String)old.invoke(resources, args);
                            imei = "aaaaaaaaaaaaaaa";
                            return imei;
                        }
                    }, old);
                }

            }
        });

这里更改的android.telephony.TelephonyManager类下的getDeviceId方法。
此时我们通过:

 String imei = telephonyManager.getDeviceId();
 Toast.makeText(MainActivity.this,"imei is :"+imei,Toast.LENGTH_SHORT).show();

获得的就是aaaaaaaaaa了

实现应用拦截

最后一次尝试一下当我打开一个应用的时候,自动打开一个毫不相干的应用,比如当我每次打开今日头条的时候,系统会跳转到网易新闻,首先我们需要知道“今日头条”和”网易新闻”的主界面的activity,使用如下命令可以获得当前界面的activity:

dumpsys activity | grep mFocusedActivity

这里写图片描述

在adb shell下可以通过如下代码启动activity

 Runtime.getRuntime().exec("am start -n com.netease.newsreader.activity/com.netease.nr.biz.ad.AdActivity");

完整代码:

MS.hookClassLoad("com.ss.android.article.news.activity.MainActivity", new MS.ClassLoadHook() {
            public void classLoaded(Class<?> resources) {
                Log.d("hookstart","com.ss.android.article.news.activity.MainActivity loaded");
                Method onCreate;
                try {
                    onCreate = resources.getMethod("onCreate",Bundle.class);
                } catch (NoSuchMethodException e) {
                    onCreate = null;
                }

                if (onCreate != null) {
                    final MS.MethodPointer old = new MS.MethodPointer();

                    MS.hookMethod(resources, onCreate, new MS.MethodHook() {
                        public Object invoked(Object resources, Object... args)
                                throws Throwable
                        {
                            Log.d("hang.liu","the ooooooo");
                            Object object = old.invoke(resources, args);
                            try {
                                Log.d("hookstart","onCreate hooked.");
                                Runtime.getRuntime().exec("am start -n com.netease.newsreader.activity/com.netease.nr.biz.ad.AdActivity");
                            } catch (Exception e) {
                                Log.d("hookstart","start activity exception happend...");
                            }
                            return object;
                        }
                    }, old);
                }
            }
        });

此时效果如下:
android上的简单hook_第6张图片

ok,可以看到,到目前为止,已经完成了我们想要的效果了。但是还是有很多限制最大的就是手机必须要有root权限,在5.0之后的版本已经不能使用。

源码下载

你可能感兴趣的:(android,hook,cydia)