首页
社区
课程
招聘
Xposed ART原理分析笔记
发表于: 2021-4-15 18:00 14769

Xposed ART原理分析笔记

2021-4-15 18:00
14769

这篇文章是我在看Xposed源码时所做的一些笔记内容,中间也参考了一些前人的分析文章这里都在最后列出了,除此之外还有一些内容纯属个人理解,如果有错误欢迎各位大佬斧正,感谢!

Xposed 相关源码: https://github.com/rovo89

Xposed注入进程的方式是通过zygote进程在forkAPP进程时使之加载XposedBridge.jar

根据XposedAndroid.mk文件可知在5.0以上的手机上编译的是app_main2.cpp

这里选取Android 7.1.1_r6app_main.cpp文件与app_main2.cpp做对比

main函数看起

图片描述

从文件的对比可以发现,app_main2.cpp中多出了对于 Xposed::handleOptions的调用,而这个函数主要是对--xposedversion的处理以及是否测试模式的启用,真正运行时无需理会

main函数的最后,增加了对Xposed的加载与runtimeStart函数的调用。

图片描述

initialize函数最终返回XposedBridge.jar是否成功加入环境变量的标志和XposedInstaller是否成功运行的标志

首先对xposed这个结构体变量进行赋值

然后在logcat中通过printStartupMarker函数和printRomInfo函数打印一些信息

然后以下函数通过启动XposedInstaller和相应Xposed服务

最后如果XPosed能够正常加载,那么就通过函数addJarToClasspathXposedBridge.jar文件加入环境变量

这里如果想要禁用Xposed只需要在XposedInstaller的私有目录下创建一个conf/disabled文件即可。

如果成功加载则调用runtimeStart函数对调用AndroidRuntime::start()函数对de.robv.android.xposed.XposedBridge类进行启动

AndroidRuntime::start()函数经过观察发现实际上完成了几个工作

1.startVm函数,启动虚拟机

2.反射调用传入的类的main函数作为虚拟机的入口点

图片描述

Xposed就是通过替换这个className来达到加载自己的art虚拟机的效果。这样就成功注入了XposedBridge.jar文件,达到任意APP在加载时内存空间中总会有XposedBridge.jar

XposedBridge.jar文件的main函数如下,其实就是一个对SELinux的处理以及对Xposed模块的加载。

对模块的加载是通过对XposedInstaller私有目录下的conf/modules.list文件进行读取,并分别是通过BOOTCLASSLOADER对模块进行加载。

在最终的loadModule函数中实际上是通过DexFile的构造函数将模块加载并通过dexFile.loadClass函数的方式对入口类进行加载。最终达到模块注入的效果

我们知道Xposed hook函数的方式是大致是通过以下模版完成的

其中最关键的执行hook逻辑的函数实际上是XposedHelpers.findAndHookMethod()函数

我们从这个函数跟踪起

图片描述

观察这个函数分为两个部分

第一部分,用于获取回调的部分实际上就是获取参数的最后一个值,而用于寻找hook对应函数的findMethodExact函数,如下所示实际上就是通过反射获取,具体代码如下:

第二部分,执行hook逻辑的函数其内容主要分为三个部分

1.检查要hook的函数是否合法,必须同时满足三个条件:第一,是普通函数或者构造函数;第二,所在类不是接口Interface;第三,函数不是abstract抽象函数。

图片描述
2.从缓存中确认函数未被hook并将新函数加入缓存。

图片描述

3.执行真实hook逻辑,具体代码如下。可以发现真实执行hook逻辑的函数交给了hookMethodNative函数,而这个函数实际上是一个native属性的函数。

图片描述

而这个函数的C++实现在libxposed_art.cpp文件中。观察其函数发现,实际上就是将Java层的Method转换成了ArtMethod,然后通过ArtMethod类的EnableXposedHook函数执行hook

EnableXposedHook函数的实现就在Xposed修改的art代码中了,打开android_art工程,找到对应实现runtime/art_method.cc文件。

具体实现分为几步

1.备份原先的Method并添加标记kAccXposedOriginalMethod

2.创建一个备份方法对应的反射对象

3.将所有相关内容保存为一个结构体存储

4.准备工作,处理函数的JIT即时编译以及其他

5.设置被hook函数的入口点(关键的hook逻辑)

6.恢复环境

这样就执行完成了函数的hook

当被hook的函数执行时,我们直接从ArtMethod->Invoke函数入手。

由于被hook的函数属性是一个native属性,观察函数中重要逻辑。由于在设置函数时已经设置过函数入口点为entry_point_from_quick_compiled_code_不为false则会进入art_quick_invoke_stub或者art_quick_invoke_static_stub跳板函数。

这里以art_quick_invoke_stub非静态函数为例,最终不管是arm还是arm64都是以汇编实现的这个函数,只是arm在真实执行函数时有一些中间的跳板,最终实现函数为art_quick_invoke_stub_internal

arm为例,其实现函数所在文件为android_art/runtime/arch/arm/quick_entrypoints_arm.S,汇编中存在着一个ART_METHOD_QUICK_CODE_OFFSET_32这个函数的调用。

ART_METHOD_QUICK_CODE_OFFSET_32函数定义在runtime/asm_support.h文件中实现如下

EntryPointFromQuickCompiledCodeOffset函数是一个获取PtrSizedFields结构体固定偏移的函数,这里就是获取的entry_point_from_quick_compiled_code_变量的值。

这里由于Xposed对这个函数进行了hook,实际上就是获取的art_quick_proxy_invoke_handler函数的地址。

故最终在art_quick_invoke_stub_internal也就是调用的art_quick_proxy_invoke_handler函数。而在这个art_quick_proxy_invoke_handler函数中,又再次调用了artQuickProxyInvokeHandler函数。

artQuickProxyInvokeHandler函数中又看到了一堆xposed相关的信息,其具体实现在android_art/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc

这里我梳理了一下Xposed相关的重要代码列出来,具体如下:

观察发现实际上最重要的就是InvokeXposedHandleHookedMethod函数的调用,其具体内容主要分成三部分。

1.处理参数信息

2.调用XposedBridge.handleHookedMethod()函数

3.处理结果并返回

在这三个部分中最最重要的实际上是第二部分。

其中首先通过GetXposedHookInfo()函数调用GetEntryPointFromJniPtrSize()函数获取Xposed在设置函数hook时保存在entry_point_from_jni_中的XposedHookInfo对象信息。

然后拼接参数并通过CallStaticObjectMethodA()函数JNI调用XposedBridge.handleHookedMethod(Member method, int originalMethodId, Object additionalInfoObj,Object thisObject, Object[] args)函数这样就再次回到Java层中。

此时再次回到XposedBridge的源码,找到对应handleHookedMethod函数的实现会发现

2.然后通过invokeOriginalMethodNative调用原函数

3.最后执行所有的afterHookedMethod回调。

其中invokeOriginalMethodNative函数则是通过保存的reflected_method反射对象对原函数进行反射调用,也就是通过原art函数InvokeMethod()函数进行调用。

https://blog.csdn.net/weixin_47883636/article/details/109018440

https://egguncle.github.io/2018/02/04/xposed-art-hook-%E6%B5%85%E6%9E%90/

https://bbs.pediy.com/thread-257844.htm

 
ifeq (1,$(strip $(shell expr $(PLATFORM_SDK_VERSION) \>= 21))) # if Android_Version >= 5.0
  LOCAL_SRC_FILES := app_main2.cpp
  LOCAL_MULTILIB := both
  LOCAL_MODULE_STEM_32 := app_process32_xposed
  LOCAL_MODULE_STEM_64 := app_process64_xposed
else
  LOCAL_SRC_FILES := app_main.cpp
  LOCAL_MODULE_STEM := app_process_xposed
endif
ifeq (1,$(strip $(shell expr $(PLATFORM_SDK_VERSION) \>= 21))) # if Android_Version >= 5.0
  LOCAL_SRC_FILES := app_main2.cpp
  LOCAL_MULTILIB := both
  LOCAL_MODULE_STEM_32 := app_process32_xposed
  LOCAL_MODULE_STEM_64 := app_process64_xposed
else
  LOCAL_SRC_FILES := app_main.cpp
  LOCAL_MODULE_STEM := app_process_xposed
endif
 
 
 
bool handleOptions(int argc, char* const argv[]) {
    // version 信息
    parseXposedProp();
 
    if (argc == 2 && strcmp(argv[1], "--xposedversion") == 0) {
        printf("Xposed version: %s\n", xposedVersion);
        return true;
    }
 
    if (argc == 2 && strcmp(argv[1], "--xposedtestsafemode") == 0) {
        printf("Testing Xposed safemode trigger\n");
 
        if (detectSafemodeTrigger(shouldSkipSafemodeDelay())) {
            printf("Safemode triggered\n");
        } else {
            printf("Safemode not triggered\n");
        }
        return true;
    }
 
    // From Lollipop coding, used to override the process name
    argBlockStart = argv[0];
    uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
    uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]);
    end += strlen(argv[argc - 1]) + 1;
    argBlockLength = end - start;
 
    return false;
}
bool handleOptions(int argc, char* const argv[]) {
    // version 信息
    parseXposedProp();
 
    if (argc == 2 && strcmp(argv[1], "--xposedversion") == 0) {
        printf("Xposed version: %s\n", xposedVersion);
        return true;
    }
 
    if (argc == 2 && strcmp(argv[1], "--xposedtestsafemode") == 0) {
        printf("Testing Xposed safemode trigger\n");
 
        if (detectSafemodeTrigger(shouldSkipSafemodeDelay())) {
            printf("Safemode triggered\n");
        } else {
            printf("Safemode not triggered\n");
        }
        return true;
    }
 
    // From Lollipop coding, used to override the process name
    argBlockStart = argv[0];
    uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
    uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]);
    end += strlen(argv[argc - 1]) + 1;
    argBlockLength = end - start;
 
    return false;
}
 
 
 
struct XposedShared {
    // Global variables
    bool zygote;
    bool startSystemServer;
    const char* startClassName;
    uint32_t xposedVersionInt;
    bool isSELinuxEnabled;
    bool isSELinuxEnforcing;
    uid_t installer_uid;
    gid_t installer_gid;
 
    // Provided by runtime-specific library, used by executable
    void (*onVmCreated)(JNIEnv* env);
 
#if XPOSED_WITH_SELINUX
    // Provided by the executable, used by runtime-specific library
    int (*zygoteservice_accessFile)(const char* path, int mode);
    int (*zygoteservice_statFile)(const char* path, struct stat* st);
    char* (*zygoteservice_readFile)(const char* path, int* bytesRead);
#endif
};
XposedShared* xposed = new XposedShared;   
xposed->zygote = zygote;
xposed->startSystemServer = startSystemServer;
xposed->startClassName = className;
xposed->xposedVersionInt = xposedVersionInt;
 
#if XPOSED_WITH_SELINUX
    xposed->isSELinuxEnabled   = is_selinux_enabled() == 1;
    xposed->isSELinuxEnforcing = xposed->isSELinuxEnabled && security_getenforce() == 1;
#else
    xposed->isSELinuxEnabled   = false;
    xposed->isSELinuxEnforcing = false;
#endif  // XPOSED_WITH_SELINUX
struct XposedShared {
    // Global variables
    bool zygote;
    bool startSystemServer;
    const char* startClassName;
    uint32_t xposedVersionInt;
    bool isSELinuxEnabled;
    bool isSELinuxEnforcing;
    uid_t installer_uid;
    gid_t installer_gid;
 
    // Provided by runtime-specific library, used by executable
    void (*onVmCreated)(JNIEnv* env);
 
#if XPOSED_WITH_SELINUX
    // Provided by the executable, used by runtime-specific library
    int (*zygoteservice_accessFile)(const char* path, int mode);
    int (*zygoteservice_statFile)(const char* path, struct stat* st);
    char* (*zygoteservice_readFile)(const char* path, int* bytesRead);
#endif
};
XposedShared* xposed = new XposedShared;   
xposed->zygote = zygote;
xposed->startSystemServer = startSystemServer;
xposed->startClassName = className;
xposed->xposedVersionInt = xposedVersionInt;
 
#if XPOSED_WITH_SELINUX
    xposed->isSELinuxEnabled   = is_selinux_enabled() == 1;
    xposed->isSELinuxEnforcing = xposed->isSELinuxEnabled && security_getenforce() == 1;
#else
    xposed->isSELinuxEnabled   = false;
    xposed->isSELinuxEnforcing = false;
#endif  // XPOSED_WITH_SELINUX
void printStartupMarker() {
    sprintf(marker, "Current time: %d, PID: %d", (int) time(NULL), getpid());
    ALOG(LOG_DEBUG, "XposedStartupMarker", marker, NULL);
}
void printRomInfo() {
    char release[PROPERTY_VALUE_MAX];
    char sdk[PROPERTY_VALUE_MAX];
    char manufacturer[PROPERTY_VALUE_MAX];
    char model[PROPERTY_VALUE_MAX];
    char rom[PROPERTY_VALUE_MAX];
    char fingerprint[PROPERTY_VALUE_MAX];
    char platform[PROPERTY_VALUE_MAX];
#if defined(__LP64__)
    const int bit = 64;
#else
    const int bit = 32;
#endif
 
    property_get("ro.build.version.release", release, "n/a");
    property_get("ro.build.version.sdk", sdk, "n/a");
    property_get("ro.product.manufacturer", manufacturer, "n/a");
    property_get("ro.product.model", model, "n/a");
    property_get("ro.build.display.id", rom, "n/a");
    property_get("ro.build.fingerprint", fingerprint, "n/a");
    property_get("ro.product.cpu.abi", platform, "n/a");
 
    ALOGI("-----------------");
    ALOGI("Starting Xposed version %s, compiled for SDK %d", xposedVersion, PLATFORM_SDK_VERSION);
    ALOGI("Device: %s (%s), Android version %s (SDK %s)", model, manufacturer, release, sdk);
    ALOGI("ROM: %s", rom);
    ALOGI("Build fingerprint: %s", fingerprint);
    ALOGI("Platform: %s, %d-bit binary, system server: %s", platform, bit, xposed->startSystemServer ? "yes" : "no");
    if (!xposed->zygote) {
        ALOGI("Class name: %s", xposed->startClassName);
    }
    ALOGI("SELinux enabled: %s, enforcing: %s",
            xposed->isSELinuxEnabled ? "yes" : "no",
            xposed->isSELinuxEnforcing ? "yes" : "no");
}
void printStartupMarker() {
    sprintf(marker, "Current time: %d, PID: %d", (int) time(NULL), getpid());
    ALOG(LOG_DEBUG, "XposedStartupMarker", marker, NULL);
}
void printRomInfo() {
    char release[PROPERTY_VALUE_MAX];
    char sdk[PROPERTY_VALUE_MAX];
    char manufacturer[PROPERTY_VALUE_MAX];
    char model[PROPERTY_VALUE_MAX];
    char rom[PROPERTY_VALUE_MAX];
    char fingerprint[PROPERTY_VALUE_MAX];
    char platform[PROPERTY_VALUE_MAX];
#if defined(__LP64__)
    const int bit = 64;
#else
    const int bit = 32;
#endif
 
    property_get("ro.build.version.release", release, "n/a");
    property_get("ro.build.version.sdk", sdk, "n/a");
    property_get("ro.product.manufacturer", manufacturer, "n/a");
    property_get("ro.product.model", model, "n/a");
    property_get("ro.build.display.id", rom, "n/a");
    property_get("ro.build.fingerprint", fingerprint, "n/a");
    property_get("ro.product.cpu.abi", platform, "n/a");
 
    ALOGI("-----------------");
    ALOGI("Starting Xposed version %s, compiled for SDK %d", xposedVersion, PLATFORM_SDK_VERSION);
    ALOGI("Device: %s (%s), Android version %s (SDK %s)", model, manufacturer, release, sdk);
    ALOGI("ROM: %s", rom);
    ALOGI("Build fingerprint: %s", fingerprint);
    ALOGI("Platform: %s, %d-bit binary, system server: %s", platform, bit, xposed->startSystemServer ? "yes" : "no");
    if (!xposed->zygote) {
        ALOGI("Class name: %s", xposed->startClassName);
    }
    ALOGI("SELinux enabled: %s, enforcing: %s",
            xposed->isSELinuxEnabled ? "yes" : "no",
            xposed->isSELinuxEnforcing ? "yes" : "no");
}
if (!determineXposedInstallerUidGid() || !xposed::service::startAll()) {
            return false;
}
if (!determineXposedInstallerUidGid() || !xposed::service::startAll()) {
            return false;
}
 
/** Create a flag file to disable Xposed. */
#if PLATFORM_SDK_VERSION >= 24
#define XPOSED_DIR "/data/user_de/0/de.robv.android.xposed.installer/"
#else
#define XPOSED_DIR "/data/data/de.robv.android.xposed.installer/"
#endif
 
#define XPOSED_LOAD_BLOCKER      XPOSED_DIR "conf/disabled"
void disableXposed() {
    int fd;
    // FIXME add a "touch" operation to xposed::service::membased
    fd = open(XPOSED_LOAD_BLOCKER, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
    if (fd >= 0)
        close(fd);
}
/** Create a flag file to disable Xposed. */
#if PLATFORM_SDK_VERSION >= 24
#define XPOSED_DIR "/data/user_de/0/de.robv.android.xposed.installer/"
#else
#define XPOSED_DIR "/data/data/de.robv.android.xposed.installer/"
#endif
 
#define XPOSED_LOAD_BLOCKER      XPOSED_DIR "conf/disabled"
void disableXposed() {
    int fd;
    // FIXME add a "touch" operation to xposed::service::membased
    fd = open(XPOSED_LOAD_BLOCKER, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
    if (fd >= 0)
        close(fd);
}
// XPOSED_CLASS_DOTS_ZYGOTE =  de.robv.android.xposed.XposedBridge
runtimeStart(runtime, isXposedLoaded ? "de.robv.android.xposed.XposedBridge" : "com.android.internal.os.ZygoteInit", args, zygote);
// XPOSED_CLASS_DOTS_ZYGOTE =  de.robv.android.xposed.XposedBridge
runtimeStart(runtime, isXposedLoaded ? "de.robv.android.xposed.XposedBridge" : "com.android.internal.os.ZygoteInit", args, zygote);
 
/* start the virtual machine */
  JniInvocation jni_invocation;
  jni_invocation.Init(NULL);
  JNIEnv* env;
  if (startVm(&mJavaVM, &env, zygote) != 0) {
      return;
  }
  onVmCreated(env);
/* start the virtual machine */
  JniInvocation jni_invocation;
  jni_invocation.Init(NULL);
  JNIEnv* env;
  if (startVm(&mJavaVM, &env, zygote) != 0) {
      return;
  }
  onVmCreated(env);
 
 
 
protected static void main(String[] args) {
        // Initialize the Xposed framework and modules
        try {
            if (!hadInitErrors()) {
                initXResources();
 
                SELinuxHelper.initOnce();
                SELinuxHelper.initForProcess(null);
 
                runtime = getRuntime();
                XPOSED_BRIDGE_VERSION = getXposedVersion();
 
                if (isZygote) {
          // 暂且忽略
                    XposedInit.hookResources();
                    XposedInit.initForZygote();
                }
            // 模块的加载
                XposedInit.loadModules();
            } else {
                Log.e(TAG, "Not initializing Xposed because of previous errors");
            }
        } catch (Throwable t) {
            Log.e(TAG, "Errors during Xposed initialization", t);
            disableHooks = true;
        }
 
        // Call the original startup code
        if (isZygote) {
            ZygoteInit.main(args);
        } else {
            RuntimeInit.main(args);
        }
    }
protected static void main(String[] args) {
        // Initialize the Xposed framework and modules
        try {
            if (!hadInitErrors()) {
                initXResources();
 
                SELinuxHelper.initOnce();
                SELinuxHelper.initForProcess(null);
 
                runtime = getRuntime();
                XPOSED_BRIDGE_VERSION = getXposedVersion();
 
                if (isZygote) {
          // 暂且忽略
                    XposedInit.hookResources();
                    XposedInit.initForZygote();
                }
            // 模块的加载
                XposedInit.loadModules();
            } else {
                Log.e(TAG, "Not initializing Xposed because of previous errors");
            }
        } catch (Throwable t) {
            Log.e(TAG, "Errors during Xposed initialization", t);
            disableHooks = true;
        }
 
        // Call the original startup code
        if (isZygote) {
            ZygoteInit.main(args);
        } else {
            RuntimeInit.main(args);
        }
    }
/*package*/ static void loadModules() throws IOException {
        final String filename = BASE_DIR + "conf/modules.list";
        BaseService service = SELinuxHelper.getAppDataFileService();
        if (!service.checkFileExists(filename)) {
            Log.e(TAG, "Cannot load any modules because " + filename + " was not found");
            return;
        }
 
        ClassLoader topClassLoader = XposedBridge.BOOTCLASSLOADER;
        ClassLoader parent;
        while ((parent = topClassLoader.getParent()) != null) {
            topClassLoader = parent;
        }
 
        InputStream stream = service.getFileInputStream(filename);
        BufferedReader apks = new BufferedReader(new InputStreamReader(stream));
        String apk;
        while ((apk = apks.readLine()) != null) {
      // 按行加载模块
            loadModule(apk, topClassLoader);
        }
        apks.close();
    }
/*package*/ static void loadModules() throws IOException {
        final String filename = BASE_DIR + "conf/modules.list";
        BaseService service = SELinuxHelper.getAppDataFileService();
        if (!service.checkFileExists(filename)) {
            Log.e(TAG, "Cannot load any modules because " + filename + " was not found");
            return;
        }
 
        ClassLoader topClassLoader = XposedBridge.BOOTCLASSLOADER;
        ClassLoader parent;
        while ((parent = topClassLoader.getParent()) != null) {
            topClassLoader = parent;
        }
 
        InputStream stream = service.getFileInputStream(filename);
        BufferedReader apks = new BufferedReader(new InputStreamReader(stream));
        String apk;
        while ((apk = apks.readLine()) != null) {
      // 按行加载模块
            loadModule(apk, topClassLoader);
        }
        apks.close();
    }
private static void loadModule(String apk, ClassLoader topClassLoader) {       
  ...
        DexFile dexFile;
        try {
            dexFile = new DexFile(apk);
        } catch (IOException e) {
            Log.e(TAG, "  Cannot load module", e);
            return;
        }
        // Instant Run的处理
        if (dexFile.loadClass(INSTANT_RUN_CLASS, topClassLoader) != null) {
            Log.e(TAG, "  Cannot load module, please disable \"Instant Run\" in Android Studio.");
            closeSilently(dexFile);
            return;
        }
 
        if (dexFile.loadClass(XposedBridge.class.getName(), topClassLoader) != null) {
            Log.e(TAG, "  Cannot load module:");
            Log.e(TAG, "  The Xposed API classes are compiled into the module's APK.");
            Log.e(TAG, "  This may cause strange issues and must be fixed by the module developer.");
            Log.e(TAG, "  For details, see: http://api.xposed.info/using.html");
            closeSilently(dexFile);
            return;
        }
  ...
}
private static void loadModule(String apk, ClassLoader topClassLoader) {       
  ...
        DexFile dexFile;
        try {
            dexFile = new DexFile(apk);
        } catch (IOException e) {
            Log.e(TAG, "  Cannot load module", e);
            return;
        }
        // Instant Run的处理
        if (dexFile.loadClass(INSTANT_RUN_CLASS, topClassLoader) != null) {
            Log.e(TAG, "  Cannot load module, please disable \"Instant Run\" in Android Studio.");
            closeSilently(dexFile);
            return;
        }
 
        if (dexFile.loadClass(XposedBridge.class.getName(), topClassLoader) != null) {
            Log.e(TAG, "  Cannot load module:");
            Log.e(TAG, "  The Xposed API classes are compiled into the module's APK.");
            Log.e(TAG, "  This may cause strange issues and must be fixed by the module developer.");
            Log.e(TAG, "  For details, see: http://api.xposed.info/using.html");
            closeSilently(dexFile);
            return;
        }
  ...
}
public class XposedHook implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
            Class clasz = loadPackageParam.classLoader.loadClass("xxxx"); //要hook的方法所在的类名
 
            XposedHelpers.findAndHookMethod(clazz, "xxx",String.class,String.class,String.class, new XC_MethodHook() { //要hook的方法名和参数类型,此处为三个String类型
 
                @Override //重写XC_MethodHook()的回调方法
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
 
 
                }
 
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.i("hook after result:",param.getResult().toString()); //打印返回值(String类型)
                }
            });
        }
    }
}
public class XposedHook implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
            Class clasz = loadPackageParam.classLoader.loadClass("xxxx"); //要hook的方法所在的类名
 
            XposedHelpers.findAndHookMethod(clazz, "xxx",String.class,String.class,String.class, new XC_MethodHook() { //要hook的方法名和参数类型,此处为三个String类型
 
                @Override //重写XC_MethodHook()的回调方法
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
 
 
                }
 
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.i("hook after result:",param.getResult().toString()); //打印返回值(String类型)
                }
            });
        }
    }
}
 
 
 
public static Method findMethodExact(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
        String fullMethodName = clazz.getName() + '#' + methodName + getParametersString(parameterTypes) + "#exact";
        // 缓存机制
        if (methodCache.containsKey(fullMethodName)) {
            Method method = methodCache.get(fullMethodName);
            if (method == null)
                throw new NoSuchMethodError(fullMethodName);
            return method;
        }
 
        try {
      // 真实逻辑
            Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
            method.setAccessible(true);
            methodCache.put(fullMethodName, method);
            return method;
        } catch (NoSuchMethodException e) {
            methodCache.put(fullMethodName, null);
            throw new NoSuchMethodError(fullMethodName);
        }
    }
public static Method findMethodExact(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
        String fullMethodName = clazz.getName() + '#' + methodName + getParametersString(parameterTypes) + "#exact";
        // 缓存机制
        if (methodCache.containsKey(fullMethodName)) {
            Method method = methodCache.get(fullMethodName);
            if (method == null)
                throw new NoSuchMethodError(fullMethodName);
            return method;
        }
 
        try {
      // 真实逻辑
            Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
            method.setAccessible(true);
            methodCache.put(fullMethodName, method);
            return method;
        } catch (NoSuchMethodException e) {
            methodCache.put(fullMethodName, null);
            throw new NoSuchMethodError(fullMethodName);
        }
    }
 
 
 
 
 
 
void XposedBridge_hookMethodNative(JNIEnv* env, jclass, jobject javaReflectedMethod,
            jobject, jint, jobject javaAdditionalInfo) {
    // Detect usage errors.
    // ScopedObjectAccess:访问管理对象时候调用,一是将jobject加入LocalReference二是线程切换为kRunnable状态,即离开安全区。
    ScopedObjectAccess soa(env);
    if (javaReflectedMethod == nullptr) {
#if PLATFORM_SDK_VERSION >= 23
        ThrowIllegalArgumentException("method must not be null");
#else
        ThrowIllegalArgumentException(nullptr, "method must not be null");
#endif
        return;
    }
 
    // Get the ArtMethod of the method to be hooked.
    ArtMethod* artMethod = ArtMethod::FromReflectedMethod(soa, javaReflectedMethod);
 
    // Hook the method
    artMethod->EnableXposedHook(soa, javaAdditionalInfo);
}
void XposedBridge_hookMethodNative(JNIEnv* env, jclass, jobject javaReflectedMethod,
            jobject, jint, jobject javaAdditionalInfo) {
    // Detect usage errors.
    // ScopedObjectAccess:访问管理对象时候调用,一是将jobject加入LocalReference二是线程切换为kRunnable状态,即离开安全区。
    ScopedObjectAccess soa(env);
    if (javaReflectedMethod == nullptr) {

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2021-4-15 18:08 被Simp1er编辑 ,原因:
收藏
免费 2
支持
分享
最新回复 (7)
雪    币: 3353
活跃值: (13998)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
2
2021-4-16 10:24
0
雪    币: 2270
活跃值: (5532)
能力值: ( LV8,RANK:146 )
在线值:
发帖
回帖
粉丝
3
珍惜Any [em_63]
还要感谢珍惜大佬的帖子
2021-4-16 21:22
0
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
2021-4-17 00:51
0
雪    币: 45
活跃值: (1359)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
收藏
2021-4-21 09:47
0
雪    币: 120
活跃值: (1597)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
2021-4-27 15:57
0
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
2021-5-3 10:23
0
雪    币: 78
活跃值: (1823)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
SetCodeItemOffset(0);
请问这个有什么特殊的用意吗?
2023-9-25 15:00
0
游客
登录 | 注册 方可回帖
返回
//