Detailed explanation of Android hook plug-in

introduction

Android plug-in is a technology that modularizes the functions of an application into independent plug-ins and dynamically loads them into the main application. Through plug-in, developers can decompose the application's functions into independent modules. Each module can be independently developed, tested and maintained as a plug-in, and then integrated into the main application through dynamic loading to achieve dynamic expansion of functions. and updates.

Android plug-ins usually involve dynamic loading, componentization, plug-in life cycle management, inter-plugin communication and other technologies. Developers need to use relevant frameworks and tools to implement plug-in functions. Plug-inization can help developers better manage the complexity of applications and improve development efficiency. It can also dynamically update and expand application functions to provide users with a better experience.

1.startActivity source code analysis

We mentioned in the previous article that calling startActivity starts an activity that is not in Manifest.xmlstart Start analyzing why the exception is reported. registered in the file will report an exception, so we will startActivityActivity The

The process of startActivity is roughly as shown above. If there is no If registered in Manifest.xml, the software will crash. So how can we avoid this? In fact, it is very simple. We only need to replace our unregistered Activity with the one we have already registered in Manifest.xml Just register. So the question comes again, how should we implement the replacement operation? Speaking of replacement, we have to use dynamic proxy to achieve it.

As can be seen from the above figure, three parameters need to be passed to create a dynamic proxy object. These parameters are introduced below.

ClassLoader loader: Class Loader

Class<?>[] interfaces: The interface that needs to be monitored

InvocationHandler h: monitored callback

Speaking of which, we extend to another question, which interface should we monitor? , in fact, we have already analyzed it from the above, we should listen to AMS.startActivity in this step, so the interface we want to monitor is < a i=3>IActivityTaskManager (9.0 and below is IActivityManager) This interface. Next we will implement a dynamic proxy for this interface.

2. Implementation of dynamic proxy

first step:

We can getIActivityTaskManagerClass.forName() > OrIActivityManager this class, as shown in the following code:

Class<?> mIActivityManagerClass;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    mIActivityManagerClass = Class.forName("android.app.IActivityTaskManager");
} else {
    mIActivityManagerClass = Class.forName("android.app.IActivityManager");
}

After having the class, we can create dynamic proxy objects, but IActivityTaskManager or IActivityManager< /span> Just use the method, as shown in the following code:"startActivity" There are so many methods in the interface, we don’t need to monitor them all, we only need to monitor the ones we care about

//创建动态代理
Object mActivityManagerProxy = Proxy.newProxyInstance(
    getClassLoader(),//类加载器
    new Class[]{mIActivityManagerClass},//要监听的回调接口
    new InvocationHandler() {//回调的监听
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if ("startActivity".equals(method.getName())) {
            //做自己的业务逻辑
            //换成可以通过AMS检测的Activity
           
        }
        //为了程序能够正确执行,我们需要系统的IActivityManager实例
        return method.invoke(需要系统的IActivityManager实例, args);
    }
);

As can be seen from the above code, to make the dynamic proxy effective, we also need an IActivityManager, check the source codeActivityTaskManager (see ActivityManager below 8.0~9.0, see ActivityManagerNative below 8.0) Found:

ActivityTaskManager.java:(Androdid10.0)

/** @hide */
public static IActivityTaskManager getService() {
    return IActivityTaskManagerSingleton.get();
}

ActivityManager.java:(Android 8.0 ~ Android9.0)

/**
* @hide
*/
public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

ActivityManagerNative.java: (Android 7.0 and below)

/**
* Retrieve the system's default/global activity manager.
*/
static public IActivityManager getDefault() {
    return gDefault.get();
}

By getService() or getDefault() Return an object instance we need, we can then use reflection to execute this method to obtain IActivityTaskManager or IActivityManager< /span> Instance object. The code is as follows:

//获取 ActivityManager 或 ActivityManagerNative 或 ActivityTaskManager
Class<?> mActivityManagerClass;
Method getActivityManagerMethod;
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
    mActivityManagerClass = Class.forName("android.app.ActivityManagerNative");
    getActivityManagerMethod = mActivityManagerClass.getDeclaredMethod("getDefault");
} else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q){
    mActivityManagerClass = Class.forName("android.app.ActivityManager");
    getActivityManagerMethod = mActivityManagerClass.getDeclaredMethod("getService");
} else {
    mActivityManagerClass = Class.forName("android.app.ActivityTaskManager");
    getActivityManagerMethod = mActivityManagerClass.getDeclaredMethod("getService");
}
getActivityManagerMethod.setAccessible(true);
//这个实例本质是 IActivityManager或者IActivityTaskManager
final Object IActivityManager = getActivityManagerMethod.invoke(null);

Now we haveIActivityTaskManager orIActivityManager instance object This will allow the program to continue executing.

Second step: Since we created it ourselvesIActivityTaskManager orFor the dynamic proxy of IActivityManager, we need to replace the original system's IActivityTaskManager or IActivityManager instance object is replaced. Or start with the above getService() or getDefault() method. We continued to trace the code and found that: ActivityManager or ActivityManagerNative or ActivityTaskManager all have a Singleton Common attributes, let’s take a look at the source code of this class:

public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

The mInstance property inside  or < /span>  value. The code is as follows:mInstance instance, so we can directly replace the IActivityManagerIActivityTaskManager happens to be 

//获取 IActivityTaskManagerSingleton 或者 IActivityManagerSingleton 或者 gDefault 属性
Field mSingletonField;
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
    mSingletonField = mActivityManagerClass.getDeclaredField("gDefault");
} else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q){
    mSingletonField = mActivityManagerClass.getDeclaredField("IActivityManagerSingleton");
} else {
    mSingletonField = mActivityManagerClass.getDeclaredField("IActivityTaskManagerSingleton");
}
mSingletonField.setAccessible(true);
Object mSingleton = mSingletonField.get(null);

//替换点
Class<?> mSingletonClass = Class.forName("android.util.Singleton");
Field mInstanceField = mSingletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
//将我们创建的动态代理设置到 mInstance 属性当中
mInstanceField.set(mSingleton, mActivityManagerProxy);

At this point our dynamic proxy has been implemented. The complete code is as follows:

private void hookAMSAction() throws Exception {
        //动态代理
        Class<?> mIActivityManagerClass;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            mIActivityManagerClass = Class.forName("android.app.IActivityTaskManager");
        } else {
            mIActivityManagerClass = Class.forName("android.app.IActivityManager");
        }
        //获取 ActivityManager 或 ActivityManagerNative 或 ActivityTaskManager
        Class<?> mActivityManagerClass;
        Method getActivityManagerMethod;
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
            mActivityManagerClass = Class.forName("android.app.ActivityManagerNative");
            getActivityManagerMethod = mActivityManagerClass.getDeclaredMethod("getDefault");
        } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q){
            mActivityManagerClass = Class.forName("android.app.ActivityManager");
            getActivityManagerMethod = mActivityManagerClass.getDeclaredMethod("getService");
        } else {
            mActivityManagerClass = Class.forName("android.app.ActivityTaskManager");
            getActivityManagerMethod = mActivityMa

Guess you like

Origin blog.csdn.net/qq_39312146/article/details/134862469