先思考一个问题,为什么我们的Activity需要在AndroidManifest.xml文件中注册?如果不注册能不能启动呢?

我们知道是AMS负责调起Activity。在启动之前他做了些什么事情呢?前面我们说过实际上AMS是给Zygote发送了消息,由Zygote进程fork一个虚拟机进程来。

那么其实在开机时Zygote进程在运行时第一个fork的进程是system_server的进程,这个服务用于管理系统级别的服务启动。

System_server进程包含了以下顶级的系统服务

  • ActivityManagerService

  • PowerManagerService

  • MountService

  • NetworkManagementService

  • InputManagerService

  • WindowManagerService

既然AMS承载了调用逻辑。我们是否可以对AMS动刀子来做到不注册Activity也能直接启动呢?

这里为什么我们前面要讲system_server服务,原因是我们要知道AMS进程不在我们自己的应用内,而是独立的远程服务进程。java层的上的反射是无法做到跨进程的。所以我们可以在自己的应用内利用AIDL的特性拿代理对象,去欺骗AMS服务。

流程如下:

1.我们使用 startActivity(intent);来启动一个Activity。

2.hook住ActivityManager内的本地binder对象,拦截startActivity方法。

3.用动态代理方式将未被注册Activity的Intent替换成已注册的Activity的Intent,并将未被注册的Intent带过去。(替换壳Activity,躲避AMS服务的检查,也就是欺骗AMS)

4.对ActivityThread中的handle进行hook。因为前面替换的是壳子,替换真正要启动的Intent。

5.发送handleMessage消息,启动未被注册的Activity。
实现欺骗:

这里我们通过反射获取到AMS的代理本地代理对象Hook以后动态串改Intent为已注册的来躲避检测

通过动态代理实现对startActivity中的Intent串改,具体逻辑见代码和注释。

hook ActivityThread 中的 handle 在这里我们需要替换我们未被注册的Activity Intent

拦截启动消息

替换我们真实要被启动的Intent

封装以后我们ASMHook将变得非常简单,简单到一行代码就可以实现不注册的情况下启动Activity。

其中HostActivity是我们的壳,OtherActivity是未被注册的。我们可以像平时正常调用API的条件下直接使用startActivity了。

结果 启动了。

哎妈呀,好腻害的样子,喘口气看看刚刚发生了什么事情。

献上封装好的HookAMS菊花(GitHubDemo)

来源:http://www.jianshu.com/p/2ad105f54d07