简介:
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