插件化讲解到实战3--Hook的源码分析和启动插件的Activity

插件化讲解到实战1–类加载的解析和双亲委派机制
插件化讲解到实战2–调用插件中的类
插件化讲解到实战3–Hook的源码分析和启动插件的Activity
插件化讲解到实战4–启动Activity适配9.0,10.0等版本
Hook中文意思就是钩子,作用就是改变代码的正常执行流程。在某段SDK源码逻辑执行的过程中,通过代码手段拦截执行该逻辑,加入自己的代码逻辑。通过动态代理和反射实现Hook。

查找Hook点的原则:
1、尽量静态变量或者单例对象
2、尽量Hook public 的对象和方法

一方面这两种情况修改的少,另一方面反射的如果不是静态的方法,那么就要拿到方法对应的类的对象。

代码实现启动插件的Activity

启动插件的Activity实际就运用了Hook技术,在AMS检查Activity是否在清单文件注册过之前,把插件PluginActivity换成清单文件中本来有的ProxyActivity,检查之后再换回插件PluginActivity。
在这里插入图片描述在这里插入图片描述

1、启动插件Activity,下一步想如何将插件的Activity换成代理的Activity呢,就是改变intent:

Intent intent = new Intent();
intent.setComponent(new ComponentName("com.enjoy.plugin", "com.enjoy.plugin.MainActivity"));
startActivity(intent);

2、
8.0源码分析如下:
startActivity调用的最终是startActivityForResult,看一下startActivityForResult 的源码:

 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) {
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

看到intent在 mInstrumentation.execStartActivity被调用,这里修改intent的话,mInstrumentation这个对象不是静态的,按照原则我们继续往里找。在Instrumentation的execStartActivity源码如下:

public ActivityResult execStartActivity(
    Context who, IBinder contextThread, IBinder token, String target,
    Intent intent, int requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    if (mActivityMonitors != null) {
        synchronized (mSync) {
            final int N = mActivityMonitors.size();
            for (int i=0; i<N; i++) {
                final ActivityMonitor am = mActivityMonitors.get(i);
                ActivityResult result = null;
                if (am.ignoreMatchingSpecificIntents()) {
                    result = am.onStartActivity(intent);
                }
                if (result != null) {
                    am.mHits++;
                    return result;
                } else if (am.match(who, null, intent)) {
                    am.mHits++;
                    if (am.isBlocking()) {
                        return requestCode >= 0 ? am.getResult() : null;
                    }
                    break;
                }
            }
        }
    }
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        int result = ActivityManager.getService()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target, requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

发现在:

 int result = ActivityManager.getService()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target, requestCode, 0, null, options);

用到了intent变量,ActivityManager.getService()是AMS,我们发现getService()是静态的,是我们要找的Hook点,我们可以在此处通过动态代理修改intent。

ActivityManager.getService()的源码如下:

public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

可以看到,返回的是IActivityManager 对象,所以说实际上调用的startActivity就是IActivityManager 这个类里面的方法,我们直接这么写:

IActivityManager {
、、、、、
startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);

}

动态代理:简单理解为将这个类复制一遍,如下:

IActivityManagerProxy {
、、、、、
startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);

}


动态代理只是简单的创建了IActivityManagerProxy ,但是类的对象如果不把系统的对象替换,那么调用的还是AMS的startActivity。所以要创建一个对象把ActivityManager.getService()的对象替换,替换之后再调用startActivity就是动态代理里面的startActivity。

1、获取系统的IActivityManager 的对象,即mInstance 对象:

// 这两块代码的目的: 为了获取系统的IActivityManager对象,即mInstance -- private IActivityManager mInstance;
// 第一步获取Singleton对象,是为了获取下一步非静态的变量,要先获取这个变量的类的对象Singleton对象
Class<?> clazz = Class.forName("android.app.ActivityManager");
Field iActivityManagerSingletonField = clazz.getDeclaredField("IActivityManagerSingleton");
iActivityManagerSingletonField.setAccessible(true);
Object singleton = iActivityManagerSingletonField.get(null);

//第二步,拿到 mInstance 对象  ---》 IActivityManager对象
Class<?> signletonClass = Class.forName("android.util.Singleton");
Field mInstanceField = signletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
final Object mInstance = mInstanceField.get(singleton);

2、创建代理对象,修改intent:

 Class<?> iActivityManagerClass = Class.forName("android.app.IActivityManager");
            //newProxyInstance()参数:第一个类加载器,第二个参数动态代理要替换的class对象,即IActivityManager对象,第三个参数是回调invoke()方法,只要系统调用了IActivityManager对象的任何方法都会执行一次invoke()
            Object mInstanceProxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                    new Class[]{iActivityManagerClass}, new InvocationHandler() {
                        @Override
                        public Object invoke(Object o, Method method, Object[] objects) throws Throwable {


                            /**
                             * startActivity(whoThread, who.getBasePackageName(), intent,
                             *                         intent.resolveTypeIfNeeded(who.getContentResolver()),
                             *                         token, target != null ? target.mEmbeddedID : null,
                             *                         requestCode, 0, null, options);
                             */
                            //只有方法是startActivity的时候才回去处理,修改intent
                            if ("startActivity".equals(method.getName())) {
                                // 修改Intent

                                int index = 0;
                               //startActivity可能有重写的几种方法,所以遍历一下
                                for (int i = 0; i < objects.length; i++) {
                                    if (objects[i] instanceof Intent) {
                                        index = i;
                                        break;
                                    }
                                }
                                // 启动插件的intent
                                Intent intent = (Intent) objects[index];

                                // 改成启动代理Intent
                                Intent intentProxy = new Intent();
                                intentProxy.setClassName("com.enjoy.leo_plugin",
                                        "com.enjoy.leo_plugin.ProxyActivity");
                                intentProxy.putExtra(TARGET_INTENT, intent);

                                objects[index] = intentProxy;
                            }


                            // 第一个参数:系统的IActivityManager对象
                            return method.invoke(mInstance, objects);
                        }
                    });

3、代理对象替换系统对象

  // 用代理对象替换系统的IActivityManager对象 ---> field
            //  mInstanceProxy --> 替换系统的 IActivityManager对象  ---》 反射去实现
            // mInstance = mInstanceProxy
            mInstanceField.set(singleton, mInstanceProxy);

到此,这三步实现了第一次Hook的替换,即把插件PluginActivity换成清单文件中本来有的ProxyActivity。下面来看ProxyActivity在AMS出来的时候替换PluginActivity。
在这里插入图片描述ActivityThread的scheduleLaunchActivity的源码如下:

@Override
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

            updateProcessState(procState, false);

            ActivityClientRecord r = new ActivityClientRecord();

            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.referrer = referrer;
            r.voiceInteractor = voiceInteractor;
            r.activityInfo = info;
            r.compatInfo = compatInfo;
            r.state = state;
            r.persistentState = persistentState;

            r.pendingResults = pendingResults;
            r.pendingIntents = pendingNewIntents;

            r.startsNotResumed = notResumed;
            r.isForward = isForward;

            r.profilerInfo = profilerInfo;

            r.overrideConfig = overrideConfig;
            updatePendingConfiguration(curConfig);

            sendMessage(H.LAUNCH_ACTIVITY, r);
        }

看到会执行到sendMessage(H.LAUNCH_ACTIVITY, r); H是继承的Handler,那么看H里面的LAUNCH_ACTIVITY是如何执行的。
在这里插入图片描述如下:

    public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
                ///省略无关代码
}}

到这里可以看到,系统调用出来AMS之后,就会执行handleLaunchActivity方法。

我们是要找方便替换的intent,继续找,handleLaunchActivity源码如下:

  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        if (r.profilerInfo != null) {
            mProfiler.setProfiler(r.profilerInfo);
            mProfiler.startProfiling();
        }

        // Make sure we are running with the most recent config.
        handleConfigurationChanged(null, null);

        if (localLOGV) Slog.v(
            TAG, "Handling launch of " + r);

        // Initialize before creating the activity
        WindowManagerGlobal.initialize();

        Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

            if (!r.activity.mFinished && r.startsNotResumed) {
                   performPauseActivityIfNeeded(r, reason);
                if (r.isPreHoneycomb()) {
                    r.state = oldState;
                }
            }
        } else {
            try {
                ActivityManager.getService()
                    .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }

然后进入performLaunchActivity:

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");

        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }

        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }
///省略无关代码
}

找到了intent,往上找发现

 static final class ActivityClientRecord {
        IBinder token;
        int ident;
        Intent intent;
        String referrer;
        ///省略无关代码

即ActivityClientRecord.intent,我们看能不能获取到ActivityClientRecord的对象,那么就拿到了intent。

继续看源码,一级级往上找ActivityClientRecord的来源:
从performLaunchActivity,往上看到handleLaunchActivity传进来的ActivityClientRecord
在这里插入图片描述继续找handleMessage,发现ActivityClientRecord 就是msg.obj,如果能拿到msg就可以了。

 public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
                ///省略无关代码

看一下Handler的源码:

 public interface Callback {
        public boolean handleMessage(Message msg);
    }
    
    /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }
    
    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

可以看到handleMessage是继承Handler必须重写的,handleMessage在dispatchMessage()调用。其实handler流程当setMessage去发送消息的时候,会执行到dispatchMessage(),dispatchMessage会执行handleMessage,然后跑到ActivityThread的handleMessage里面。

dispatchMessage中的mCallback 一般是空的,我们创建一个去替换系统的mCallback ,那么mCallback 不为空的话,会执行mCallback.handleMessage(msg),也就拿到了msg,可以进行修改,相当于修改了 handleMessage(msg);中的msg,也就是修改了msg.obj中的msg。

Callback–>创建一个Callback对象,替换系统的Callback–>反射
反向流程:
Callback.msg->handleMessage(msg)->msg.obj->获取ActivityClientRecord的对象->intent
其实就是:

//系统的Callback对象 --》 mh对象 --》 ActivityThread对象 — 》
// private static volatile ActivityThread sCurrentActivityThread;

继续写代码:

4、拿到mH 对象和系统的mCallbackField :

 // sCurrentActivityThread
        Class<?> clazz = Class.forName("android.app.ActivityThread");
        Field sCurrentActivityThreadField = clazz.getDeclaredField("sCurrentActivityThread");
        sCurrentActivityThreadField.setAccessible(true);
        Object activityThread = sCurrentActivityThreadField.get(null);

        // mh对象
        Field mHField = clazz.getDeclaredField("mH");
        mHField.setAccessible(true);
        Handler mH = (Handler) mHField.get(activityThread);

        Class<?> handlerClass = Class.forName("android.os.Handler");
        Field mCallbackField = handlerClass.getDeclaredField("mCallback");
        mCallbackField.setAccessible(true);

5、创建Callback,修改intent

Handler.Callback callback = new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message message) {
            switch (message.what) {
                //H中LAUNCH_ACTIVITY=100
                case 100:
                    // 拿到了message
                    // ActivityClientRecord的对象 --- msg.obj
                    try {
                        //拿到intent的field对象
                        Field intentField = message.obj.getClass().getDeclaredField("intent");
                        //设置作用域
                        intentField.setAccessible(true);
                        //  启动代理 intent
                        Intent intentProxy = (Intent) intentField.get(message.obj);
                        // 启动插件的intent
                        Intent intent = intentProxy.getParcelableExtra(TARGET_INTENT);
                        if (intent != null) {
                            intentField.set(message.obj, intent);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    break;
            }
            return false;
        }
    };

6、把系统的callback 设置为自己创建的callback

   // 系统的callback = 自己创建的callback
            mCallbackField.set(mH, callback);

完整代码:

HookUtil.java:

import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;

import androidx.annotation.NonNull;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class HookUtil {

    private static String TARGET_INTENT = "target_Intent";

    public static void hookAMS() {

        // 动态代理需要替换的是IActivityManager
        try {

            // 目的: 为了获取系统的IActivityManager对象 -- private IActivityManager mInstance;
            // Singleton对象
            Class<?> clazz = Class.forName("android.app.ActivityManager");
            Field iActivityManagerSingletonField = clazz.getDeclaredField("IActivityManagerSingleton");
            iActivityManagerSingletonField.setAccessible(true);
            Object singleton = iActivityManagerSingletonField.get(null);

            // mInstance 对象  ---》 IActivityManager对象
            Class<?> signletonClass = Class.forName("android.util.Singleton");
            Field mInstanceField = signletonClass.getDeclaredField("mInstance");
            mInstanceField.setAccessible(true);
            final Object mInstance = mInstanceField.get(singleton);

            Class<?> iActivityManagerClass = Class.forName("android.app.IActivityManager");
            //newProxyInstance()参数:第一个类加载器,第二个参数动态代理要替换的class对象,即IActivityManager对象,第三个参数是回调invoke()方法,只要系统调用了IActivityManager对象的任何方法都会执行一次invoke()
            Object mInstanceProxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                    new Class[]{iActivityManagerClass}, new InvocationHandler() {
                        @Override
                        public Object invoke(Object o, Method method, Object[] objects) throws Throwable {


                            /**
                             * startActivity(whoThread, who.getBasePackageName(), intent,
                             *                         intent.resolveTypeIfNeeded(who.getContentResolver()),
                             *                         token, target != null ? target.mEmbeddedID : null,
                             *                         requestCode, 0, null, options);
                             */
                            //只有方法是startActivity的时候才回去处理,修改intent
                            if ("startActivity".equals(method.getName())) {
                                // 修改Intent

                                int index = 0;
                                //startActivity可能有重写的几种方法,所以遍历一下
                                for (int i = 0; i < objects.length; i++) {
                                    if (objects[i] instanceof Intent) {
                                        index = i;
                                        break;
                                    }
                                }
                                // 启动插件的intent
                                Intent intent = (Intent) objects[index];

                                // 改成启动代理Intent
                                Intent intentProxy = new Intent();
                                intentProxy.setClassName("com.enjoy.leo_plugin",
                                        "com.enjoy.leo_plugin.ProxyActivity");
                                intentProxy.putExtra(TARGET_INTENT, intent);

                                objects[index] = intentProxy;
                            }


                            // 第一个参数:系统的IActivityManager对象
                            return method.invoke(mInstance, objects);
                        }
                    });
            // 用代理对象替换系统的IActivityManager对象 ---> field
            //  mInstanceProxy --> 替换系统的 IActivityManager对象  ---》 反射去实现
            // mInstance = mInstanceProxy
            mInstanceField.set(singleton, mInstanceProxy);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void hookHandler() {

        //系统的Callback对象 --》 mh对象 --》 ActivityThread对象 --- 》
        // private static volatile ActivityThread sCurrentActivityThread;

        try {
            // sCurrentActivityThread
            Class<?> clazz = Class.forName("android.app.ActivityThread");
            Field sCurrentActivityThreadField = clazz.getDeclaredField("sCurrentActivityThread");
            sCurrentActivityThreadField.setAccessible(true);
            Object activityThread = sCurrentActivityThreadField.get(null);

            // mh对象
            Field mHField = clazz.getDeclaredField("mH");
            mHField.setAccessible(true);
            Handler mH = (Handler) mHField.get(activityThread);

            Class<?> handlerClass = Class.forName("android.os.Handler");
            Field mCallbackField = handlerClass.getDeclaredField("mCallback");
            mCallbackField.setAccessible(true);

            Handler.Callback callback = new Handler.Callback() {
                @Override
                public boolean handleMessage(@NonNull Message message) {
                    switch (message.what) {
                        //H中LAUNCH_ACTIVITY=100
                        case 100:
                            // 拿到了message
                            // ActivityClientRecord的对象 --- msg.obj
                            try {
                                //拿到intent的field对象
                                Field intentField = message.obj.getClass().getDeclaredField("intent");
                                //设置作用域
                                intentField.setAccessible(true);
                                //  启动代理 intent
                                Intent intentProxy = (Intent) intentField.get(message.obj);
                                // 启动插件的intent
                                Intent intent = intentProxy.getParcelableExtra(TARGET_INTENT);
                                if (intent != null) {
                                    intentField.set(message.obj, intent);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }

                            break;
                    }
                    return false;
                }
            };

            // 系统的callback = 自己创建的callback
            mCallbackField.set(mH, callback);

        } catch (Exception e) {
            e.printStackTrace();
        }


        // 用我们创建的Callback对象,替换系统的Callback对象
    }


}

MyApplication.java:

import android.app.Application;

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

         HookUtil.hookAMS();
        HookUtil.hookHandler();

    }
}

本篇基于8.0,下一篇会适配其他。

本篇基于8.0,下一篇会适配其他。

本篇基于8.0,下一篇会适配其他。

参考:
https://www.jianshu.com/p/74c12164ffca

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值