疑问
- root问题,你想象中手机root后是什么样子的?
- 手机root之后,是不是每个应用进程都具有了root权限?
- 如果root了,是不是就可以调用系统api了?
- 老听别人说,利用一个安全漏洞,获取了root权限,是怎么实现的?
- 自己编译的aosp的root和传统的root有啥区别?
- 我听说过xposed,但是我不知道怎么使用xposed,xposed模块开发难不难?
ROOT的实现
目前实现root的方式:
- 解锁 Bootloader,通过修改 Android 系统的某一部分实现 root。
- 通过某些系统漏洞提取,进而获取 root 权限。
而我们下面所聊的都是基于第一种方式,目前市面上主流的root框架有以下几种:
- XPosed:定制app_process程序和定art虚拟机。(Zygote进程)
- KernelSU:修改系统内核方式来实现root(android11之前通过修改kernel,android11之后开发GKI模块方式)。(内核)
- Magisk:修改init文件和运行时修改init.rc。(Init进程)
Android启动流程
Loader和Kernel
- loader 加载引导程序到RAM
- bootloader RAM检查,初始化硬件参数
- kernel 初始化linux内核
Native
Native这一层正式进入了android系统的初始化,首先会初始化init(1号进程),主要是挂载系统文件,初始化 property 服务,解析执行 rc 配置文件,启动service manager(跨进程通信能力)
- rc配置文件是 Android的init语言,可以启动服务和设置监听后续Android系统的各个流程设置监听(重点)
FrameWork
init.zygote64.rc
1 | service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server |
init启动之后 会执行这个rc文件,启动zygote进程;我们知道所有的App应用都是通过zygote fork而来的,它主要做以下工作:
- dlopen so共享库
- 初始化libart (ART虚拟机)
- 启动一个socket服务,等待fork进程
在zygote初始化完并且手动gc后,会直接fork一个进程出来system_server进程出来(非socket调用fork),这个进程会经常和我们应用进程打交道,其中的AMS,PMS,WM等Binder服务都来自这个进程。我们常说的FrameWork就是system_server进程。
App
LSPosed框架
LSPosed 是一个面向 Android 系统的开源框架,用于实现对应用程序的行为修改和扩展。它基于 Xposed 框架进行开发,并提供了更简单和高效的方式来实现应用的 Hook 和模块化开发。
下方这种图是LSPosed
我们再解释一遍:
Magisk:让一切成为可能,因为Magisk修改了init的启动,在启动流程中,我们可以干一些我们想干的事;对于模块来说,Magisk在post-fs-data阶段和framework启动阶段会调模块。(这里的修改是了ROM中的boot.img,需要刷机)
Zygisk: zygote和Magisk单词组合而成,提供了注入Zygote代码的能力。和Riru的功能一样。使用时是互斥的。
Riru模块:提供了注入到Zygote进程代码的能力。 (Magisk模块)
Riru-LSPosed模块:主要是调用注入代码能力,将XPosedBridge.jar和Xposed模块注入到Zygote进程。(Magisk模块)
LSPosed管理器:管理XPosed模块。
XPosedBridge:很久之前一个同学开发了Root框架(XPosed),XPosedBridge是hook java类的一个接口框架(仅仅是接口,并非真正去hook),XPosed通过修改ART虚拟机实现了hook,然后大家开发的模块时,都是依赖XPosedBridge标准接口框架开发。后来XPosed不维护了,但是大家写的模块都是基于XPosedBridge的。新的Root框架也实现XPosedBridge接口,这样模块开发者开发的框架就可以完美运行在新的Root框架之上了。
Xposed模块:开发者依赖XPosedBridge标准接口框架开发的模块。
Dobby:inline hook能力的框架,LSPosed会将XPosedBridge和inline hook桥接到一起,最终实现hook。
LSPlant:主要提供hook能力。
EdXPosed:LSPosed是基于EdXPosed开发的,因为两位开发者闹掰了,然后其中一位开发者才开发了LSPosed。
LSPosed和EdXPosed的八卦消息。
残页(LSPosed开发者):
LSPosed:
MlgmXyysd(EdXposed):
XPosed模块
当爱奇艺打开的时候,是从Zygote进程fork了一个新的进程,所以此时的爱奇艺具有以下能力:
- 加载模块代码能力
- inline hook代码能力
- 和LSPosed通信能力
以上的这些能力都是LSPosed赋予的,可以在LSPosed中开控制是否赋于爱奇艺这些能力。
联璧模块
以下是一个使用联璧XPosed模块免费看剧的故事,它支持爱奇艺/优酷/腾讯/芒果等平台解析看剧,开始的时候感觉很好用,但是用了几次后就开始收费了。
感觉好用,是因为联璧模块可以直接解析,真正好的是因为爱奇艺有视频推荐。所以我们也可以开发一个免费看剧模块。这里我们关注两点:
- 剧名
- 跳转
模块开发
我们只需要有拿着剧名跳转到一个app的能力就可以了,至于搜索剧名的任务就交给我们自己开发的app了。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26// hook 所有activity
XposedHelpers.findAndHookMethod("android.app.Activity", lpparam.classLoader, "onCreate", Bundle.class, new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
activities.add((Activity) param.thisObject);
Activity activity = (Activity) param.thisObject;
// 爱奇艺播放器activity
if ("org.iqiyi.video.activity.PlayerActivity".equals(activity.getClass().getCanonicalName())) {
// 找到简介组件
TextView tvDes = getView(activity.getWindow().getDecorView(),"简介");
tvDes.setText("解析");
tvDes.setTextColor(Color.RED);
tvDes.setTextSize(20);
tvDes.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// 拿到剧名
String videoName = getVideoName();
// 跳转到我们自己的app中搜索剧名
doSearch(activity,videoName);
}
});
}
}
}
通过上面的hook代码,我们就有了拿着剧名跳转到我们自己app的能力了。
视频播放
这里又涉及到了一个逆向,反编译未上架的灰产视频播放app。
我这里调研了一个叫自由无二的视频app,它使用了360壳加固;所以这里第一步需要脱壳,LSPosed插件市场有dex脱壳和so脱壳的插件,直接使用脱壳即可。紧接着使用”adb shell dump”和jadx反编译阅读代码相关代码即可。
视频搜索:来自于自由无二app中阅读代码取得。
视频播放:JZVideo 饺子播放器 + 定制(折叠屏全屏,倍速,内核选择,锁屏,快进阻尼因子等)。
最终效果:
终结
从XPosed到LSPosed,再到Magisk,涉及的技术很多,这里简单总结一下:
- inline hook框架(ELF文件解析 + 汇编 + ART虚拟机 + PLT hook)
- Android系统初始化流程
- Magisk (Magisk boot patch原理 + Magisk init原理)
- LSPosed
Android启动分析
Magisk boot patch原理
Magisk init学习
ELF文件机构
Pine hook汇编解析