发布于

Xposed 框架入门指南:Android 系统级修改的强大工具

作者

Xposed 框架入门指南:Android 系统级修改的强大工具

Xposed 框架是 Android 平台上最强大的系统级修改工具之一,它允许开发者在不修改 APK 文件的情况下改变应用程序的行为。本文将详细介绍 Xposed 框架的基本概念、安装方法和入门开发。

Xposed 框架概述

什么是 Xposed 框架

Xposed 框架是一个运行在 Android 系统上的模块化平台,它通过 Hook 技术拦截和修改系统和应用程序的方法调用:

// Xposed Hook 基本原理示例
public class XposedHookExample implements IXposedHookLoadPackage {
    
    @Override
    public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
        // 只 Hook 特定的应用包名
        if (!lpparam.packageName.equals("com.example.targetapp")) {
            return;
        }
        
        // Hook 目标方法
        findAndHookMethod(
            "com.example.targetapp.MainActivity",  // 目标类
            lpparam.classLoader,                   // 类加载器
            "targetMethod",                        // 目标方法名
            String.class,                          // 方法参数类型
            new XC_MethodHook() {                  // Hook 回调
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    // 方法执行前的处理
                    XposedBridge.log("方法执行前: " + param.args[0]);
                }
                
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    // 方法执行后的处理
                    XposedBridge.log("方法执行后,返回值: " + param.getResult());
                    
                    // 修改返回值
                    param.setResult("Modified Result");
                }
            }
        );
    }
}

核心概念

// 1. Hook 方法 - 拦截方法调用
public class MethodHookExample {
    
    public static void hookMethod() {
        findAndHookMethod(
            "android.telephony.TelephonyManager",
            null,  // 使用系统类加载器
            "getDeviceId",
            new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    // 修改设备ID返回值
                    param.setResult("123456789012345");
                }
            }
        );
    }
}

// 2. Hook 构造函数
public class ConstructorHookExample {
    
    public static void hookConstructor() {
        findAndHookConstructor(
            "java.io.File",
            null,
            String.class,  // 构造函数参数类型
            new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    String path = (String) param.args[0];
                    XposedBridge.log("创建文件: " + path);
                    
                    // 可以修改构造函数参数
                    if (path.contains("sensitive")) {
                        param.args[0] = "/safe/path";
                    }
                }
            }
        );
    }
}

// 3. 替换方法实现
public class MethodReplaceExample {
    
    public static void replaceMethod() {
        findAndHookMethod(
            "android.os.SystemProperties",
            null,
            "get",
            String.class,
            String.class,
            new XC_MethodReplacement() {
                @Override
                protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
                    String key = (String) param.args[0];
                    String defaultValue = (String) param.args[1];
                    
                    // 自定义逻辑
                    if ("ro.build.version.release".equals(key)) {
                        return "Custom Android Version";
                    }
                    
                    // 调用原始方法
                    return XposedBridge.invokeOriginalMethod(param.method, param.thisObject, param.args);
                }
            }
        );
    }
}

环境搭建和安装

前置条件

# 1. 设备要求
# - Android 设备已 Root
# - 解锁 Bootloader
# - 支持的 Android 版本 (通常 4.0+)

# 2. 开发环境
# - Android Studio
# - Java/Kotlin 开发环境
# - ADB 工具

# 3. 检查设备兼容性
adb shell su -c "ls /system/framework/"
# 查看是否有 XposedBridge.jar

Xposed 框架安装

# 方法一:通过 Xposed Installer (传统方法)
# 1. 下载 Xposed Installer APK
# 2. 安装并授予 Root 权限
# 3. 在应用中安装框架

# 方法二:通过 Magisk 模块 (推荐)
# 1. 安装 Magisk Manager
# 2. 下载 Riru 模块
adb push riru-v26.1.7.zip /sdcard/
# 3. 在 Magisk 中安装 Riru
# 4. 下载并安装 LSPosed 模块
adb push LSPosed-v1.8.6-6552-zygisk-release.zip /sdcard/

# 方法三:EdXposed (Android 8.0+)
# 1. 安装 Riru 核心
# 2. 安装 EdXposed 模块
# 3. 重启设备

# 验证安装
adb shell su -c "ls /data/misc/riru/modules/"

开发环境配置

// app/build.gradle
android {
    compileSdkVersion 33
    
    defaultConfig {
        applicationId "com.example.xposedmodule"
        minSdkVersion 21
        targetSdkVersion 33
        versionCode 1
        versionName "1.0"
    }
    
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    // Xposed API
    compileOnly 'de.robv.android.xposed:api:82'
    compileOnly 'de.robv.android.xposed:api:82:sources'
    
    // 其他依赖
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.9.0'
}
<!-- AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.xposedmodule">
    
    <!-- Xposed 模块声明 -->
    <application
        android:label="@string/app_name"
        android:icon="@mipmap/ic_launcher">
        
        <!-- Xposed 模块元数据 -->
        <meta-data
            android:name="xposedmodule"
            android:value="true" />
        <meta-data
            android:name="xposeddescription"
            android:value="示例 Xposed 模块" />
        <meta-data
            android:name="xposedminversion"
            android:value="54" />
        
        <!-- 主 Activity -->
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    
    <!-- 权限声明 -->
    <uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
</manifest>

基础模块开发

第一个 Xposed 模块

// XposedInit.java - 模块入口点
package com.example.xposedmodule;

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

public class XposedInit implements IXposedHookLoadPackage {
    
    private static final String TAG = "XposedModule";
    
    @Override
    public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
        // 记录加载的包
        XposedBridge.log(TAG + ": 加载包 " + lpparam.packageName);
        
        // Hook 系统设置
        if ("com.android.settings".equals(lpparam.packageName)) {
            hookSettings(lpparam);
        }
        
        // Hook 特定应用
        if ("com.example.targetapp".equals(lpparam.packageName)) {
            hookTargetApp(lpparam);
        }
        
        // Hook 系统服务
        if ("android".equals(lpparam.packageName)) {
            hookSystemServices(lpparam);
        }
    }
    
    private void hookSettings(LoadPackageParam lpparam) {
        try {
            // Hook 设置应用的特定功能
            Class<?> settingsClass = XposedHelpers.findClass(
                "com.android.settings.Settings", 
                lpparam.classLoader
            );
            
            XposedHelpers.findAndHookMethod(
                settingsClass,
                "onCreate",
                android.os.Bundle.class,
                new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        XposedBridge.log(TAG + ": 设置应用启动");
                    }
                }
            );
        } catch (Throwable t) {
            XposedBridge.log(TAG + ": Hook 设置失败 - " + t.getMessage());
        }
    }
    
    private void hookTargetApp(LoadPackageParam lpparam) {
        try {
            // Hook 目标应用的方法
            XposedHelpers.findAndHookMethod(
                "com.example.targetapp.MainActivity",
                lpparam.classLoader,
                "checkLicense",
                new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        // 始终返回已授权
                        param.setResult(true);
                        XposedBridge.log(TAG + ": 许可证检查被绕过");
                    }
                }
            );
        } catch (Throwable t) {
            XposedBridge.log(TAG + ": Hook 目标应用失败 - " + t.getMessage());
        }
    }
    
    private void hookSystemServices(LoadPackageParam lpparam) {
        try {
            // Hook 系统服务
            Class<?> activityManagerService = XposedHelpers.findClass(
                "com.android.server.am.ActivityManagerService",
                lpparam.classLoader
            );
            
            XposedHelpers.findAndHookMethod(
                activityManagerService,
                "startActivity",
                // 参数类型较复杂,使用 findMethodExact
                new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        XposedBridge.log(TAG + ": Activity 启动被拦截");
                    }
                }
            );
        } catch (Throwable t) {
            XposedBridge.log(TAG + ": Hook 系统服务失败 - " + t.getMessage());
        }
    }
}

配置文件

# assets/xposed_init
com.example.xposedmodule.XposedInit

实用工具类

// XposedUtils.java - 实用工具类
package com.example.xposedmodule.utils;

import android.content.Context;
import android.content.SharedPreferences;
import de.robv.android.xposed.XSharedPreferences;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;

public class XposedUtils {
    
    private static final String TAG = "XposedUtils";
    private static final String PREFS_NAME = "xposed_module_prefs";
    
    // 获取共享配置
    public static XSharedPreferences getPreferences(String packageName) {
        XSharedPreferences prefs = new XSharedPreferences(packageName, PREFS_NAME);
        prefs.makeWorldReadable();
        return prefs;
    }
    
    // 安全地查找类
    public static Class<?> findClassSafely(String className, ClassLoader classLoader) {
        try {
            return XposedHelpers.findClass(className, classLoader);
        } catch (XposedHelpers.ClassNotFoundError e) {
            XposedBridge.log(TAG + ": 类未找到 - " + className);
            return null;
        }
    }
    
    // 安全地 Hook 方法
    public static boolean hookMethodSafely(String className, ClassLoader classLoader, 
                                         String methodName, Object... parameterTypesAndCallback) {
        try {
            XposedHelpers.findAndHookMethod(className, classLoader, methodName, parameterTypesAndCallback);
            XposedBridge.log(TAG + ": 成功 Hook " + className + "." + methodName);
            return true;
        } catch (Throwable t) {
            XposedBridge.log(TAG + ": Hook 失败 " + className + "." + methodName + " - " + t.getMessage());
            return false;
        }
    }
    
    // 获取字段值
    public static Object getFieldValue(Object obj, String fieldName) {
        try {
            return XposedHelpers.getObjectField(obj, fieldName);
        } catch (Throwable t) {
            XposedBridge.log(TAG + ": 获取字段失败 " + fieldName + " - " + t.getMessage());
            return null;
        }
    }
    
    // 设置字段值
    public static boolean setFieldValue(Object obj, String fieldName, Object value) {
        try {
            XposedHelpers.setObjectField(obj, fieldName, value);
            return true;
        } catch (Throwable t) {
            XposedBridge.log(TAG + ": 设置字段失败 " + fieldName + " - " + t.getMessage());
            return false;
        }
    }
    
    // 调用方法
    public static Object callMethod(Object obj, String methodName, Object... args) {
        try {
            return XposedHelpers.callMethod(obj, methodName, args);
        } catch (Throwable t) {
            XposedBridge.log(TAG + ": 调用方法失败 " + methodName + " - " + t.getMessage());
            return null;
        }
    }
    
    // 检查方法是否存在
    public static boolean methodExists(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
        try {
            XposedHelpers.findMethodExact(clazz, methodName, parameterTypes);
            return true;
        } catch (NoSuchMethodError e) {
            return false;
        }
    }
    
    // 获取应用上下文
    public static Context getApplicationContext(Object activityThread) {
        try {
            return (Context) XposedHelpers.callMethod(activityThread, "getApplication");
        } catch (Throwable t) {
            XposedBridge.log(TAG + ": 获取应用上下文失败 - " + t.getMessage());
            return null;
        }
    }
}

配置界面

// MainActivity.java - 模块配置界面
package com.example.xposedmodule;

import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {
    
    private static final String PREFS_NAME = "xposed_module_prefs";
    
    private SharedPreferences prefs;
    private CheckBox enableModuleCheckBox;
    private CheckBox enableLoggingCheckBox;
    private EditText targetPackageEditText;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 初始化配置
        prefs = getSharedPreferences(PREFS_NAME, MODE_WORLD_READABLE);
        
        initViews();
        loadSettings();
    }
    
    private void initViews() {
        enableModuleCheckBox = findViewById(R.id.enableModuleCheckBox);
        enableLoggingCheckBox = findViewById(R.id.enableLoggingCheckBox);
        targetPackageEditText = findViewById(R.id.targetPackageEditText);
        
        // 设置监听器
        enableModuleCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
            saveSettings();
            showToast("模块" + (isChecked ? "已启用" : "已禁用"));
        });
        
        enableLoggingCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
            saveSettings();
        });
        
        findViewById(R.id.saveButton).setOnClickListener(v -> {
            saveSettings();
            showToast("设置已保存");
        });
        
        findViewById(R.id.testButton).setOnClickListener(v -> {
            testModule();
        });
    }
    
    private void loadSettings() {
        enableModuleCheckBox.setChecked(prefs.getBoolean("enable_module", true));
        enableLoggingCheckBox.setChecked(prefs.getBoolean("enable_logging", false));
        targetPackageEditText.setText(prefs.getString("target_package", ""));
    }
    
    private void saveSettings() {
        SharedPreferences.Editor editor = prefs.edit();
        editor.putBoolean("enable_module", enableModuleCheckBox.isChecked());
        editor.putBoolean("enable_logging", enableLoggingCheckBox.isChecked());
        editor.putString("target_package", targetPackageEditText.getText().toString());
        editor.apply();
        
        // 确保文件可读
        try {
            Runtime.getRuntime().exec("chmod 644 " + getSharedPrefsFile(PREFS_NAME).getAbsolutePath());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private void testModule() {
        // 测试模块功能
        boolean isXposedActive = false;
        try {
            // 检查 Xposed 是否激活
            isXposedActive = de.robv.android.xposed.XposedBridge.getXposedVersion() > 0;
        } catch (Throwable t) {
            // Xposed 未激活
        }
        
        if (isXposedActive) {
            showToast("Xposed 框架已激活,模块可以正常工作");
        } else {
            showToast("Xposed 框架未激活,请检查安装");
        }
    }
    
    private void showToast(String message) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }
}
<!-- res/layout/activity_main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">
    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Xposed 模块配置"
        android:textSize="24sp"
        android:textStyle="bold"
        android:gravity="center"
        android:layout_marginBottom="24dp" />
    
    <CheckBox
        android:id="@+id/enableModuleCheckBox"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启用模块"
        android:textSize="18sp"
        android:layout_marginBottom="16dp" />
    
    <CheckBox
        android:id="@+id/enableLoggingCheckBox"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启用日志记录"
        android:textSize="18sp"
        android:layout_marginBottom="16dp" />
    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="目标包名:"
        android:textSize="16sp"
        android:layout_marginBottom="8dp" />
    
    <EditText
        android:id="@+id/targetPackageEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="com.example.app"
        android:layout_marginBottom="24dp" />
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        
        <Button
            android:id="@+id/saveButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="保存设置"
            android:layout_marginEnd="8dp" />
        
        <Button
            android:id="@+id/testButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="测试模块"
            android:layout_marginStart="8dp" />
    </LinearLayout>
    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="注意:修改设置后需要重启目标应用才能生效"
        android:textSize="14sp"
        android:textColor="#666"
        android:layout_marginTop="24dp"
        android:gravity="center" />
    
</LinearLayout>

调试和测试

日志调试

// LogUtils.java - 日志工具类
package com.example.xposedmodule.utils;

import de.robv.android.xposed.XposedBridge;

public class LogUtils {
    
    private static final String TAG = "XposedModule";
    private static boolean DEBUG = true;
    
    public static void d(String message) {
        if (DEBUG) {
            XposedBridge.log(TAG + ": " + message);
        }
    }
    
    public static void i(String message) {
        XposedBridge.log(TAG + ": " + message);
    }
    
    public static void w(String message) {
        XposedBridge.log(TAG + ": WARNING - " + message);
    }
    
    public static void e(String message) {
        XposedBridge.log(TAG + ": ERROR - " + message);
    }
    
    public static void e(String message, Throwable throwable) {
        XposedBridge.log(TAG + ": ERROR - " + message);
        XposedBridge.log(throwable);
    }
    
    public static void logMethodCall(String className, String methodName, Object... args) {
        if (DEBUG) {
            StringBuilder sb = new StringBuilder();
            sb.append("调用方法: ").append(className).append(".").append(methodName).append("(");
            for (int i = 0; i < args.length; i++) {
                if (i > 0) sb.append(", ");
                sb.append(args[i] != null ? args[i].toString() : "null");
            }
            sb.append(")");
            XposedBridge.log(TAG + ": " + sb.toString());
        }
    }
}

测试方法

# 1. 查看 Xposed 日志
adb logcat | grep "Xposed"

# 2. 查看模块日志
adb logcat | grep "XposedModule"

# 3. 检查模块是否加载
adb shell su -c "ls /data/data/de.robv.android.xposed.installer/conf/"

# 4. 重启 Zygote 进程(应用 Hook)
adb shell su -c "killall zygote"

# 5. 检查模块状态
adb shell am start -n de.robv.android.xposed.installer/.XposedInstallerActivity

常见问题和解决方案

兼容性问题

// CompatibilityHelper.java - 兼容性处理
package com.example.xposedmodule.utils;

import android.os.Build;
import de.robv.android.xposed.XposedHelpers;

public class CompatibilityHelper {
    
    // 检查 Android 版本兼容性
    public static boolean isCompatibleVersion() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
    }
    
    // 根据版本选择不同的 Hook 策略
    public static void hookMethodByVersion(String className, ClassLoader classLoader, 
                                         String methodName, Object callback) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // Android 10+ 的处理方式
            hookMethodForAndroid10Plus(className, classLoader, methodName, callback);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // Android 8-9 的处理方式
            hookMethodForAndroid8To9(className, classLoader, methodName, callback);
        } else {
            // 旧版本的处理方式
            hookMethodForLegacy(className, classLoader, methodName, callback);
        }
    }
    
    private static void hookMethodForAndroid10Plus(String className, ClassLoader classLoader, 
                                                  String methodName, Object callback) {
        // Android 10+ 特定的 Hook 逻辑
        try {
            XposedHelpers.findAndHookMethod(className, classLoader, methodName, callback);
        } catch (Throwable t) {
            LogUtils.e("Android 10+ Hook 失败", t);
        }
    }
    
    private static void hookMethodForAndroid8To9(String className, ClassLoader classLoader, 
                                                String methodName, Object callback) {
        // Android 8-9 特定的 Hook 逻辑
        try {
            XposedHelpers.findAndHookMethod(className, classLoader, methodName, callback);
        } catch (Throwable t) {
            LogUtils.e("Android 8-9 Hook 失败", t);
        }
    }
    
    private static void hookMethodForLegacy(String className, ClassLoader classLoader, 
                                          String methodName, Object callback) {
        // 旧版本特定的 Hook 逻辑
        try {
            XposedHelpers.findAndHookMethod(className, classLoader, methodName, callback);
        } catch (Throwable t) {
            LogUtils.e("旧版本 Hook 失败", t);
        }
    }
}

总结

Xposed 框架入门要点:

🎯 核心概念

  1. Hook 技术:拦截和修改方法调用
  2. 模块化设计:独立的功能模块
  3. 运行时修改:无需修改 APK 文件
  4. 系统级访问:深度定制 Android 系统

✅ 开发要点

  • 正确配置开发环境
  • 理解 Hook 生命周期
  • 处理兼容性问题
  • 实现安全的错误处理

🚀 最佳实践

  • 使用安全的 Hook 方法
  • 提供用户友好的配置界面
  • 详细的日志记录和调试
  • 考虑不同 Android 版本的兼容性

⚠️ 注意事项

  • 需要 Root 权限
  • 可能影响系统稳定性
  • 注意法律和道德规范
  • 及时更新适配新版本

掌握 Xposed 框架,开启 Android 深度定制之旅!


Xposed 框架为 Android 系统定制提供了强大的能力,但使用时需要谨慎和负责任。