菜单

开发模块插件

模块插件使用场景

主要用于在云机中为指定应用注入自己的代码,对java层或native进行修改。

支持的功能

自动注入dex
自动注入so
内置java层Hook框架LspLant
内置native层Hook框架Dobby

模块示例下载

dplus_demo源码
dplus_demo模块

编译环境

该项目当前使用:

  • Android Gradle Plugin:8.6.0
  • Gradle Wrapper:8.7
  • compileSdk / targetSdk:34
  • minSdk:29
  • CMake:3.22.1
  • JDK:21

注意:请使用 JDK 21 编译。若使用更高版本的 JDK(例如 JDK 23),执行 ./gradlew assembleDebug 时可能出现如下错误:

Unsupported class file major version 67

环境准备

建议使用 Android Studio 打开并编译项目,同时提前安装好以下组件:

  • Android SDK Platform 34
  • Android SDK Build-Tools
  • CMake 3.22.1
  • Android NDK
  • JDK 21

下载和配置 JDK 21

方式一:通过 Android Studio 下载

  1. 打开 Android Studio。
  2. 进入 Settings / Preferences -> Build, Execution, Deployment -> Build Tools -> Gradle
  3. Gradle JDK 中选择 Download JDK...
  4. 版本选择 21,下载完成后应用配置即可。

如果你只在 Android Studio 中编译,这是最省事的方式。

方式二:手动安装 JDK 21

你也可以自行安装 OpenJDK 21 / Temurin 21,然后配置 JAVA_HOME

Linux / macOS 示例:

bash 复制代码
export JAVA_HOME=/path/to/jdk-21
export PATH=$JAVA_HOME/bin:$PATH

java -version

确认输出中包含 21 后,再执行编译命令。

如果你使用 zsh,可以将上面的两行环境变量追加到 ~/.zshrc 中长期生效。

如果你不想修改系统默认 JDK,也可以单独为 Gradle 指定 JDK 21。在 ~/.gradle/gradle.properties 或项目根目录的 gradle.properties 中加入:

properties 复制代码
org.gradle.java.home=/path/to/jdk-21

这样即使终端默认的 Java 版本不是 21,Gradle 也会优先使用这里指定的 JDK。

编译方法

使用 Android Studio 编译

  1. 使用 Android Studio 打开项目。
  2. 确认 Gradle JDKJDK 21
  3. 等待 Gradle Sync 完成。
  4. 执行 Build -> Make Project,或者直接编译 assembleDebug

使用命令行编译

先确认当前终端的 Java 版本为 21:

bash 复制代码
java -version
./gradlew -version

然后执行:

bash 复制代码
./gradlew assembleDebug

编译成功后,生成的 APK 默认位于:

bash 复制代码
app/build/outputs/apk/debug/app-debug.apk

常见问题

1. 出现 Unsupported class file major version 67

原因:当前 Gradle 进程使用了错误的 JDK 版本,通常是 JDK 23,而不是 JDK 21。

处理方式:

bash 复制代码
export JAVA_HOME=/path/to/jdk-21
export PATH=$JAVA_HOME/bin:$PATH
java -version
./gradlew assembleDebug

如果是在 Android Studio 中编译,请把 Gradle JDK 切换为 JDK 21。

如果你有多个 JDK 并且不想频繁切换,也可以使用上面的 org.gradle.java.home 方式固定 Gradle 使用 JDK 21。

模块安装

使用Android Studio打开该项目。编译后得到模块app-debug.apk

将该文件上传自云机中,例如/sdcard/Download/app-debug.apk路径下

通过下面的命令可进行安装和查看

复制代码
//首先连接到云机
adb connect xx.xx.xx.xx

//进入云机终端
adb shell

//然后安装模块
dplus install patch:/sdcard/Download/app-debug.apk

//成功安装后可以查看模块
dplus dump

//可以通过模块name卸载删除模块
dplus uninstall dplus_demo

模块开发介绍

模块源码结构如下图

config.json文件用于配置模块

native-lib.cpp中实现dobby的hook例子

Entry.java是java层hook的入口

config配置说明

该文件主要用于描述模块,并且引导注入的,样例数据如下

复制代码
{
    "name": "dplus_demo",   //模块名称,卸载时使用
    "package":"com.example.dplus_demo",  //模块的包名
    "desc": "module",       //模块的描述
    "type": "user",         //模块的类型,主要为system和user。
    "libs": "libdplus_demo.so",  //要注入的so,可以不配置或者通过';'配置多条
    "pattern": [
        "com.android.settings"   //需要生效的包名
    ]
}

dobby例子

下面演示了如何简单的对openat函数进行hook输出

复制代码
int (*source_openat)(int fd, const char *path, int oflag, int mode) = nullptr;

int MyOpenAt(int fd, const char *pathname, int flags, int mode) {
    LOGI("MyOpenAt  pathname %s",pathname);
    return source_openat(fd, pathname, flags, mode);
}

void HookOpenAt() {
    //查找函数地址
    void *__openat =
            DobbySymbolResolver("libc.so", "__openat");

    if (__openat == nullptr) {
        LOGI("__openat null ");
        return;
    }

    LOGI("拿到 __openat 地址 ");
    
    //通过dobby替换原函数
    if (DobbyHook((void *) __openat,
                  (void *) MyOpenAt,
                  (void **) &source_openat) == 0) {
        LOGI("DobbyHook __openat sucess");
    }
}

jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {

    LOGI("Test JNI_OnLoad 开始加载");
    HookOpenAt();
    return JNI_VERSION_1_6;
}

java层例子

init函数是作为应用启动完后的一个入口点,在这里执行相关逻辑即可。LspLant相关的代码进行了简单的修改,所以部分类和函数不是原名称。

复制代码
public class Entry {

    public String TAG="demo_Entry";

    public void init(Application app){
        DPLog.i(TAG,"enter init");
        LSPHelpers.findAndHookMethod("java.util.HashMap", app.getClassLoader(), "put",Object.class,Object.class, new LSP_MethodH() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                super.beforeHookedMethod(param);
                Log.i(TAG,"enter HashMap.put key:"+param.args[0]+",value:"+param.args[1]);
            }

            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
                Log.i(TAG,"leave HashMap.put");
            }
        });
    }

}

模块注入后的效果

该模块对应用Setting进行测试,关掉Setting应用重新打开时相关日志如下图

上一个
订单列表
下一个
谷歌三级验证
最近修改: 2026-04-22Powered by