我們先來(lái)看一下activity啟動(dòng)的過(guò)程
activity的startActivity:
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
經(jīng)過(guò)一系列調(diào)用,會(huì)調(diào)到startActivityForResult:
其中調(diào)用了Instrumentation中的execStartActivity()方法
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
execStartActivity:
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
...
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
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;
}
其中啟動(dòng)activity的方法是ActivityManagerNative.getDefault().startActivity()。ActivityManagerNative繼承了Binder,同時(shí)實(shí)現(xiàn)了IActivityManager接口,啟動(dòng)activity用到了Android中binder機(jī)制,getDefault方法實(shí)際上獲得了系統(tǒng)ActivityManagerService
checkStartActivityResult方法會(huì)檢查,到這里我們已經(jīng)找到的報(bào)錯(cuò)的地方
getDefault:返回了IActivityManager的一個(gè)單例巢钓,有沒有辦法把這個(gè)單例替換掉,自己實(shí)現(xiàn)startActivity方法來(lái)繞過(guò)系統(tǒng)對(duì)activity的校驗(yàn)?zāi)?/p>
思路:通過(guò)動(dòng)態(tài)代理的方式修改接口
步驟
1.在manifest中注冊(cè)代理的activity
<activity android:name=".ProxyActivity"/>
2.通過(guò)反射修改ActivityManagerNative類的 gDefault屬性
public void hookStartActivity() throws Exception{
// 1>:獲取 ActivityManagerNative里面的 gDefault;
Class<?> amnClass = Class.forName("android.app.ActivityManagerNative") ;
// 通過(guò) ActivityManagerNative 類 獲取 gDefault屬性
Field gDefaultField = amnClass.getDeclaredField("gDefault");
gDefaultField.setAccessible(true); // 設(shè)置權(quán)限
Object gDefault = gDefaultField.get(null) ;
// 2>:獲取gDefault中的 mInstance屬性;
Class<?> singletonClass = Class.forName("android.util.Singleton") ;
Field mInstanceField = singletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
Object iamInstance = mInstanceField.get(gDefault);
Object a;
Class<?> iamClass = Class.forName("android.app.IActivityManager") ;
a = Proxy.newProxyInstance(HookStartActivityUtil.class.getClassLoader(),
new Class[] {iamClass} ,
// InvocationHandler:必須有一個(gè)執(zhí)行者栖茉,就是誰(shuí)去執(zhí)行這個(gè)方法
new StartActivityInvocationHandler(iamInstance)) ;
// 3>:重新指定
mInstanceField.set(gDefault,a);
}
3.設(shè)置代理
private class StartActivityInvocationHandler implements InvocationHandler {
// 這個(gè)才是方法的執(zhí)行者
private Object mObject ;
// 通過(guò)構(gòu)造方法把mObject傳遞進(jìn)來(lái)
public StartActivityInvocationHandler(Object object){
this.mObject = object ;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在這里可以 hook到 IActivityManager中所有的方法
Log.e("TAG" , method.getName()) ;
// 替換intent ,過(guò)AndroidManifest.xml 檢測(cè)
if (method.getName().equals("startActivity")){
// 1. 首先獲取原來(lái)的intent
Intent originIntent = (Intent) args[2];
// 2. 創(chuàng)建一個(gè)安全的intent
Intent safeIntent = new Intent(mContext , mProxyClass) ;
// 3. 替換第二個(gè)參數(shù)
args[2] = safeIntent ;
// 4. 綁定原來(lái)的Intent
safeIntent.putExtra(EXTER_ORIGIN_INTENT , originIntent) ;
}
return method.invoke(mObject , args);
}