本文hook以activity来讲解,运用Java反射以及代理。
hook技术的难点在于hook到某个点,就是寻找在内存中“不变”的对象,那么静态修饰或者单例就是我们要hook的点,然后实现代理。所以根据这个想法,我们就来找Activity需要hook的点。
一:我们先跟踪 startActivity源码
第一步:
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
第二步:发现startActivity实际上调用了startActivityForResult
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
startActivityForResult(intent, -1);
}
}
第三步:跟进startActivityForResult,发现是 Instrumentation 执行了execStartActivity
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
if (mParent == null) {
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
}
}
第四步:跟踪Instrumentation.execStartActivity(),发现是ActivityManagerNative.getDefault()执行了startActivity,而ActivityManagerNative.getDefault()是静态全局变量,所以,该变量就是我们要hook的点。
public Instrumentation.ActivityResult execStartActivity(***) {
/**
* 省略
*/
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess();
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
二:通过反射获取ActivityManagerNative.getDefault()属性。并将其中的值替换成代理对象。
public class HookUtil {
public static void hook() {
try {
// AS无法直接调用,所以采用该方式获取ActivityManagerNative.class文件
Class<?> activityManagerNative = Class.forName("android.app.ActivityManagerNative");
//获取gDefault属性
Field gDefaultFiled = activityManagerNative.getDeclaredField("gDefault");
//将field设置为可访问
gDefaultFiled.setAccessible(true);
//由于ActivityManagerNative.gDefault为static类型,所以不需要传ActivityManagerNative对象,该属性为类所有
Object gDefault = gDefaultFiled.get(null);
/**
* gDefault实际上是Singleton对象,所以我们要获取Singleton中的IActivityManager对象
* private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
* protected IActivityManager create() {
* IBinder b = ServiceManager.getService("activity");
* IActivityManager am = asInterface(b);
* return am;
* }
* };
*/
//Singleton也无法通过AS直接调用,所以也采用该方式获取
Class<?> SingletonClass = Class.forName("android.util.Singleton");
Field mInstanceField = SingletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
Object iActivityManager = mInstanceField.get(gDefault);
/**
* 以下将iActivityManager生成代理对象。
*/
ProxyHander proxyHander = new ProxyHander();
Object proxyInstance = proxyHander.proxy(iActivityManager);
//将mInstanceField的值替换成代理对象
mInstanceField.set(gDefault, proxyInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ActivityInterceptor {
public void before() {
Log.i("ActivityInterceptor", "before= ");
}
public void after() {
Log.e("ActivityInterceptor", "after= ");
}
}
public class ProxyHander implements InvocationHandler {
/**
* 被代理的对象
*/
private Object object;
/**
* activity自定义的拦截器
*/
private ActivityInterceptor interceptor = new ActivityInterceptor();
/**
* 动态生成一个代理类对象
*
* @param object
* @return 返回的是代理对象
*/
public Object proxy(Object object) {
this.object = object;
Object proxyInstance = Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(), this);
return proxyInstance;
}
/**
* 被代理对象执行方法时会调该方法
*
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
interceptor.before();
Object result = method.invoke(this.object, args);
interceptor.after();
return result;
}
}
三:在Application中执行该段代码。
@Override
public void onCreate() {
super.onCreate();
HookUtil.hook();
}
四:运行效果,会在activity onCreate等方法执行前后输出 before ,after
总结:
1:通过反射获取到ActivityManagerService中的gDefault对象,并通过反射拿到IActivityManager对象,然后对IActivityManager对象进行代理。
2:该hook技术应用于Android P以下系统,Android P禁用了非公开API的调用。