插件化原理解析Hook AMS&PMS

ActivityManagerService可以认为是Android系统四大组件的通讯中心。四大组件相关的操作都会跟它打交道。而PackageManagerService则主要负责应用包内容的解析校验。因此在插件化过程中,Hook它们可以带来很多方便

AMS

1
ActivityManager.getService();

通过上述代码,我们能够获得AMS

1
2
3
4
5
6
7
8
9
10
11
12
13
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};

其最终通过ServiceManager获取对应的IBinder对象,然后转成对应的接口,也就是AMS

Hook AMS

通过查看源码,我们能够知道在8.0及之后,ActivityManagerNative以及标记过期,即将被去掉。而是直接使用ActivityManager来获取服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class AmsPmsHookHelperKt {
companion object {
fun hookActivityManager() {
try {
val activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative")

val gDefaultField = activityManagerNativeClass.getDeclaredField("gDefault")
gDefaultField.isAccessible = true
val gDefault = gDefaultField.get(null)

val singletonClass = Class.forName("android.util.Singleton")
val instanceField = singletonClass.getDeclaredField("mInstance")
instanceField.isAccessible = true

val rawIActivityManager = instanceField.get(gDefault)
val activityManagerInterface = Class.forName("android.app.IActivityManager")
val proxy = Proxy.newProxyInstance(Thread.currentThread().contextClassLoader, arrayOf(activityManagerInterface), HookHandler(rawIActivityManager))
instanceField.set(gDefault, proxy)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}

获取ActivityManagerNative,通过动态代理,重新创建出一个对象,用来替换gDefault

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class HookHandler implements InvocationHandler {

private static final String TAG = "HookHandler";

private Object mBase;

public HookHandler(Object base) {
mBase = base;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.d(TAG, "hey, baby; you are hooked!!");
Log.d(TAG, "method:" + method.getName() + " called with args:" + Arrays.toString(args));

return method.invoke(mBase, args);
}
}

IActivityManager触发调用时,invoke回调,这个时候会打印出添加的内容

1
2
10-04 16:04:13.092 17046-17046/cn.binea.pluginframeworkdemo D/HookHandler: hey, baby; you are hooked!!
10-04 16:04:13.093 17046-17046/cn.binea.pluginframeworkdemo D/HookHandler: method:activityIdle called with args:[android.os.BinderProxy@e0086ab, {1.0 310mcc260mnc [en_US] ldltr sw360dp w360dp h568dp 480dpi nrml port finger qwerty/v/v -nav/h s.6}, false]

PMS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}

IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}

return null;
}

ContextImpl中通过ActivityThread.getPackageManager获取pms,并会通过ApplicationPackageManager增强pms

1
2
3
4
5
6
7
8
9
10
11
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
//Slog.v("PackageManager", "returning cur default = " + sPackageManager);
return sPackageManager;
}
IBinder b = ServiceManager.getService("package");
//Slog.v("PackageManager", "default service binder = " + b);
sPackageManager = IPackageManager.Stub.asInterface(b);
//Slog.v("PackageManager", "default service = " + sPackageManager);
return sPackageManager;
}

ThreadActivity中,检查缓存pms是否存在。如果不存在,通过ServiceManager获取特定IBinder对象,并通过asInterface转换成对应的接口IPackageManager.这里可以Hook这个缓存对象。