写过windows编辑的同学肯定对当时的特别强大的HOOK记忆犹新,不管是什么系统事件,都能捕捉住,那么在android中,如何实现Hook机制呢。

hook,又叫钩子,通常是指对一些方法进行拦截。这样当这些方法被调用时,也能够执行我们自己的代码,这也是面向切面编程的思想(AOP)

android中,本身并不提供这样的拦截机制,但是有时候,我们可以在一些特殊的场合实现一种的Hook方法。
大致思路:
1. 找到需要Hook方法的系统类(最好是单例的情况)
2. 利用java的动态代理这个系统类
3. 使用反射的方法把这个系统类替换成你的动态代理类

这里,我们以最常见到的拦截 Activity的生命周期为例。经过研究观察,我们发现在android.app.ActivityManagerNative中有一个gDefault属性,这个属性是static final的,返回的是一个singleton的IActivityManager。

private static final Singleton gDefault = new Singleton() {    protected IActivityManager More ...create() {        IBinder b = ServiceManager.getService("activity");            if (false) {                Log.v("ActivityManager", "default service binder = " + b);            }            IActivityManager am = asInterface(b);            if (false) {                Log.v("ActivityManager", "default service = " + am);            }            return am;    }};

这个就给我们可以操作的入口。
有了目标之后,就可以用自己的动态代理,取代这个类。我们先建立一个动态代理。

public class MyActivityManager  implements InvocationHandler{    public static final String TAG = "MyActivityManager";    public Object orignal ;    public Class<?> getOrignalClass() throws ClassNotFoundException {        return Class.forName("android.app.ActivityManagerNative");    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        Log.d(TAG, "before method called:" + method.getName());        final Object obj =  method.invoke(orignal, args);        Log.d(TAG, "after method called:" + method.getName());        return obj;    }}

这个类实现了InvocationHandler,主要用于动态代理。实现的比较简单,仅仅是在调用系统方法的前后,打印日志,当然你也可以做得更多。调用系统的方法也是以原始系统对象的基础上来调用的。

现在我们就可以做点小动作,把系统的类替换成我们的类。

前面说到了,我们需要获取原始系统对象。
第一步获取Singleton gDefault对象。

MyActivityManager activityManager = new MyActivityManager();        Class oriClass = activityManager.getOrignalClass();        Object obj = FieldUtils.readStaticField(oriClass, "gDefault");

这是个由Singleton包装的IActivityManager, 再进一步,查看Singleton的源码:

public abstract class Singleton {    private T mInstance;    public Singleton() {    }    protected abstract T create();    public T get() {        synchronized(this) {            if(this.mInstance == null) {                this.mInstance = this.create();            }            return this.mInstance;        }    }}

最终是要获取mInstance的对象

final Object oriObj = FieldUtils.readField(obj, "mInstance");

这个oriObj就是IActivityManager的一个实现。

我们把这个对象赋给MyActivityManager.

activityManager.orignal = oriObj;

接下来,创建一个代理,

List<Class<?>> interfaces = Utils.getAllInterfaces(oriObj.getClass());        Class[] ifs = interfaces != null && interfaces.size() > 0 ? interfaces.toArray(new Class[interfaces.size()]) : new Class[0];        final Object object = Proxy.newProxyInstance(oriObj.getClass().getClassLoader(),ifs, activityManager);

最后,把这个代理对象写入到系统的对象中。

 FieldUtils.writeStaticField(oriClass, "gDefault", new android.util.Singleton() {            @Override            protected Object create() {                return object;            }        });   

运行程序,可以看到以下日志:

11-18 14:24:24.322 9881-9881/com.win16.hooktest D/MyActivityManager: before method called:checkPermission
11-18 14:24:24.327 9881-9881/com.win16.hooktest D/MyActivityManager: after method called:checkPermission
11-18 14:24:24.327 9881-9881/com.win16.hooktest D/MyActivityManager: before method called:checkPermission
11-18 14:24:24.327 9881-9881/com.win16.hooktest D/MyActivityManager: after method called:checkPermission
11-18 14:24:24.387 9881-9881/com.win16.hooktest D/MyActivityManager: before method called:broadcastIntent
11-18 14:24:24.477 9881-9881/com.win16.hooktest D/MyActivityManager: after method called:broadcastIntent
11-18 14:24:24.502 9881-9881/com.win16.hooktest D/MyActivityManager: before method called:activityResumed
11-18 14:24:24.507 9881-9881/com.win16.hooktest D/MyActivityManager: after method called:activityResumed
11-18 14:24:24.507 9881-9881/com.win16.hooktest D/MyActivityManager: before method called:broadcastIntent
11-18 14:24:24.507 9881-9881/com.win16.hooktest D/MyActivityManager: after method called:broadcastIntent
11-18 14:24:24.507 9881-9881/com.win16.hooktest D/MyActivityManager: before method called:activityPaused
11-18 14:24:24.512 9881-9881/com.win16.hooktest D/MyActivityManager: after method called:activityPaused
11-18 14:24:24.622 9881-9881/com.win16.hooktest D/MyActivityManager: before method called:activitySlept
11-18 14:24:24.622 9881-9881/com.win16.hooktest D/MyActivityManager: after method called:activitySlept
11-18 14:24:24.812 9881-9881/com.win16.hooktest D/MyActivityManager: before method called:activityStopped
11-18 14:24:24.812 9881-9881/com.win16.hooktest D/MyActivityManager: after method called:activityStopped
11-18 14:24:24.832 9881-9881/com.win16.hooktest D/MyActivityManager: before method called:activityIdle
11-18 14:24:24.832 9881-9881/com.win16.hooktest D/MyActivityManager: after method called:activityIdle

小结
这里提供一种拦截系统API的思路,供大家参考。另外还有一种更加底层的拦截方式,修改JVM中的slot来实现,有兴趣的同学可以参考:https://github.com/alibaba/dexposed

本文相关源码下载:https://github.com/mutsinghua/AndroidHook

更多相关文章

  1. 最封闭的开源系统,话说Android的八宗罪(转)
  2. 【Android 性能优化】应用启动优化 ( 安卓应用启动分析 | Launch
  3. Android系统触摸屏的校正——http://carvencao.blog.sohu.com/15
  4. Android方法数
  5. 改变Android按钮背景颜色的高效方法
  6. Android输入法框架系统(上)
  7. Android双击返回键退出程序的实现方法
  8. QtAndroid详解(5):JNI调用Android系统功能(2)
  9. 混合开发之ReactNative调用Android原生方法

随机推荐

  1. Android(安卓)程序的安装、卸载和更新
  2. 箭头的使用
  3. android利用数字证书对程序签名
  4. 升级到Android(安卓)Studio 3.2.1,报The s
  5. java服务端与ios,android实现简单数据加密
  6. android中设置AlertDialog的大小
  7. Android中BLE连接出现“BluetoothGatt st
  8. android电子书大全 下载
  9. android 更改TextView部分字体颜色、大小
  10. android搜索热词(热门标签)流式布局的实