若对Activity的启动流程不熟悉的可以看我这篇文章App启动——Activity的启动流程
首先看一般的activity的启动流程
一般的activity的启动流程.png我们要进行拦截activity,AMS中进行HOOK这个是不可能的因为它还管理其他APP呢,所以我们可以对第一步和最后一步进行Activity的拦截,如何拦截,看下面这个图
image.png
在第一步启动ActivityB的时候进行拦截
我们都知道Activity和AMS进行通信是通过AMN/AMP,我们在AMN中可以看到这行代码
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
IActivityManger中有这行代码
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,
ProfilerInfo profilerInfo, Bundle options) throws RemoteException;
因此我们实际上可以对IActivityManger中的startActivity方法进行拦截,把第二个参数intent换成我们安全的intent,再用代理对象将原本的IActivityManager整体进行替换(代码有足够的解释,不再阐述)
private Context mContext;
private Class<?> mProxyClass;
//保留原始intent
private final String EXTRA_ORIGIN_INTENT = "EXTRA_ORIGIN_INTENT";
public HookStartActivityUtil(Context context, Class<?> proxyClass) {
this.mContext = context.getApplicationContext();
this.mProxyClass = proxyClass;
}
public void hookStartActivity() throws Exception {
//1.首先获取到ActivityManagerNative中的gDefault属性
Class<?> amnClazz = Class.forName("android.app.ActivityManagerNative");
//获取属性
Field gDefaultField = amnClazz.getDeclaredField("gDefault");
//获取权限
gDefaultField.setAccessible(true);
//获取值
Object gDefault = gDefaultField.get(null);
//2.获取gDefault中的mInstance属性
//因为gDefault实际是android.util.Singleton属性,而我们实际的目的是替换它里面的泛型也就是mInstance
Class<?> singletonClazz = Class.forName("android.util.Singleton");
//获取属性
Field mInstanceField = singletonClazz.getDeclaredField("mInstance");
//获取属性
mInstanceField.setAccessible(true);
//获取mInstance值
Object mInstance = mInstanceField.get(gDefault);
//获得里面的值之后就开始替换了,要替换的泛型mInstance实际上是IActivityManager,看gDefault的源码,用代理对象去替换
//首先创建一个IActivityManager对象
Class<?> iamClazz = Class.forName("android.app.IActivityManager");
mInstance = Proxy.newProxyInstance(HookStartActivityUtil.class.getClassLoader(),
new Class[]{iamClazz},
new StartActivityInvocationHandler(mInstance));
//3.重新指定
mInstanceField.set(gDefault,mInstance);
}
private class StartActivityInvocationHandler implements InvocationHandler {
// 方法执行者
private Object mObject;
public StartActivityInvocationHandler(Object object) {
this.mObject = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.e("TAG",method.getName());
if(method.getName().equals("startActivity")){
//1.首先要获取原来的intent
Intent originIntent = (Intent) args[2];
//2.创建一个安全的intern
Intent safeIntent=new Intent(mContext,mProxyClass);
//偷梁换柱
args[2]=safeIntent;
//保存原始的的originIntent,最后一步的时候需要设置回去
safeIntent.putExtra(EXTRA_ORIGIN_INTENT, originIntent);
}
return method.invoke(mObject,args);
}
}
现在将最后一步代理的activity换成原本的
我们都知道最后实际是mH发送一个LAUNCH_ACTIVITY(值为100)消息,并将含有intent的记录ActivityClientRecord发送过去,思路就是在发送消息之前也就是mCallback重写msg.what=100的消息将值intent重新赋值过去
public void hookLaunchActivity() throws Exception {
//1 获取ActivityThread实例
Class<?> atClass = Class.forName("android.app.ActivityThread");
Field scatField = atClass.getDeclaredField("sCurrentActivityThread");
scatField.setAccessible(true);
//获取值
Object sCurrentActivityThread = scatField.get(null);
//2.获取ActivityThread中的mH
Field mhField = atClass.getDeclaredField("mH");
mhField.setAccessible(true);
Handler mHandler = (Handler) mhField.get(sCurrentActivityThread);
// 设置Callback
/* Field callBackField = Handler.class.getDeclaredField("mCallback");
callBackField.setAccessible(true);*/
Class<?> handlerClass = Class.forName("android.os.Handler");
Field mCallbackField = handlerClass.getDeclaredField("mCallback");
mCallbackField.setAccessible(true);
mCallbackField.set(mHandler,new ActivityThreadHandlerCallBack());
}
private class ActivityThreadHandlerCallBack implements Handler.Callback{
@Override
public boolean handleMessage(Message msg) {
if (msg.what==100){
handleLaunchActivity(msg);
}
return false;
}
}
private void handleLaunchActivity(Message msg) {
try {
Object obj = msg.obj;
Field intentField = obj.getClass().getDeclaredField("intent");
intentField.setAccessible(true);
Intent proxyIntent = (Intent) intentField.get(obj);
//获得原始的intent
Intent originIntent = proxyIntent.getParcelableExtra(EXTRA_ORIGIN_INTENT);
//设置回去
if(originIntent!=null){
intentField.set(obj,originIntent);
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
兼容AppCompatActivity
上面代码在activity中是完美运行的,但是在AppCompatActivity中老是报错。修改handleLaunchActivity代码
private void handleLaunchActivity(Message msg) {
try {
Object record = msg.obj;
// 1.从record 获取过安检的Intent
Field intentField = record.getClass().getDeclaredField("intent");
intentField.setAccessible(true);
Intent safeIntent = (Intent) intentField.get(record);
// 2.从safeIntent中获取原来的originIntent
Intent originIntent = safeIntent.getParcelableExtra(EXTRA_ORIGIN_INTENT);
// 3.重新设置回去
if (originIntent != null) {
intentField.set(record, originIntent);
}
// 兼容AppCompatActivity报错问题
Class<?> forName = Class.forName("android.app.ActivityThread");
Field field = forName.getDeclaredField("sCurrentActivityThread");
field.setAccessible(true);
Object activityThread = field.get(null);
// 我自己执行一次那么就会创建PackageManager,系统再获取的时候就是下面的iPackageManager
Method getPackageManager = activityThread.getClass().getDeclaredMethod("getPackageManager");
Object iPackageManager = getPackageManager.invoke(activityThread);
PackageManagerHandler handler = new PackageManagerHandler(iPackageManager);
Class<?> iPackageManagerIntercept = Class.forName("android.content.pm.IPackageManager");
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[]{iPackageManagerIntercept}, handler);
// 获取 sPackageManager 属性
Field iPackageManagerField = activityThread.getClass().getDeclaredField("sPackageManager");
iPackageManagerField.setAccessible(true);
iPackageManagerField.set(activityThread, proxy);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class PackageManagerHandler implements InvocationHandler {
private Object mActivityManagerObject;
public PackageManagerHandler(Object iActivityManagerObject) {
this.mActivityManagerObject = iActivityManagerObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().startsWith("getActivityInfo")) {
ComponentName componentName = new ComponentName(mContext, mProxyClass);
args[0] = componentName;
}
return method.invoke(mActivityManagerObject, args);
}
}
网友评论