实现原理
通过Android的Activity启动原理可以知道startActivity()时,通过进程间通信(IPC)通知ActivityManagerService,然后PackageManagerService通过intent过滤器扫描清单文件。
hook技术可以让启动的Activity不在清单文件中注册,通过动态代理的方式结合反射,使用可以通过PackageManagerService扫描的intent(在清单文件注册),当intent通过后并且Acitvity启动之前,再将intent中的Component替换为需要启动的acitivty即可。
代码实现
1.创建一个hook工具类:
/**
* @param proxyActivity 代理Activity
* @param context
*/
public HookAmsUtil(Class<?> proxyActivity, Context context) {
this.proxyActivity = proxyActivity;
this.context = context;
}
public void hookAms() {
try {
//通过反射得到ActivityManagerNative类 和成员变量gDefault
Class<?> forName = Class.forName("android.app.ActivityManagerNative");
Field defaultField = forName.getDeclaredField("gDefault");
defaultField.setAccessible(true);
Object defaultValue = defaultField.get(null);
//反射SingleTon
Class<?> aClass = Class.forName("android.util.Singleton");
Field instanceField = aClass.getDeclaredField("mInstance");
instanceField.setAccessible(true);
//得到源码中的iActivityManager
Object iActivityManagerObject = instanceField.get(defaultValue);
//使用动态代理 创建hook
Class<?> iActivityManagerIntercept = Class.forName("android.app.IActivityManager");
AmsInvocationHandler handler = new AmsInvocationHandler(iActivityManagerObject);
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{iActivityManagerIntercept}, handler);
//替换
instanceField.set(defaultValue, proxy);
} catch (Exception e) {
e.printStackTrace();
}
}
2.因为intent中的xxxActivity.class并没有在清单文件注册,这里将其从 IActivityManager取出并替换为代理intent,程序不会崩溃。
class AmsInvocationHandler implements InvocationHandler {
private Object iActivityManagerObject;
public AmsInvocationHandler(Object iActivityManagerObject) {
this.iActivityManagerObject = iActivityManagerObject;
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
Log.i("INFO", "methodName:" + method.getName());
if ("startActivity".contains(method.getName())) {
Intent intent = null;
int index = 0; //记录索引,通过后再体会为原意图
for (int i = 0; i < objects.length; i++) {
if (objects[i] instanceof Intent) {
intent = (Intent) objects[i]; //原意图
index = i;
break;
}
}
//Intent intent = new Intent(context,ProxyActivity.class);//可以这样写
Intent proxyIntent = new Intent();
ComponentName componentName = new ComponentName(context, proxyActivity);
proxyIntent.setComponent(componentName);
//绑定通过系统的filter
proxyIntent.putExtra("oldIntent", intent);
//开始替换
objects[index] = proxyIntent;
return method.invoke(iActivityManagerObject, objects);
}
return method.invoke(iActivityManagerObject, objects);
}
}
3.当Intent通过时,启动activity通过源码 系统是通过handler进行启动,handler有个callback 当判断callback为空时才进行发消息,启动activit,这里再创建一个hook,自定义一个callback,把intent的activity替换为我们想要启动的
public void hookSystemHandler() {
try {
Class<?> forName = Class.forName("android.app.ActivityThread");
Field currentActivityThread = forName.getDeclaredField("sCurrentActivityThread");
currentActivityThread.setAccessible(true);
Object activityThreadValue = currentActivityThread.get(null);//程序的入口
Field handlerField = forName.getDeclaredField("mH");
handlerField.setAccessible(true);
Handler handlerObject = (Handler) handlerField.get(activityThreadValue);
Field callbackField = Handler.class.getDeclaredField("mCallback");
callbackField.setAccessible(true); //防止私有
callbackField.set(handlerObject,new ActivityThreadHandlerCallback(handlerObject));
} catch (Exception ex) {
ex.printStackTrace();
}
}
class ActivityThreadHandlerCallback implements Handler.Callback{
Handler handler;
public ActivityThreadHandlerCallback(Handler handler) {
this.handler = handler;
}
@Override
public boolean handleMessage(Message message) {
Log.i("INFO","message callback");
//这里替换回之前的intent
if (message.what == 100){
Log.i("INFO","lauchActivity");
handleLaunchActivity(message);
}
handler.handleMessage(message);
return true;
}
private void handleLaunchActivity(Message message) {
Object obj = message.obj; //ActivityClientRecord
try {
//不能强转 framwork层
Field intentField = obj.getClass().getDeclaredField("intent");
intentField.setAccessible(true);
Intent proxyIntent = (Intent) intentField.get(obj);
Intent realIntent = proxyIntent.getParcelableExtra("oldIntent");
if (realIntent != null){
//代理意图替换成真实意图
proxyIntent.setComponent(realIntent.getComponent());
}
}catch (Exception e){
e.printStackTrace();
}
}
}
4.application中配置:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
HookAmsUtil amsUtil = new HookAmsUtil(ProxyActivity.class,this);
amsUtil.hookAms();
amsUtil.hookSystemHandler();
}
}
宿主中通过下载的插件安装,后期更新。
github的demo地址