在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。

  1. 下载 github.com/newbit1/roo…
  2. 运行模拟器
  3. 执行rootAVD.sh EMULATOR_IMAGE_PATH/ramdisk.img
  4. 模拟器自动重启,Magisk就安装好了
  5. Root完成,打开Magisk可以进行授权管理

Magisk界面截图如下:

Magisk-Small2.png

安装Xposed框架

Xposed框架现在由国内开发者开发了,名字是LSPosed,包含一个Zip包给系统打补丁,一个Apk用于管理模块。 安装的话,有了Magisk之后,也是很简单。

  1. 下载 github.com/LSPosed/LSP… 最新的版本
  2. 将下载下来的压缩包,复制到模拟器里
  3. 打开Magisk管理器,安装刚复制进来的模块
  4. 重启模拟器即可

LSPosed的apk其实是注入到了系统的一个app里的,主要目的是防止被微信、银行等敏感的三方应用检测到。因此开机之后,他没有单独的app图标,你可以在通知栏看到一个常驻通知,使用这个通知创建一个启动快捷方式。

LSP界面截图如下:

LSP-Small2.png

一个入门的Hook模块

有了LSP,就可以对任意应用包括系统进行hook了,我们写一个例子,劫持Activity启动逻辑,打印个日志。

首先需要知道LSP模块是什么?

LSP模块是一个APK,就和我们平时开发的APK一样,区别是相对普通APK,它可以让LSP加载到指定的进程中,并对该进程的Java进行Hook。

因此,相对普通APK开发,额外要做的两件事:

  1. 定义要入侵的进程,LSP官方叫做Scope,一个scope其实就是指定一个包名,例如此处我们要hook android系统,那么包名就是android。
  2. 指定如何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,启用我们的模块,见下图。之后务必重启设备。这一步很重要!!

SelectScope-Small2.png

设备重新启动后,就可以在控制台,看见我们的日志了,切换Activity的时候也打印了。

Log.png

谢谢!

全部评论

相关推荐

03-26 15:18
已编辑
华北水利水电大学 Java
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务