我们先来看一下activity启动的过程
activity的startActivity:
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
经过一系列调用,会调到startActivityForResult:
其中调用了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;
}
其中启动activity的方法是ActivityManagerNative.getDefault().startActivity()。ActivityManagerNative继承了Binder,同时实现了IActivityManager接口,启动activity用到了Android中binder机制,getDefault方法实际上获得了系统ActivityManagerService
checkStartActivityResult方法会检查,到这里我们已经找到的报错的地方
getDefault:返回了IActivityManager的一个单例,有没有办法把这个单例替换掉,自己实现startActivity方法来绕过系统对activity的校验呢
思路:通过动态代理的方式修改接口
步骤
1.在manifest中注册代理的activity
<activity android:name=".ProxyActivity"/>
2.通过反射修改ActivityManagerNative类的 gDefault属性
public void hookStartActivity() throws Exception{
// 1>:获取 ActivityManagerNative里面的 gDefault;
Class<?> amnClass = Class.forName("android.app.ActivityManagerNative") ;
// 通过 ActivityManagerNative 类 获取 gDefault属性
Field gDefaultField = amnClass.getDeclaredField("gDefault");
gDefaultField.setAccessible(true); // 设置权限
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:必须有一个执行者,就是谁去执行这个方法
new StartActivityInvocationHandler(iamInstance)) ;
// 3>:重新指定
mInstanceField.set(gDefault,a);
}
3.设置代理
private class StartActivityInvocationHandler implements InvocationHandler {
// 这个才是方法的执行者
private Object mObject ;
// 通过构造方法把mObject传递进来
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 ,过AndroidManifest.xml 检测
if (method.getName().equals("startActivity")){
// 1. 首先获取原来的intent
Intent originIntent = (Intent) args[2];
// 2. 创建一个安全的intent
Intent safeIntent = new Intent(mContext , mProxyClass) ;
// 3. 替换第二个参数
args[2] = safeIntent ;
// 4. 绑定原来的Intent
safeIntent.putExtra(EXTER_ORIGIN_INTENT , originIntent) ;
}
return method.invoke(mObject , args);
}
网友评论