Xposed 模块开发指南

Xposed

Xposed 是一个针对 Android 系统的框架,允许开发者通过 Hook(钩取)系统或应用的函数来修改其行为,实现个性化功能,无需修改原始 APK 文件。

通过 Xposed,开发者可以轻松进行数据劫持、修改参数值和返回值、主动调用方法等操作。基于此框架,开发者能够创建出各种强大的模块,且这些模块可以在功能不冲突的前提下同时运行,极大提升了系统的可定制性。例如,可以实现消息防撤回、步数修改、去广告、界面美化等功能,满足不同用户的需求并增强用户体验。

Xposed实现原理

Xposed 框架通过替换 Android 系统原本的 app_process,使用自定义的 app_process 来启动 Zygote 进程,并加载一个额外的 XposedBridge.jar。该 JAR 包包含了 Xposed 框架的核心代码,框架会执行 XposedBridge.main() 方法。此方法的核心任务是利用 Xposed 提供的 Hook 能力,动态劫持原本将被调用的 ZygoteInit.main() 方法,从而劫持 Zygote 进程以及所有通过 Zygote 启动的应用进程。通过这种方式,Xposed 能够在不修改 APK 的情况下,通过注入代码动态修改 Dalvik/ART 虚拟机的行为,实现在系统和应用中的 Hook 和修改功能。

Xposed 框架的发展

特性 Xposed Installer EdXposed LSPosed
Android支持 4.0--8.1 8.0--11 8.1--14+
注入方式 替换app_process Riru动态注入 Zygisk集成
Hook模式 全局生效 全局生效 作用域隔离(白名单)
模块生效 需重启系统 需重启系统 仅重启应用
抗检测能力 中(依赖Riru隐藏) 高(Zygisk隐匿)

准备工作

  • 安卓开发环境(Android Studio)
  • 一台可以安装Xposed框架的手机(本文使用LSPosed)
  • jadx

编写第一个Xposed模块

项目创建

  1. 打开Android Studio,创建新项目

  2. 项目模板选择"No Activity"

  3. 设置名字,这里我们设置成"XPDemo"

  4. 本文我们使用Java语言开发

  5. 点击finish创建项目

引入依赖

修改 settings.gradle.kts 文件中的dependencyResolutionManagement节点

kotlin 复制代码
...
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url =  uri("https://api.xposed.info/") }	// 添加 Xposed 相关的 Maven 仓库,允许从指定地址下载相关依赖
    }
}
...

修改 build.gradle.kts 文件中的dependencies节点

Kotlin 复制代码
dependencies {
    compileOnly("de.robv.android.xposed:api:82")	 // 仅编译时使用 Xposed API,不会打包进 APK 中
    implementation(libs.appcompat)
    implementation(libs.material)
    testImplementation(libs.junit)
    androidTestImplementation(libs.ext.junit)
    androidTestImplementation(libs.espresso.core)
}

声明模块

修改AndroidManifest.xml中的application节点

xml 复制代码
    <application
        ...>

        <!-- 声明本应用是Xposed模块,,xposed根据这个判断是否是模块的 -->
        <meta-data
            android:name="xposedmodule"
            android:value="true" />
        <!-- 本模块的模块描述 -->
        <meta-data
            android:name="xposeddescription"
            android:value="Xposed Module Demo" />
        <!-- 最低xposed版本号 -->
        <meta-data
            android:name="xposedminversion"
            android:value="52" />
        <!-- 模块生效的作用域<可选> -->
        <meta-data
            android:name="xposedscope"
            android:resource="@array/xpdemo_scope"/>
    </application>

如果设置了xposedscope,就需要在src/main/res/values中创建arrays.xml文件,然后写入模块生效的应用,如下

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="xpdemo_scope">
        <item>qhmx.flat.game</item>
        <item>com.example.demo1</item>
    </string-array>
</resources>

创建Hook类

创建Hook类,这里我们叫HookMain,这个类的修饰符必须是public,并且需要实现IXposedHookLoadPackage接口重写handleLoadPackage方法。

java 复制代码
package com.example.xpdemo;

import android.util.Log;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class HookMain implements IXposedHookLoadPackage{
    private static final String TAG = "HookMain";
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        Log.e(TAG, lpparam.packageName + "Starting");
    }
}

创建xposed_init

在src/main中创建assets目录,在该目录中创建xposed_init文件,我们需要在这个文件里写上HOOK类全路径,方便Xposed模块能找到HOOK类。这个例子中就是com.example.xpdemo.HookMain.

至此框架搭建完毕。

加载Xposed 模块

把编译好的apk安装到手机上。

安装后,LSPosed就可以检测到我们的模块。

在上图中可以看到我们插件的名字和模块描述。

在上图中可以我设置模块作用的包名会有一个推荐应用的显示。

实战

我们只是为了练习Xposed 模块的编写,不讨论样本的难以程度。

我在网上下载了一个样本程序,它的功能是:需要输入一个密码,点击提交,然后他会判断密码是否是预期的密码,然后给出对应提示。

分析

使用jadx反编译MainActivity

通过反编译的结果得知,如果flag不为null,就达到我们的目的。所以继续追踪FlagGuard类的getFlag方法。

通过反编译getFlag方法的实现得知,如果str和Data类的getData方法返回相同,该函数的返回值就不为null。

我们可以通过Hook Data类的getData方法来得到正确的密码。

代码实现

目标:通过Hook getData方法使用Toast来显示出正确的密码。

提示:jadx可以通过右击方法名,复制为xposed片段,直接生成Hook代码。

java 复制代码
package com.example.xpdemo;

import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.util.Log;
import android.widget.Toast;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import de.robv.android.xposed.XposedHelpers;

public class HookMain implements IXposedHookLoadPackage{
    private static final String TAG = "HookMain";
    public static final String targetPackName = "com.XXX.crackme0x02";
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {

        if(!lpparam.packageName.equals(targetPackName)) {
            return;
        }


        Log.e(TAG, lpparam.packageName + " Starting");
        XposedHelpers.findAndHookMethod("com.XXX.crackme0x02.Data", lpparam.classLoader, "getData", android.content.Context.class, new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                super.beforeHookedMethod(param);
            }
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
                Context context = (Context)param.args[0];
                String passWord = (String)param.getResult();
                Toast.makeText(context, "Password is " + passWord, Toast.LENGTH_LONG).show();
                copyTextToClipboard(passWord, context);
            }
        });
    }

    private void copyTextToClipboard(String text, Context context) {
        // 获取系统剪切板服务
        ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);

        // 创建 ClipData 对象,包含要复制的文本
        ClipData clip = ClipData.newPlainText("label", text);

        // 将 ClipData 设置到剪切板
        clipboard.setPrimaryClip(clip);
    }

}

效果

安全防范

Xposed 框架功能强大,它会对应用安全可能造成一定影响。为应对这一问题,推荐一款加固工具。Virbox Protector 通过深度加固机制应对 Xposed 框架的安全风险:其核心防护手段包括实时检测 Xposed 环境、阻断模块注入、强化反调试及内存完整性校验,有效拦截 Zygote 进程劫持与代码 Hook 行为;配合 DEX 加密、字符串混淆及防篡改技术,从根源上防止 Xposed 模块对应用逻辑的篡改与数据窃取,显著提升应用在 Root 环境下的抗逆向能力,保障开发者代码安全与用户隐私。