實現(xiàn)原理
通過Android的Activity啟動原理可以知道startActivity()時,通過進程間通信(IPC)通知ActivityManagerService,然后PackageManagerService通過intent過濾器掃描清單文件瑰抵。
hook技術(shù)可以讓啟動的Activity不在清單文件中注冊,通過動態(tài)代理的方式結(jié)合反射消别,使用可以通過PackageManagerService掃描的intent(在清單文件注冊)熄驼,當intent通過后并且Acitvity啟動之前,再將intent中的Component替換為需要啟動的acitivty即可料扰。
代碼實現(xiàn)
1.創(chuàng)建一個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);
//使用動態(tài)代理 創(chuàng)建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);
//綁定通過系統(tǒng)的filter
proxyIntent.putExtra("oldIntent", intent);
//開始替換
objects[index] = proxyIntent;
return method.invoke(iActivityManagerObject, objects);
}
return method.invoke(iActivityManagerObject, objects);
}
}
3.當Intent通過時望迎,啟動activity通過源碼 系統(tǒng)是通過handler進行啟動,handler有個callback 當判斷callback為空時才進行發(fā)消息凌外,啟動activit辩尊,這里再創(chuàng)建一個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 {
//不能強轉(zhuǎn) 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地址