美文网首页
Activity插件化(一)hookIActivityManag

Activity插件化(一)hookIActivityManag

作者: 慕_先生 | 来源:发表于2020-05-25 19:36 被阅读0次

    先上startActivity的流程图和ActivityThread启动activity的流程图,写的代码对照这个流程图就清晰很多了


    startActivity流程图.png
    ActivityThread启动activity流程图.png

    为了让AMS验证通过,需要在AndroidManifest中注册的Activity(StubActivity)占坑,在启动插件Activity(TargetActivity)时替换为占坑Activity(StubActivity),达到一个欺上瞒下的作用,当AMS验证通过之后,需要将启动的占坑Activity(StubActivity)替换为插件Activity(TargetActivity)。

    总的来说有两个步骤
    1.将请求启动的插件TargetActivity替换为占坑StubActivity欺骗AMS通过验证
    2.骗过AMS验证后,将占坑StubActivity替换回插件TargetActivity

    //启动一个TargetActivity
    //但是在AMS验证的时候,是StubActivity给AMS验证
    Intent intent = new Intent(this,TargetActivity.class);
    startActivity(intent);
    

    下面是分析AMS的源码:
    hook的点是IActivityManager和Handler
    先讲hook IActivityManager,先看IActivityManager源码

    public interface IActivityManager extends IInterface {
        public int startActivity(IApplicationThread caller, String callingPackage,
                Intent intent, String resolvedType, IBinder resultTo, String resultWho,
                int requestCode, int flags, String profileFile,
                ParcelFileDescriptor profileFd, Bundle options) throws RemoteException;
        public int startActivityAsUser(IApplicationThread caller, String callingPackage,
                Intent intent, String resolvedType, IBinder resultTo, String resultWho,
                int requestCode, int flags, String profileFile,
                ParcelFileDescriptor profileFd, Bundle options, int userId) throws RemoteException;
        public WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
                Intent intent, String resolvedType, IBinder resultTo, String resultWho,
                int requestCode, int flags, String profileFile,
                ParcelFileDescriptor profileFd, Bundle options, int userId) throws RemoteException;
        public int startActivityWithConfig(IApplicationThread caller, String callingPackage,
                Intent intent, String resolvedType, IBinder resultTo, String resultWho,
                int requestCode, int startFlags, Configuration newConfig,
                Bundle options, int userId) throws RemoteException;
    

    IActivityManager是实现了IInterface接口,可知是通过Binder通讯的,所以我们可以通过动态代理Proxy修改其中的Intent来达到欺骗AMS。
    现在再看看在那里可以获取到IActivityManager的实例(注意:Android O开始重构了AMS代码,所以需要版本兼容)。O以上的版本可以在ActivityManager中获得IActivityManager实例,O以下的版本可以在ActivityManagerNative中获取。

    Android O以上获取IActivityManager:

        public static IActivityManager getService() {
            return IActivityManagerSingleton.get();
        }
    
        private static final Singleton<IActivityManager> IActivityManagerSingleton =
                new Singleton<IActivityManager>() {
                    @Override
                    protected IActivityManager create() {
                        final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                        final IActivityManager am = IActivityManager.Stub.asInterface(b);
                        return am;
                    }
                };
    

    ANdroid O以下获取IActivityManager:

    public abstract class ActivityManagerNative extends Binder implements IActivityManager{
            static public IActivityManager asInterface(IBinder obj) {
            if (obj == null) {
                return null;
            }
            IActivityManager in =
                (IActivityManager)obj.queryLocalInterface(descriptor);
            if (in != null) {
                return in;
            }
            return new ActivityManagerProxy(obj);
        }
        static public IActivityManager getDefault() {
            return gDefault.get();
        }
        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;
            }
        };    
    }
    

    所以我们获取IActivityManager的时候就要判断版本了,再看看两个都用到了Singleton这个类。

    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;
            }
        }
    }
    

    实现获取IActivityManager并代理的代码

    public static void hookActivityManager(final Activity activity){
            try{
                Field gDefaultField;
                if(Build.VERSION.SDK_INT > Build.VERSION_CODES.O){
                    //获取的Singleton<IActivityManager>成员
                    Class<?> amClaz = Class.forName("android.app.ActivityManager");
                    gDefaultField = amClaz.getDeclaredField("IActivityManagerSingleton");
                }else {
                    //获取的Singleton<IActivityManager>成员
                    Class<?> amClaz = Class.forName("android.app.ActivityManagerNative");
                    gDefaultField = amClaz.getDeclaredField("gDefault");
                }
                gDefaultField.setAccessible(true);
                //获取Singleton<IActivityManager> gDefault的真实对象
                Object gDefault = gDefaultField.get(null);
                
                Class singletonClaz = Class.forName("android.util.Singleton");
                Field mInstance = singletonClaz.getDeclaredField("mInstance");
                mInstance.setAccessible(true);
                //获取到了IActivityManager的真实对象 相当于getService或者getDefault
                //gDefault关联Singleton,所以mInstance就是IActivityManager的实例
                final Object iam = mInstance.get(gDefault);
                //获取当前线程的ClassLoader
                ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
                //动态代理的接口
                Class<?> iActivityManagerInterface = Class.forName("android.app.IActivityManager");
                //动态代理IActivityManager的接口
                Object proxy = Proxy.newProxyInstance(classLoader, new Class[]{iActivityManagerInterface},
                                                                     new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //判断调用的方法,如果是startActivity的话,拦截,修改里面的Intent
                        if (method.getName().equals("startActivity")){
                            int index = 0;
                            Intent rawIntent = null;
                            for (int i = 0; i < args.length; i++) {
                                if (args[i] instanceof Intent){
                                    index = i;
                                    rawIntent = (Intent) args[i];
                                    break;
                                }
                            }
                            //把在清单文件中注册的StubActivity给换上去 欺骗AMS
                            Intent newIntent = new Intent();
                            newIntent.setComponent(new ComponentName
                                    (activity.getPackageName(),StubActivity.class.getName()));
                            newIntent.putExtra(TARGET_INTENT,rawIntent);
                            args[index] = newIntent;
                        }
                        //调用方法  相当于iam.startActivity(args)
                        return method.invoke(iam,args);
                    }
                });
                //把修改的后的设置回去
                mInstance.set(gDefault,proxy);
            }catch (Exception e){
                Log.e(TAG, "hookActivityManager: exception" + e.getMessage() );
                e.printStackTrace();
            }
        }
    

    接下来,我们要把这个rawIntent给改回去,所以需要hook Handler,可以从ActivityThread入手,ActivityThread由于也被重构了,所以Android O的上下版本略有不同
    先看源码找思路:
    首先一个app 只有一个ActivityThread 然后就只有一个mH,我们app所有的activity的生命周期的处理都在mH的handleMessage里面处理的。在Android 8.0之前,不同的生命周期对应不同的msg.what处理,在Android 8.0 改成了全部由EXECUTE_TRANSACTION来处理

    public final class ActivityThread extends ClientTransactionHandler {
       static volatile IPackageManager sPackageManager;
        final ApplicationThread mAppThread = new ApplicationThread();
        final Looper mLooper = Looper.myLooper();
        final H mH = new H();
        //ActivityThread 一个app进程 只有一个sCurrentActivityThread
        private static volatile ActivityThread sCurrentActivityThread;
    }
    

    Android O以上在ActivityThread的内部类H中

    class H extends Handler {
            //public static final int LAUNCH_ACTIVITY         = 100;
            //public static final int PAUSE_ACTIVITY          = 101;
            //public static final int PAUSE_ACTIVITY_FINISHING= 102;
            //public static final int STOP_ACTIVITY_SHOW      = 103;
            //public static final int STOP_ACTIVITY_HIDE      = 104;
            //public static final int SHOW_WINDOW             = 105;
            //public static final int HIDE_WINDOW             = 106;
            //public static final int RESUME_ACTIVITY         = 107;
            //public static final int SEND_RESULT             = 108;
            //public static final int DESTROY_ACTIVITY        = 109;
            public static final int BIND_APPLICATION        = 110;
            public static final int EXIT_APPLICATION        = 111;
            public static final int RECEIVER                = 113;
            public static final int CREATE_SERVICE          = 114;
            public static final int SERVICE_ARGS            = 115;
            public static final int STOP_SERVICE            = 116;
            ~~~
            public static final int EXECUTE_TRANSACTION = 159;
            
            public void handleMessage(Message msg) {
                if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
                switch (msg.what) {
                    case EXECUTE_TRANSACTION:
                        final ClientTransaction transaction = (ClientTransaction) msg.obj;
                        mTransactionExecutor.execute(transaction);
                        if (isSystem()) {
                            // Client transactions inside system process are recycled on the client side
                            // instead of ClientLifecycleManager to avoid being cleared before this
                            // message is handled.
                            transaction.recycle();
                        }
                        // TODO(lifecycler): Recycle locally scheduled transactions.
                        break;
                }
            }
    }
    

    Android O以下在ActivityThread的内部类H中

    private class H extends Handler {
            public static final int LAUNCH_ACTIVITY         = 100;
            public static final int PAUSE_ACTIVITY          = 101;
            public static final int PAUSE_ACTIVITY_FINISHING= 102;
            public static final int STOP_ACTIVITY_SHOW      = 103;
            public static final int STOP_ACTIVITY_HIDE      = 104;
            public static final int SHOW_WINDOW             = 105;
            public static final int HIDE_WINDOW             = 106;
            public static final int RESUME_ACTIVITY         = 107;
            public static final int SEND_RESULT             = 108;
            public static final int DESTROY_ACTIVITY        = 109;
            public static final int BIND_APPLICATION        = 110;
            ~~~
             public void handleMessage(Message msg) {
                switch (msg.what) {
                    case LAUNCH_ACTIVITY: {
                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                        final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                      }
                 }
              }
    }
    

    在Android O及以上所有的生命周期都走的是EXECUTE_TRANSACTION,在Android O以下不同的生命周期对应不同的msg.what处理
    下一步,从H也就是Handler入手

    //Handler 源码
     public Handler() {
         this(null, false);
     }
     public Handler(Callback callback) {
         this(callback, false);
     }
    
    public void dispatchMessage(@NonNull Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    

    由于ActivityThread中的H用的是空构造方法new H(),所以mCallback为空。再看dispatchMessage这个方法,会判断mCallback != null,我们可以通过给mCallback赋值,然后在里面做还原操作。
    所以实现还原的操作如下代码:

    public static void hookHandler(){
            try {
                //获取ActivityThread的class
                Class<?> atClass = Class.forName("android.app.ActivityThread");
                //获取ActivityThread里面的成员 sCurrentActivityThread
                Field sCurrentActivityThreadField = atClass.getDeclaredField("sCurrentActivityThread");
                sCurrentActivityThreadField.setAccessible(true);
                //获取sCurrentActivityThread的实例
                //sCurrentActivityThread是一个静态成员,所以get不需要传object,传null就可以了
                Object sCurrentActivityThread = sCurrentActivityThreadField.get(null);
                
                //获取成员mH H继承Handler
                Field mHField = atClass.getDeclaredField("mH");
                mHField.setAccessible(true);
                //获取mH的实例并强转Handler
                final Handler mH = (Handler) mHField.get(sCurrentActivityThread);
                ////获取Handler CallBack
                Field mCallbackField = Handler.class.getDeclaredField("mCallback");
                mCallbackField.setAccessible(true);
    
                //dispatchMessage方法中会判断mCallback是否为空,不为空就调用Callback的handleMessage
                //所以可以在mCallback里面做换回rawIntent的操作
                //给mCallback赋值
                mCallbackField.set(mH, new Handler.Callback() {
                    @Override
                    public boolean handleMessage(@NonNull Message msg) {
                      //launch_activity 两个版本低版本的是 LAUNCH_ACTIVITY = 100
                     //高版本的是 EXECUTE_TRANSACTION = 159
                        switch (msg.what){
                            case 100:{
                                try {
                                    //msg.obj =  ActivityClientRecord
                                    //相当于反射获取ActivityClientRecord的 intent
                                    Field intentField = msg.obj.getClass().getDeclaredField("intent");
                                    intentField.setAccessible(true);
                                    Intent intent = (Intent) intentField.get(msg.obj);
                                    //把存放在intent里面的rawIntent取出来,替换回来
                                    Intent rawIntent = intent.getParcelableExtra(TARGET_INTENT);
                                    intent.setComponent(rawIntent.getComponent());
                                } catch (Exception e) {
                                    Log.e(TAG, "handleMsg 100: Exception" + e.getMessage());
                                    e.printStackTrace();
                                }
                            }
                            break;
                                    //从AndroidP开始重构了状态模式
                                    // 首先一个app 只有一个ActivityThread 然后就只有一个mH
                                    //我们app所有的activity的生命周期的处理都在mH的handleMessage里面处理
                                    //在Android 8.0之前,不同的生命周期对应不同的msg.what处理
                                    //在Android 8.0 改成了全部由EXECUTE_TRANSACTION来处理
                            case 159:{
                                try{
                                    //obj == ClientTransaction
                                    Object obj = msg.obj;
                                    //获取ClientTransaction下的mActivityCallbacks
                                    //private List<ClientTransactionItem> mActivityCallbacks;
                                    //ClientTransactionItem有个子类是LaunchActivityItem,我们需要的是这个子类
                                    Field mActivityCallbacksField = obj.getClass().getDeclaredField("mActivityCallbacks");
                                    mActivityCallbacksField.setAccessible(true);
                                    //获取mActivityCallbacks的实例
                                    List<Object> mActivityCallbacks = (List<Object>) mActivityCallbacksField.get(obj);
                                    Log.e(TAG, "handleMessage: mActivityCallbacks= " + mActivityCallbacks);
                                   
                                    if (mActivityCallbacks.size() > 0 ){
                                        String luanchName = "android.app.servertransaction.LaunchActivityItem";
                                        //LaunchActivityItem是ClientTransactionItem的子类
                                        //  而Intent的信息则存在LaunchActivityItem的mIntent中
                                        if (mActivityCallbacks.get(0).getClass().getCanonicalName().equals(luanchName)){
                                            Object object = mActivityCallbacks.get(0);
                                            Field intentField = object.getClass().getDeclaredField("mIntent");
                                            intentField.setAccessible(true);
                                            Intent intent = (Intent) intentField.get(object);
                                            Intent rawIntent = intent.getParcelableExtra(TARGET_INTENT);
                                            intent.setComponent(rawIntent.getComponent());
    
                                        }
                                    }
                                }catch (Exception e){
                                    Log.e(TAG, "handleMsg 159: Exception" + e.getMessage());
                                    e.printStackTrace();
                                }
                            }
                            break;
                        }
                        //调用mH的handleMessage
                        mH.handleMessage(msg);
                        return true;
                    }
                });
            }catch (Exception e){
                Log.e(TAG, "hookHandler:Exception " + e.getMessage() );
                e.printStackTrace();
            }
        }
    

    接下来调用看效果:

    <!-- TragetActivity并没有在清单文件中 -->
    <activity android:name=".StubActivity" />
    <activity android:name=".MainActivity">
          <intent-filter>
               <action android:name="android.intent.action.MAIN" />
               <category android:name="android.intent.category.LAUNCHER" />
         </intent-filter>
    </activity>
    
    public class MainActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //hook
            HookActivityUtils.hookActivityManager(this);
            HookActivityUtils.hookHandler();
            Intent intent = new Intent(this,TargetActivity.class);
            startActivity(intent);
        }
    }
    
    //TragetActivity布局
    <TextView
            android:textSize="20sp"
            android:text="这是目标activity,TragetActivity"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    //StubActivity布局
    <TextView
            android:textSize="20sp"
            android:text="这个是代理activity,StubActivity"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    
    

    如果看日志的话,会发现mActivityCallbacks.size() == 0,原因是Activity的生命周期方法会回调到EXECUTE_TRANSACTION统一处理,所以启动和销毁都有size == 0的情况

    E/=====: handleMessage: mActivityCallbacks= []
    E/=====: handleMessage: mActivityCallbacks= [WindowVisibilityItem{showWindow=true}]
    E/=====: handleMessage: mActivityCallbacks= [LaunchActivityItem{intent=Intent { cmp=com.simple.bzm0518/.StubActivity (has extras) },ident=68590014,info=ActivityInfo{9ec475a com.simple.bzm0518.StubActivity}]
    E/=====: handleMessage: mActivityCallbacks= []
    
    效果图.png

    还有另外一种简单的方案是Hook Instrumentation,后续再更新
    Github : https://github.com/bzm0518/HookAMS

    相关文章

      网友评论

          本文标题:Activity插件化(一)hookIActivityManag

          本文链接:https://www.haomeiwen.com/subject/yvneahtx.html