android hook源码绕过AndroidManifest跳转Activity

1,542 阅读8分钟

通过hook系统源码,绕过AndroidManifest检测,亲测支持 android5.0~android 10.0系统(文末有 github 地址)

要绕过AndroidManifest检测就得先明白activity的跳转流程,从Activity的源码中可以看到所有的startActivity方法最终都走到了startActivityForResult();

![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a6241b257aba40aba7aca75c7279fa5f~tplv-k3u1fbpfcp-zoom-1.image)

继续到Instrumentation类跟进一下execStartActivity()

	 public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    Uri referrer = target != null ? target.onProvideReferrer() : null;
    if (referrer != null) {
        intent.putExtra(Intent.EXTRA_REFERRER, referrer);
    }
    if (mActivityMonitors != null) {
        synchronized (mSync) {
            final int N = mActivityMonitors.size();
            for (int i=0; i<N; i++) {
                final ActivityMonitor am = mActivityMonitors.get(i);
                if (am.match(who, null, intent)) {
                    am.mHits++;
                    if (am.isBlocking()) {
                        return requestCode >= 0 ? am.getResult() : null;
                    }
                    break;
                }
            }
        }
    }
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        // 注释 1 android api 25 Instrumentation源码
        int result = ActivityManagerNative.getDefault()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

在注释1处,android系统通过ActivityManagerNative.getDefault()获取到一个IActivityManager接口,然后调用了这个接口的startActivity()方法。这里的IActivityManager接口实际上就是AMS,activity的检查将会在AMS中进行。

在AMS检查完毕后,AMS会执行到ActivityStackSupervisor类中的scheduleLaunchActivity方法,就是通过这个方法回调到ActivityThread,然后在ActivityThread中去启动具体的Activity

具体AMS的调度流程可以参考:blog.csdn.net/kc58236582/…

那么activity启动的整体流程可以概括为

	app进程 > AMS进程(AndroidManifest检测) > app进程

按照上面的流程来看,我们只需要在进入AMS之前把一个已经注册过的activity传给AMS就能骗过AMS的AndroidManifest检测,然后在回到app进程的时候,将原本要跳转的activity替换回来就能实现绕过AMS的AndroidManifest检测。

代码需要hook两个地方,一个ams入口处,一个ams出口处,由于android系统每个版本之间源码有差异所以需要做根据系统差异做兼容。

目前将android 5.0android7.1分为一个版本,android8.0android9.0分为一个版本,android10.0分为一个版本。

android 5.0~android7.1 版本:

通过反射得到AMS和ActivityManagerNative中的gDefault属性

	if (OSVersion.isAndroidOS_21_22_23_24_25()) {  //android 低版本 21~25
        Class mActivityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");

        Method getDefault = mActivityManagerNativeClass.getDeclaredMethod("getDefault");
        getDefault.setAccessible(true);
        mIActivityManager = getDefault.invoke(null); //得到ams对象

        Field gDefault = mActivityManagerNativeClass.getDeclaredField("gDefault");
        gDefault.setAccessible(true);
        mSingleton = gDefault.get(null); //得到当前ActivityManagerNative中的singleton属性

    }
    
    

通过动态代理得到一个android.app.IActivityManager的代理对象,AMS实现了IActivityManager这个接口。

在这代理对象中,我们将startActivity方法进行hook,将其中的intent参数替换成已经在AndroidManifest中注册过的proxyActivity,并将原本的intent通过参数的方式带过去

if (OSVersion.isAndroidOS_26_27_28() || OSVersion.isAndroidOS_21_22_23_24_25()) {
        Class mIActivityManagerProxy = Class.forName("android.app.IActivityManager"); // hook系统的IActivityManager
        final Object finalMIActivityManager = mIActivityManager;  // 这个其实就是AMS对象
        Object proxy = Proxy.newProxyInstance(context.getClassLoader(), new Class[]{mIActivityManagerProxy}, new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
            	// 如果是startActivity方法
                if ("startActivity".equals(method.getName())) {
                	//创建一个intent,使用AndroidManifest中已经注册过的ProxyActivity
                    //来绕过AMS的检测
                    //代理activity的intent
                    Intent proxyIntent = new Intent(context, ProxyActivity.class);
                    //目标activity的intent
                    Intent target = (Intent) objects[2];
                    //将startActivity方法的第三个参数替换成代理intent
                    objects[2] = proxyIntent;
                    //将原本的intent通过putExtra的方式添加到代理intent的参数中
                    proxyIntent.putExtra("target", target);
                }
                //用反射得到的AMS去执行startActivity方法
                return method.invoke(finalMIActivityManager, objects);
            }
        });
    }

然后将代理对象设置给 ActivityManagerNative类中的gDefault属性中的mInstance属性(这一段比较绕,需要结合 android.app.ActivityManagerNative 类和 android.util.Singleton 这个类源码才好理解)

        /**
         * 将Ams对象中的singleton属性设置为动态代理对象
         */
        //得到singleton类
        Class mSingletonClass = Class.forName("android.util.Singleton");
        //得到singleton属性
        Field mInstance = mSingletonClass.getDeclaredField("mInstance");
        mInstance.setAccessible(true);
        //把Ams中的singleton设置为动态代理对象
        mInstance.set(mSingleton, proxy);
        

到这里AMS的入口处我们就hook完毕了,接下来再看看如何将proxyIntnet在ActivityThread中还原成原本的targetIntent

通过反射获取ActivityThread对象,并获取到其中的Handler对象mH

	 //获取ActivityThread对象
    Class mActivityThreadClass = Class.forName("android.app.ActivityThread");
    Field mActivityThreadField = mActivityThreadClass.getDeclaredField("sCurrentActivityThread");
    mActivityThreadField.setAccessible(true);
    Object mActivityThread = mActivityThreadField.get(null); //此时获取到的就是真正的ActivityThread对象
    
    
     //  获取Handler对象
    Field mHField = mActivityThreadClass.getDeclaredField("mH");
    mHField.setAccessible(true);
    Handler mH = (Handler) mHField.get(mActivityThread);//通过当前ActivityThread对象获取mH对象
    

在android5.0~android7.1的版本中ActivityThread是通过

	public static final int LAUNCH_ACTIVITY         = 100;
    

这个msg.what来启动一个activity的,来看看LAUNCH_ACTIVITY中做了些什么操作:

	 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;
            

在LAUNCH_ACTIVITY中通msg.obj得到了一个ActivityClientRecord,ActivityClientRecord中就记录着activity的所有信息,我们需要通过ActivityClientRecord获取到intent,并将其替换成原本的targetIntent

那我们就来替换一下ActivityClientRecord吧,在替换ActivityClientRecord之前,我们要hook一下Handler.callback这个接口,因为Handler源码中有个dispatchMessage方法,是用来分发消息的,我们要将ActivityThread中的mH这个handler中的callback方法替换成我们自己的callback,以便处理LAUNCH_ACTIVITY消息

	public void dispatchMessage(Message msg) {
    /**
     *  如果msg中自带callback不为空执行callback中的方法
     */

    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        //如果Handler的回调不为空
        if (mCallback != null) {
            // 执行Handler的回调
            if (mCallback.handleMessage(msg)) {
                // 如果是使用callback的方式,并在callback中返回true,在这里就会直接return,不会执行Handler的重载方法
                return;
            }
        }
        // 执行Handler的重载方法
        handleMessage(msg);
    }
}

替换Handler中的callback

	 //设置Handler中的callback
    Field mCallbackField = Handler.class.getDeclaredField("mCallback");
    mCallbackField.setAccessible(true);
    if (OSVersion.isAndroidOS_21_22_23_24_25()) {
    	//给ActivityThread中的mH设置callback
        mCallbackField.set(mH, new MyCallback_21_22_23_24_25());
    }
    

自定义的Handler.Callback,在callback中替换intent

	private static final class MyCallback_21_22_23_24_25 implements Handler.Callback {

    @Override
    public boolean handleMessage(Message msg) {
        if (msg.what == 100) {
            try {
                Object mActivityClientRecord = msg.obj; //得到mActivityClientRecord对象
                Field intentField = mActivityClientRecord.getClass().getDeclaredField("intent");
                intentField.setAccessible(true);
                Intent proxyIntent = (Intent) intentField.get(mActivityClientRecord);
                Intent targetIntent = proxyIntent.getParcelableExtra("target");
                if (targetIntent != null) {
                    intentField.set(mActivityClientRecord, targetIntent);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //这里记得要returen false 让handler继续执行下去
        return false;
    }
}

到这里android5.0~android7.1的绕过AndroidManifest注册就完成了,但是在android8.0到android9.0源码变了,需要做兼容。

android 8.0~android9.1 版本:

首先是ams的hook,源码中的方法名和属性名称都发生了变化,主要的类也发生了变化。

代码不在android.app.ActivityManagerNative类中了,放到了android.app.ActivityManager类中

代码中也要做相应的兼容

	 else if (OSVersion.isAndroidOS_26_27_28()) {  //android 高版本 26~28
        //反射 android.app.ActivityManager 类
        Class mActivityManagerClass = Class.forName("android.app.ActivityManager");
        //获取 getService 方法
        Method mGetServiceMethod = mActivityManagerClass.getMethod("getService");
        mGetServiceMethod.setAccessible(true);
        mIActivityManager = mGetServiceMethod.invoke(null);


		// 获取IActivityManagerSingleton属性
        Field iActivityManagerSingletonField =
                mActivityManagerClass.getDeclaredField("IActivityManagerSingleton");
        iActivityManagerSingletonField.setAccessible(true);
        mSingleton = iActivityManagerSingletonField.get(null);
    }
    

AMS入口处的hook还好搞,但是AMS的出口处ActivityThread的代码变动得就有点多了

首先 LAUNCH_ACTIVITY 没了

然后ActivityClientRecord也没了。。。。

但是有一个

	public static final int EXECUTE_TRANSACTION = 159;
    

看下 EXECUTE_TRANSACTION 执行了啥

	 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;
                

ClientTransaction是什么鬼,点进去看一下

发现ClientTransaction中有个mActivityCallbacks属性,还是个list,list类型为ClientTransactionItem,继续看ClientTransactionItem是个什么鬼

public abstract class ClientTransactionItem implements BaseClientRequest, Parcelable {

    /** Get the state that must follow this callback. */
    @LifecycleState
    public int getPostExecutionState() {
        return UNDEFINED;
    }


  // Parcelable

  @Override
  public int describeContents() {
      return 0;
  }
  

嗯?是个抽象类,那再看看那些类实现了这个抽象类,全局搜索一下ClientTransactionItem

看到LaunchActivityItem继承了这个抽象类,哦豁,名字都叫LaunchActivity了,应该是这里了,点进去看一眼

果然在LaunchActivityItem中发现了熟悉的intent属性,接下来进行替换targetIntent操作

Handler还是那个Handler,把自定义的callback改一下

     if (OSVersion.isAndroidOS_21_22_23_24_25()) {
     	//低版本的callback
        mCallbackField.set(mH, new MyCallback_21_22_23_24_25());
    } else if (OSVersion.isAndroidOS_26_27_28() || OSVersion.isAndroidOS_29()) {
    	//高版本的callback
        mCallbackField.set(mH, new MyCallback_26_27_28());
    }
    

高版本的自定义callback

 /**
 * android 26~28的Handler回调
 */
private static final class MyCallback_26_27_28 implements Handler.Callback {

    @Override
    public boolean handleMessage(Message msg) {
        if (msg.what == 159) { // EXECUTE_TRANSACTION
            try {
                Object mClientTransaction = msg.obj; //得到ClientTransaction对象

                Class mClientTransactionClass = Class.forName("android.app.servertransaction.ClientTransaction");
                Field mActivityCallbacksField = mClientTransactionClass.getDeclaredField("mActivityCallbacks");
                mActivityCallbacksField.setAccessible(true);
                //得到mActivityCallbacks属性
                List mActivityCallbacks = (List) mActivityCallbacksField.get(mClientTransaction);
                //做一下空判断
                if (mActivityCallbacks.size() == 0) {
                    return false;
                }
                //获取到第一个mActivityCallback
                Object mLaunchActivityItem = mActivityCallbacks.get(0);
                Class mLaunchActivityItemClass = Class.forName("android.app.servertransaction.LaunchActivityItem");
                //做一下校验,看是不是属于LaunchActivityItem
                if (mLaunchActivityItemClass.isInstance(mLaunchActivityItem)) {
                    //intent 替换操作
                    Field intentField = mLaunchActivityItemClass.getDeclaredField("mIntent");
                    intentField.setAccessible(true);
                    Intent proxyIntent = (Intent) intentField.get(mLaunchActivityItem);
                    Intent targetIntent = proxyIntent.getParcelableExtra("target");
                    if (targetIntent != null) {
                        intentField.set(mLaunchActivityItem, targetIntent);
                    }

                }

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

到这里高版本的AMS出口处hook就完成了,在测试机 8.0~9.0 系统上能运行,但是我自己手机是10.0,一跑crash了,真令人头大。

点开源码发现系统源码又变了

getService还是那个getService,但ActivityManager却不是那个ActivityManager了,变成了ActivityTaskManager

点进ActivityTaskManager.getService()发现返回的接口也变了

返回的接口变成了IActivityTaskManager,并且在代码中还搜索不到这个类,在android 10.0源码中找到了这个类

在android 10.0中IActivityTaskManager接口没有直接写在源码中,而是通过AIDL的方式去生成的,没事能生成就行,看了下目录,还是在android.app目录下,那就继续反射呗

    Class mActivityTaskManagerClass = Class.forName("android.app.ActivityTaskManager");

        Field iActivityTaskManagerSingletonField = mActivityTaskManagerClass.getDeclaredField("IActivityTaskManagerSingleton");
        iActivityTaskManagerSingletonField.setAccessible(true);
        mSingleton = iActivityTaskManagerSingletonField.get(null);

        /**
         * 这里由于10.0 hide 了getService 无法通过getService得到mIActivityTaskManager
         */
        Method mGetServiceMethod = mActivityTaskManagerClass.getDeclaredMethod("getService");
        mGetServiceMethod.setAccessible(true);
        mIActivityTaskManager = mGetServiceMethod.invoke(null); //得到activity_task
        

这里由于 android 10 getService方法被hide了,反射一直无法获取到getService方法

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

但是 IActivityTaskManagerSingleton 这个属性并没有被hide,于是通过IActivityTaskManagerSingleton属性获取 IActivityTaskManager 接口

    	/**
         * 这里由于10.0 hide 了getService 所以需要通过 Singleton 的get方法得到 mIActivityTaskManager
         */
        Class SingletonClass = Class.forName("android.util.Singleton");
        Method getMethod = SingletonClass.getDeclaredMethod("get");
        getMethod.setAccessible(true);
        mIActivityTaskManager = getMethod.invoke(mSingleton);
        

然后继续反射替换proxy对象

     // 动态代理 IActivityTaskManager 接口
        Class proxyIActivityTaskManagerClass = Class.forName("android.app.IActivityTaskManager");
        final Object finalMIActivityTaskManager = mIActivityTaskManager;
        Object proxyIActivityTaskManager = Proxy.newProxyInstance(context.getClassLoader(), new Class[]{proxyIActivityTaskManagerClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
                //这里的流程就跟低版本流程一样了,替换intent
                if ("startActivity".equals(method.getName())) {
                    Intent proxyIntent = new Intent(context, ProxyActivity.class);
                    Intent target = (Intent) objects[2];
                    objects[2] = proxyIntent;
                    proxyIntent.putExtra("target", target);
                }
                return method.invoke(finalMIActivityTaskManager, objects);
            }
        });

        Class mSingletonClass = Class.forName("android.util.Singleton");
        Field mInstanceField = mSingletonClass.getDeclaredField("mInstance");
        mInstanceField.setAccessible(true);
        mInstanceField.set(mSingleton, proxyIActivityTaskManager);
        

到此android 10.0的 AMS 入口处hook就完成了,出口处相比8.0~9.0版本并没有变化,所以不需要做特别处理。

自此 android 5.0 ~ android 10.0 的绕过AndroidManifest跳转activity终于完成了(虽然并没什么卵用 =。=!)

在阅读android 10.0源码中还发现一个有趣的现象,感觉AMS在新版本中在被慢慢的拆分。

AMS在android中实在是太庞大了,四大组件都杂糅在AMS中,对于源码阅读很不方便,希望四大组件能拆分成对应的TASK_SERVICE吧!

最后项目源码:github.com/amusiaHzr/A…