Hook

简介:

API Hook: 通过 Java 反射,来改变 Android 虚拟机调用函数的方式,从而达到 Java 函数重定向的目的叫做API Hook
API Hook的原理:如果B对象持有A的引用,为A创建动态代理,并利用反射把A用A的代理对象替换

所以使用Hook必须熟悉:相关源码,动态代理,反射

步骤:

1.确定hook的对象
2.寻找hook对象的持有对象
3.使用动态代理创建hook对象的代理类
4.用hook对象的代理类替换hook对象

5.Hook点的选取:要替换的对象尽量选取静态对象,单例,或单例的成员变量,因为单例只需要hook一个对象,而且不用担心这个对象被重置导致Hook效果消失;

例1:在所有View的OnClick事件前增加一句log

1.首先看源码:

class View {
	private ListenerInfo mListenerInfo;
	
	ListenerInfo getListenerInfo() {
        if (mListenerInfo != null) {
           return mListenerInfo;
        }
     	mListenerInfo = new ListenerInfo();
      	return mListenerInfo;
 	}  
}

发现OnClickListener对象被ListenerInfo类的对象持有

2.写Hook工具类:

public class HookSetOnClickListenerHelper {
    public static void hook(Context context, final View v) {
 		try {
 			//确定hook对象为mOnClickListener,而ListenerInfo持有mOnClickListener的引用,
 			//所以要从View中获取ListenerInfo
			Method method = View.class.getDeclaredMethod("getListenerInfo");
    		method.setAccessible(true);//由于getListenerInfo()方法并不是public的,所以要加这个代码来保证访问权限
    		Object mListenerInfo = method.invoke(v);
    		//从ListenerInfo中获取View.OnClickListener
    		Class<?> listenerInfoClz = Class.forName("android.view.View$ListenerInfo");// 这是内部类的表示方法
    		Field field = listenerInfoClz.getDeclaredField("mOnClickListener");
    		final View.OnClickListener onClickListenerInstance = (View.OnClickListener) 		
    		field.get(mListenerInfo);//取得真实的mOnClickListener对象
			//创建OnClickListener的动态代理
			Object proxyOnClickListener = Proxy.newProxyInstance(context.getClass().getClassLoader(),
	 				new Class[]{View.OnClickListener.class}, new InvocationHandler() {
               @Override
               public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                   Log.d("OnClickListener ", "hookEvnet");//加入自己的逻辑
                   return method.invoke(onClickListenerInstance, args);//执行被代理的对象的逻辑
               }
           });
    		//用代理对象替换实际对象
    		field.set(mListenerInfo, proxyOnClickListener);
		} catch(Exception e) {
		}
	}
}

3.使用:

	v.setOnClickListener(v->{});
 	HookSetOnClickListenerHelper.hook(this, v);
例2:用代理Activity替换目标Activity

效果:让Activity启动其他应用的Activity,即使要启动的Activity没有在manifest文件中注册

在这个例子中除了hook之外还涉及到了APK动态加载的内容

1.首先建立一个目标活动TargetActiity,和一个代理活动ProxyActivity,并在Manifest文件中注册代理活动;
2.写IActivityManager的代理对象:

public class IActivityManagerProxy implements InvocationHandler {
    private Object mActivityManager;
    private static final String TAG = "IActivityManagerProxy";
    public IActivityManagerProxy(Object activityManager) {
        this.mActivityManager = activityManager;
    }
    @Override
    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
        if ("startActivity".equals(method.getName())) {//1
            Intent intent = null;
            int index = 0;
            for (int i = 0; i < args.length; i++) {
                if (args[i] instanceof Intent) {
                    index = i;
                    break;
                }
            }
            intent = (Intent) args[index];
            Intent subIntent = new Intent();//2
            String packageName = "com.example.liuwangshu.pluginactivity";
            subIntent.setClassName(packageName,packageName+".StubActivity");//3
            subIntent.putExtra(HookHelper.TARGET_INTENT, intent);//4
            args[index] = subIntent;//5
        }
        return method.invoke(mActivityManager, args);
    }
}

3.获取IActivityManager:

public class HookHelper {
    public static void hookAMS() throws Exception {
        Object defaultSingleton = null;
        if (Build.VERSION.SDK_INT >= 26) {			//Android8.0及以上
        	//得到ActivityManager类型的Class对象
            Class<?> activityManageClazz = Class.forName("android.app.ActivityManager");
            //从ActivityManager中获取IActivityManagerSingleton字段
            //IActivityManagerSingleton是一个Singleton<IActivityManager>类型的静态变量
            defaultSingleton=  FieldUtil.getField(activityManageClazz ,null,"IActivityManagerSingleton");
        } else {									//Android8.0以下
        	//得到ActivityManagerNative类型的Class对象
            Class<?> activityManagerNativeClazz = Class.forName("android.app.ActivityManagerNative");
            //从ActivityManagerNative中获取gDefault字段
            //gDefault也是一个Singleton<IActivityManager>类型的静态变量
            defaultSingleton=  FieldUtil.getField(activityManagerNativeClazz,null,"gDefault");
        }
        Class<?> singletonClazz = Class.forName("android.util.Singleton");
        //从Singleton中获取mInstance变量,mInstance是IActivityManager类型的
        Field mInstanceField = FieldUtil.getField(singletonClazz ,"mInstance");//2
        //获取IActivityManager,作用是用它来构造代理对象;
        Object iActivityManager = mInstanceField.get(defaultSingleton);//3
        Class<?> iActivityManagerclz = Class.forName("android.app.IActivityManager");
        Proxy.newProxyInstance(getClassLoader(), iActivityManagerclz.getInterfaces(), new InvocationHandler() {
           	@Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if ("startActivity".equals(method.getName())) {		//拦截startActivity方法
                    Intent intent = null;							
                    int index = 0;
                    for (int i = 0; i < args.length; i++) {			//遍历proxyIntent方法的参数,找到Intent
                        if (args[i] instanceof Intent) {
                            index = i;								//Intent对象在参数列表中的位置
                            break;
                        }
                    }
                    intent = (Intent) args[index];					//获取startActivity方法的Intent类型的参数
                    Intent proxyIntent = new Intent();
                    String packageName = "com.example.test";
                    proxyIntent.setClassName(packageName,packageName+".ProxyActivity");
                    proxyIntent.putExtra("origin_intent", intent);
                    args[index] = subIntent;			//把startActivity参数列表中的原始Intent用代理Intent替换
                }
                return method.invoke(iActivityManager, args);
            }
        });
        mInstanceField.set(defaultSingleton, proxy);				//用代理IActivityManager替换原本的
    }
}

反射工具类:

public class FieldUtil {
	//获取的target对象(target为Class类型)的成员变量name
    public static Object getField(Class clazz, Object target, String name) throws Exception {
        Field field = clazz.getDeclaredField(name);
        field.setAccessible(true);
        return field.get(target);
    }
    //Class类型的的成员变量name
    public static Field getField(Class clazz, String name) throws Exception{
        Field field = clazz.getDeclaredField(name);
        field.setAccessible(true);
        return field;
    }
    //把的target对象(target为Class类型)的成员变量name的值设置为value
    public static void setField(Class clazz, Object target, String name, Object value) throws Exception {
        Field field = clazz.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target, value);
    }
}

4.在Application初始化时调用hookAMS方法:

public class MyApplication extends Application {
    @Override
    public void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        try {
            HookHelper.hookAMS();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
还原目标Activity

源码:AMS执行完Activity启动的任务后或通知客户端用Handler切换到主线程进行关于生命周期的事件分发,Hook点可以选取在Handler中,重写Handler的handleMessage方法:
1.写Handler的代理类:

public class HCallback implements Handler.Callback{
    public static final int LAUNCH_ACTIVITY = 100;
    Handler mHandler;
    public HCallback(Handler handler) {
        mHandler = handler;
    }
    @Override
    public boolean handleMessage(Message msg) {
        if (msg.what == LAUNCH_ACTIVITY) {
            Object r = msg.obj;
            try {
                //得到消息中的Intent(启动SubActivity的Intent)
                Intent intent = (Intent) FieldUtil.getField(r.getClass(), r, "intent");
                //得到此前保存起来的Intent(启动TargetActivity的Intent)
                Intent target = intent.getParcelableExtra(HookHelper.TARGET_INTENT);
                //将启动SubActivity的Intent替换为启动TargetActivity的Intent
                intent.setComponent(target.getComponent());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        mHandler.handleMessage(msg);
        return true;
    }
}

2.替换handler:

 public static void hookHandler() throws Exception {
        Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
        //获取ActivityThread类中静态的sCurrentActivityThread对象
        Object currentActivityThread = FieldUtil.getField(activityThreadClass ,null,"sCurrentActivityThread");
      	//获取ActivityThread类中静态的mH成员变量
        Field mHField = FieldUtil.getField(activityThreadClass ,"mH");
        //获取currentActivityThread对象Handler对象
        Handler mH = (Handler) mHField.get(currentActivityThread);
        //把mH对象的mCallback参数替换成HCallback代理对象
        FieldUtil.setField(Handler.class,mH,"mCallback",new HCallback(mH));
}

https://www.jianshu.com/p/5d4fc9cc12ac
https://www.jianshu.com/p/2da466493f69

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值