Hook技术之Activity启动流程(android 9.0)

3,672 阅读6分钟

一. 前言

本文部分内容来自于《android进阶解密》这本书,不同的是书中实现的是android9.0之前的hook,在android9.0中,activity的启动过程会有些不同,因此本文不会对activity启动流程做具体分析,主要是讲解9.0的hook.

二. 寻找hook点

这里需要寻找两个地方的hook点,一个是对Intent中Activity的替换,一个是对Intent中Activity的还原

1. Activity替换

android8和9启动流程中,到获得AMS进行远程调用的过程都是一样的,这里可以对AMS进行动态代理,也可以对Instrumentation进行代理,android8中对AMS的hook过程和9有点不一样,网上有太多对android8的AMS的hook文章,这里只介绍对9的处理
AMS的代理类

public class IActivityManagerProxy implements InvocationHandler {
    private Object activityManager;
    private static final String TAG="IActivityManagerProxy";
    public IActivityManagerProxy(Object activityManager){
        this.activityManager=activityManager;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(method.getName().equals("startActivity")){
            Intent intent =null;
            int index=0;
            for(int i=0;i<args.length;i++){
                if(args[i] instanceof Intent){
                    index=i;
                    break;
                }
            }
            intent = (Intent) args[index];
            String packageName = "com.suny.hooktest";
            Intent subIntent = new Intent();
            //替换activity为已经注册的占坑activity,这里第一个参数为application所在的包,第二//个参数为Activity所在的包+activityName
            subIntent.setClassName(packageName,packageName+".SubActivity");
            //同时将真正的intent保存在subintent中,绕过AMS的检查后,将真正的intent替换回来
            subIntent.putExtra("target_intent",intent);
            args[index]=subIntent;
            Log.d(TAG, "invoke: subIntent="+subIntent+"inteent="+intent);
        }
        return method.invoke(activityManager,args);
    }
}

hook操作

public class HookHelper {
    public static void hookAms() throws Exception {
        Class clazz = ActivityManager.class;
        Field singletonIAMS = clazz.getDeclaredField("IActivityManagerSingleton");
        singletonIAMS.setAccessible(true);
        Object defultSingleton = singletonIAMS.get(null);
        Class singletonClazz = Class.forName("android.util.Singleton");
        Field mInstance = singletonClazz.getDeclaredField("mInstance");
        mInstance.setAccessible(true);
        Object iAMs = mInstance.get(defultSingleton);
        Class iAmClazz =Class.forName("android.app.IActivityManager");
        Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class[]{iAmClazz},new IActivityManagerProxy(iAMs));
        mInstance.set(defultSingleton,proxy);
    }
}

2. Activity还原

对启动流程不做更多分析,在启动过程中,由于是通过AMS跨进程调用的,所以最后一步都是ActivityStackSupervisor中相关方法,通过ApplicationThread进行跨进程调用

private class ApplicationThread extends IApplicationThread.Stub

如果你对aidl熟悉的话,你可以看到,这和aidl帮我们生成的类的结构一样

(1). 8.0中的处理

ActivityStackSupervisor通过调用realStartActivityLocked

final boolean realStartActivityLocked (...) {
    ...
    app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
        System.identityHashCode(r), r.info,
        // TODO: Have this take the merged configuration instead of separate global
        // and override configs.
        mergedConfiguration.getGlobalConfiguration(),
        mergedConfiguration.getOverrideConfiguration(), r.compat,
        r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
        r.persistentState, results, newIntents, !andResume,
        mService.isNextTransitionForward(), profilerInfo);
    ...
}

AppThreadApplication通过handle发送了一条消息

public final void scheduleLaunchActivity(...) {
    ...
    sendMessage(H.LAUNCH_ACTIVITY, r);
    ...
}

对消息的处理

public void handleMessage(Message msg) {
        
    switch (msg.what) {
        case LAUNCH_ACTIVITY: {
            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;
        ...

可以看到在Android8中,对Activity的还原可以在这里进行,因为ActivityClientRecord中包含有 intent这个变量

(2) 9.0中的处理

intent的查找

ActivityStackSupervisor通过调用realStartActivityLocked

final boolean realStartActivityLocked (...) {
    ...
    clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                        r.persistentState, results, newIntents, mService.isNextTransitionForward(),
                        profilerInfo));
     // Schedule transaction.
    mService.getLifecycleManager().scheduleTransaction(clientTransaction);
    ...
}

mService.getLifecycleManager()即为ClientLifecycleManager,ClientLifecycleManager.scheduleTrasaction方法的调用过程

void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    //注意这个 Client,即为ApplicationThread
    final IApplicationThread client = transaction.getClient();
    transaction.schedule();
    if (!(client instanceof Binder)) {
        // If client is not an instance of Binder - it's a remote call and at this point it is
        // safe to recycle the object. All objects used for local calls will be recycled after
        // the transaction is executed on client in ActivityThread.
        transaction.recycle();
    }
}

里边调用了ClientTransactionschedule方法

public void schedule() throws RemoteException {
    mClient.scheduleTransaction(this);
}

mClient即为ApplicationThread,这样调用过程又通过跨进程的方法调用,回到本地了

public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    ActivityThread.this.scheduleTransaction(transaction);
}

这里ActivityThread继承了ClientTransactionHandler,也是通过handler发送了一条消息

void scheduleTransaction(ClientTransaction transaction) {
    transaction.preExecute(this);
    sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}

接着看消息的处理过程

public void handleMessage(Message msg) {
    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;
}

这里可以看到和8中消息处理已经不太一样了,查看ClientTransaction,这个类中并没有intent这个字段,不过,intent肯定在其中,不然ActivityThread怎么进行解析呢,沿着方法调用查找,TransactionExecutorexecute方法

public void execute(ClientTransaction transaction) {
    ...
    executeCallbacks(transaction);
    executeLifecycleState(transaction);
    ...
}

executeCallbacks方法中

public void executeCallbacks(ClientTransaction transaction) {
    ...
    final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
    ...
    for (int i = 0; i < size; ++i) {
        ...
        final ClientTransactionItem item = callbacks.get(i);
        ...
        item.execute(mTransactionHandler, token, mPendingActions);
        item.postExecute(mTransactionHandler, token, mPendingActions);
        ...
    }
}

我们发现item.execute()可能是启动流程中的一个关键方法,在这里边可能会去调用ActivityThread的相关方法来完成Activity的创建工作,但是这个ClientTransactionItem是一个抽象类,必须要找到他的一个实现类

public abstract class ClientTransactionItem implements BaseClientRequest, Parcelable

还记得9的启动过程中吗,在ActivityStackSupervisor中的realStartActivityLocked方法中在调用scheduleTransaction之前有这个一段代码

final boolean realStartActivityLocked (...) {
    ...
    clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                        r.persistentState, results, newIntents, mService.isNextTransitionForward(),
                        profilerInfo));
     // Schedule transaction.
    mService.getLifecycleManager().scheduleTransaction(clientTransaction);
    ...
}

可以看到clientTransaction添加了一个LaunchActivityItem的实现类,并且把intent,放进了这个实现类中。
总结一下:
在9中,intent是在ClientTransactionList<ClientTransactionItem> mActivityCallbacks这个成员变量中元素的一个实现类LaunchActivityItem的成员变量中

hook操作将intent还原

主要是对ActivityThread中的Handler(mH)成员变量进行hook,设置一个callback

public class HookHelper {
    public static void hookHandler() throws Exception{
        Class acThreadClazz = Class.forName("android.app.ActivityThread");
        Field currentActivityThread = acThreadClazz.getDeclaredField("sCurrentActivityThread");
        currentActivityThread.setAccessible(true);
        Object currThread = currentActivityThread.get(null);
        Field mHField = acThreadClazz.getDeclaredField("mH");
        mHField.setAccessible(true);
        Handler mH = (Handler) mHField.get(currThread);
        Field mCallback = Handler.class.getDeclaredField("mCallback");
        mCallback.setAccessible(true);
        //为mH,添加mCallback,那么mH在handleMessage时,就会走我们自己定义的callback中的handleMessage方法
        mCallback.set(mH,new HCallback(mH));
    }
}

问题:在ActivityThreadsCurrentActivityThread虽然是静态变量,但是初始值是null,会导致我们通过反射获取到的值为null吗?
答案是不会,初始化时我们一般最早会在applicationattachBaseContext中进行初始化,而sCurrentActivityThread的赋值,是在ActivityThreadmain方法中,通过attach方法进行赋值,而application的创建在赋值之后

 private void attach(boolean system) {
    //赋值
    sCurrentActivityThread = this;
    ...
    //application的创建在这里,又是一次远程调用后,会调用bindApplication方法,
    //进行ContentProvider的初始化,和application的创建,随便提一下,在这里可以看出
    //ContentProvider的onCreate在Application的onCreate之前执行,
    //但是Application的attachBaseContext在ContentProvider的onCreate之前执行
    try {
        mgr.attachApplication(mAppThread);
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
}

HCallbck

public class HCallback implements Handler.Callback{
    private final String TAG="HCallback";
    private Handler mHandler;
    public HCallback(Handler handler){
        mHandler=handler;
    }
    @Override
    public boolean handleMessage(Message msg) {
        //这里为159,是因为EXECUTE_TRANSACTION字段的值为159
        if(msg.what==159){
            //r实际为clienttransaction
            Object r= msg.obj;
            try {
                Class clientClazz = r.getClass();
                Field fCallbacks = clientClazz.getDeclaredField("mActivityCallbacks");
                fCallbacks.setAccessible(true);
                //得到transactionz中的callbacks,为一个list,其中元素为LaunActivityItem
                List<?> lists = (List) fCallbacks.get(r);
                for(int i=0;i<lists.size();i++){
                    Object item = lists.get(i);
                    Class itemClazz = item.getClass();
                    //拿到LaunActivityItem中的intent,进行替换
                    Field mIntent = itemClazz.getDeclaredField("mIntent");
                    mIntent.setAccessible(true);
                    Intent intent = (Intent) mIntent.get(item);
                    Intent target = intent.getParcelableExtra("target_intent");
                    if(target!=null){
                        intent.setComponent(target.getComponent());
                    }
                }
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        mHandler.handleMessage(msg);
        return true;
    }
}

最后

在application中初始化即可

public class MyApplication extends Application {
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        try {
            HookHelper.hookAms();
            HookHelper.hookHandler();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

三. 思考

其实hookActivity主要就是绕过AMS的验证,因此在调用AMS的startActivity方法之前,都可以进行intent的替换,在AMS过后都可以进行intent的还原,因此有很多种hook方法,比如hook,Instrumatention进行intent的替换,对于intent的还原,目前我只想到在handlerMeassage中进行还原,因为ActivityThread中有一个静态变量sCurrentActivityThread,可以获取activitythread对象,从而可以改变mH这个变量,或许还有更好的hook点