在Android模拟器上玩转Xposed
在Android模拟器上玩转Xposed
这篇文章演示了如何Root Android模拟器。 另外通过一个简单的例子,演示我们基于Xposed框架,hook Android系统,实时打印当前Activity的信息。
学完这个我们就能按照需求,随意劫持Android系统或者三方App了。
Root 模拟器
此处以Android13为例。
现在Root技术,主要由Magisk实现,这是一套Root工具,包含一个刷入手机的Zip包,以及安装到手机上的Apk用于进行Root授权管理。
在真机上Root和模拟器Root是有区别的,真机相对比较麻烦,需要解锁BL,刷入恢复系统之后,才能刷入Magisk root包。
而在模拟器上,相对简单,只需要修改Boot镜像,在其中加入Magisk root包即可,有一个开源的模拟器Root工具 RootAVD,可快速完成root。
- 下载 github.com/newbit1/roo…
- 运行模拟器
- 执行
rootAVD.sh EMULATOR_IMAGE_PATH/ramdisk.img
- 模拟器自动重启,Magisk就安装好了
- Root完成,打开Magisk可以进行授权管理
Magisk界面截图如下:
安装Xposed框架
Xposed框架现在由国内开发者开发了,名字是LSPosed,包含一个Zip包给系统打补丁,一个Apk用于管理模块。 安装的话,有了Magisk之后,也是很简单。
- 下载 github.com/LSPosed/LSP… 最新的版本
- 将下载下来的压缩包,复制到模拟器里
- 打开Magisk管理器,安装刚复制进来的模块
- 重启模拟器即可
LSPosed的apk其实是注入到了系统的一个app里的,主要目的是防止被微信、银行等敏感的三方应用检测到。因此开机之后,他没有单独的app图标,你可以在通知栏看到一个常驻通知,使用这个通知创建一个启动快捷方式。
LSP界面截图如下:
一个入门的Hook模块
有了LSP,就可以对任意应用包括系统进行hook了,我们写一个例子,劫持Activity启动逻辑,打印个日志。
首先需要知道LSP模块是什么?
LSP模块是一个APK,就和我们平时开发的APK一样,区别是相对普通APK,它可以让LSP加载到指定的进程中,并对该进程的Java进行Hook。
因此,相对普通APK开发,额外要做的两件事:
- 定义要入侵的进程,LSP官方叫做Scope,一个scope其实就是指定一个包名,例如此处我们要hook android系统,那么包名就是android。
- 指定如何Hook,就是要写hook的代码了,通过代码hook java method,将其替换成我们自己的逻辑。
下面开始代码示例:
首选新建一个工程,没什么要求,可随便创建。
首先添加Scope定义
在AndroidManifest.xml里,定义以下meta data,主要是告知LSP我们是一个模块,以及我们的scope在哪个xml里,让它去解析。
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication"
tools:targetApi="31" >
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="This is a demo for Xposed" />
<meta-data
android:name="xposedminversion"
android:value="53" />
<meta-data
android:name="xposedscope"
android:resource="@array/xposed_scope" />
</application>
Scope XML 定义如下,支持定义多个,我们还是以Android系统为例。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="xposed_scope">
<item>android</item>
</string-array>
</resources>
接下来,指定Hook逻辑
LSP加载我们的Hook逻辑时,要知道我们的Hook代码入口,因此,我们需要创建一个xposed_init
文件,放在app/assets目录下,供LSP解析。
文件内容如下:
com.example.xposed.demo.HookEntry
下面就要开始实现HookEntry这个类了,到此我们需要引用一个lib依赖,这个依赖提供了Hook相关的一些工具以及接口,我们要实现接口,利用工具去修改method。
在app依赖中添加,注意是compileOnly的,因为在安装LSP时,这个lib已经集成到系统运行时了:
compileOnly("de.robv.android.xposed:api:82")
由于这个库出来很久了,所以要在根目录settings.gradle,加上jcenter仓库,否则拉不下来。
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
// here.
jcenter()
}
}
现在开始正式编码:
const val LOG_TAG = "XposedDemo"
class HookEntry : IXposedHookLoadPackage {
// 加载一个应用的进程的时候,会调用这个方法
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
// 如果多个scope,那么要通过lpparam判断,具体加载的是哪个应用
if (lpparam.packageName == "android") {
// 用XposedBridge打印的日志,可以在LSPosed管理器中看到日志记录
XposedBridge.log("$LOG_TAG Loading Android")
// 通过工具,找到要劫持的class
val classToHook = XposedHelpers.findClass(
"com.android.server.wm.ActivityStarter",
// 这个classloader就是目标app的,用它才能定位到目标class
lpparam.classLoader
)
XposedBridge.log("$LOG_TAG classToHook: $classToHook")
// https://cs.android.com
// 我们可以查阅AOSP代码,看下Activity启动流程
// 此处我们hook以下ActivityStarter的启动方法
// 原型如下:
// private int executeRequest(Request request) {...}
XposedBridge.hookAllMethods(
// 类
classToHook,
// 要hook的方法名
"executeRequest",
object : XC_MethodHook() {
// AOP方法之一,在方法执行之前要做的事情,此处我们打印日志
// 提示:此处除了可以获取到method参数,返回值信息之外,还能修改返回值
override fun beforeHookedMethod(param: MethodHookParam) {
super.beforeHookedMethod(param)
val request = param.args[0]
// 工具很方便
val intent = XposedHelpers.getObjectField(request, "intent")
// 打印日志,目的达到了
XposedBridge.log("$LOG_TAG Starting Activity: $intent")
}
})
}
}
}
至此,编码完成,打包安装apk到模拟器上。打开LSP管理器,进入模块Tab,启用我们的模块,见下图。之后务必重启设备。这一步很重要!!
设备重新启动后,就可以在控制台,看见我们的日志了,切换Activity的时候也打印了。
谢谢!