0x5、Xposed如何Hook Zygote
从上面的跟踪结果,不难得出这样的调用链:
init进程 → init.rc → app_process(app_main.cpp) → 启动Zygote进程 → ZygoteInit的main() → startSystemServer() → fork出system_server子进程。
接着来看下Xposed具体是怎么注入Zygote的,打开Xposed的仓库,发现这样两个文件:
em...区分Android 5.0 前后版本,打开 Android.mk
:
呕吼,定制 app_process 文件,而且可以根据sdk版本选择对应文件作为入口,打开 app_main2.app
,跟到下述位置:
有点眼熟,跟下:xposed.cpp –> initialize
,部分代码如下:
bool initialize(bool zygote, bool startSystemServer, const char* className, int argc, char* const argv[]) { // ① 初始化xposed相关变量 xposed->zygote = zygote; xposed->startSystemServer = startSystemServer; xposed->startClassName = className; xposed->xposedVersionInt = xposedVersionInt; ... // ② 将XposedBridge.jar加载到系统的CLASSPATH路径中。 return addJarToClasspath(); }
跳回前面,如果初始化成功,调用 调用 XPOSED_CLASS_DOTS_ZYGOTE
即 de.robv.android.xposed.XposedBridge
的 main() 方法,若初始化失败,则按照正常流程初始化。跟下 XposedBridge → main()
,部分代码如下:
到此Xposed Hook Zygote的流程很明了了:
编译生成自定义app_process → 把原先调用 ZygoteInit.main() 处 改为调用 XposedInit.main() → Hook资源和一些准备工作 → 调用系统原本启动Zygote的方法。
0x6、Xposed如何替换系统app_process
上面说到系统的app_process替换成自定义的了,那具体是怎么替换的呢?
那就得看看 XposedInstaller
了,除了介绍那里说到的管理Xposed模块外,它还有两个核心功能:替换系统app_process
和 将XposedBridge.jar文件放到私有目录中
。
打开XposedInstaller项目搜下app_process:
在Code没找到,却在某次commit找到了,点开,定位到 assets/install.sh
流程简洁明了,改权限搬运文件,不过这是旧版的,在新版中却没找到这个关键字。
打开手机XposedInstaller抓下包,发现了这样的请求:
http://dl-xda.xposed.info/framework.json
接着项目中搜索下域名:
跟url有点不同,请求下framework.json:
可以,就是拼接zip包url的模板,包含:系统sdk版本,架构,xposed版本号,以我的魅蓝e2为例,拼接后的url:
http://dl-xda.xposed.info/framework/sdk23/arm64/xposed-v89-sdk23-arm64.zip
下载解压后,开始找搬运脚本,可却只找到了二进制文件、so库和XposedBridge.jar:
尴尬,只能从源码入手了,XposedInstaller点击安装时会弹出 Install 和 Install via recovery,搜下后面这个字符串:
跟到:FrameworkZips → INSTALLER
不难看出这个函数是拿来解析framework.json的
哪里调用到了 parseZipSpec()
:
哪里调用到了 getOnline()
:
跟下:StatusInstallerFragment → addZipViews() → addZipView() → showActionDialog()
这个 flash()
就是刷入方法,可以看到第二个参数类型是不一样的:FlashDirectly
和 FlashRecoveryAuto
,先跟下前者的flash()方法:
再看看 FlashRecoveryAuto 的 flash()
方法:
当系统处于recovery模式会自动检测command文件是否存在,存在其中的指令,后续刷入跟前者一致。
不过,还是没有解决我的疑问,啥时候替换的app_process,网上说update-binary其中会调用一个 flash-script.sh
文件,在zip包中可以找到此文件:
em...很明显,就是替换文件的脚本,还对32位及64位的情况作了区分,验证起来有些麻烦,后面我如果自己编译Xposed再验证下吧,暂且记住这个结论:
XposedInstaller下载补丁包 → 获取root权限 → 解压复制update-binary文件到特定目录 → 文件执行时会调用flash-script.sh脚本,将app_process、Xposedbridge.jar、so库等写到系统私有目录。