Activity插件化(一)hookIActivityManager

先上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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。