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模块
项目创建
-
打开Android Studio,创建新项目
-
项目模板选择"No Activity"
-
设置名字,这里我们设置成"XPDemo"
-
本文我们使用Java语言开发
-
点击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 环境下的抗逆向能力,保障开发者代码安全与用户隐私。