final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
同样的,getService方法返回了了IActivityManager类型的对象,并且IActivityManager借助了Singleton类来实现单例,确定了无论是Android7.0还是Android8.0,IActivityManager都是比较好的Hook点。Singleton类如下所示,后面会用到。 frameworks/base/core/java/android/util/Singleton.java
public abstract class Singleton {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
由于Hook需要多次对字段进行反射操作,先写一个字段工具类FieldUtil:
FieldUtil.java
public class FieldUtil {
public static Object getField(Class clazz, Object target, String name) throws Exception {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field.get(target);
}
public static Field getField(Class clazz, String name) throws Exception{
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field;
}
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);
}
其中setField方法不会马上用到,接着定义替换IActivityManager的代理类IActivityManagerProxy,如下所示。
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);
}
}
Hook点IActivityManager是一个接口,建议采用动态代理。在注释1处拦截startActivity方法,接着获取参数args中第一个Intent对象,它是原本要启动插件TargetActivity的Intent。注释2、3处新建一个subIntent用来启动的StubActivity,注释4处将这个TargetActivity的Intent保存到subIntent中,便于以后还原TargetActivity。注释5处用subIntent赋值给参数args,这样启动的目标就变为了StubActivity,用来通过AMS的校验。 最后用代理类IActivityManagerProxy来替换IActivityManager,如下所示。
HookHelper.java
public class HookHelper {
public static final String TARGET_INTENT = “target_intent”;
public static void hookAMS() throws Exception {
Object defaultSingleton=null;
if (Build.VERSION.SDK_INT >= 26) {//1
Class<?> activityManageClazz = Class.forName(“android.app.ActivityManager”);