首页
论坛
课程
招聘
[原创]ART/Dalvik环境下Xposed实现异同分析
2021-4-29 19:17 2439

[原创]ART/Dalvik环境下Xposed实现异同分析

2021-4-29 19:17
2439

写了一部分,先占个坑,后续补完

1. ART/Dalvik环境异同

2. Xposed底层实现逻辑变更

了解到ART/Dalvik的异同之后,我们再来看看我们的主题,当Android虚拟机DalvikARTXposed针对这种变化对其底层实现逻辑做了哪些变更呢?

 

首先从源头入手,Xposed框架在编译app_main文件时做了系统适配处理,针对不同版本的系统使用不同的app_main文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Android.mk
 
# PLATFORM_SDK_VERSION字段
# 参考xref: /build/core/version_defaults.mk
# PLATFORM_VERSION := 7.1.2
# PLATFORM_SDK_VERSION := 25
# 根据系统版本不同,7以上的版本使用app_main2.cpp来编译
ifeq (1,$(strip $(shell expr $(PLATFORM_SDK_VERSION) \>= 21)))
  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
 
##########################################################
# Library for Dalvik-/ART-specific functions
##########################################################
# 针对libxposed_xxx.cpp文件也是同样的道理
ifeq (1,$(strip $(shell expr $(PLATFORM_SDK_VERSION) \>= 21)))
  include frameworks/base/cmds/xposed/ART.mk
else
  include frameworks/base/cmds/xposed/Dalvik.mk
endif

那么下面我们分析下这两份文件的实现

2.1 app_main文件的实现变更

 

可以看到,在两份文件中针对AppRuntime类的修改大致是相同的,同样都是调用了xposed::onVmCreated

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// xposed.cpp
 
/** Load the libxposed_*.so library for the currently active runtime. */
// 同样都是调用了xposed.cpp的onVmCreated函数
void onVmCreated(JNIEnv* env) {
    // Determine the currently active runtime
    // 初始化xposed lib路径
    const char* xposedLibPath = NULL;
    // 轮询/proc/self/maps结果,查看系统到底是art还是dalvik再决定赋值
    // xposed.h
    // #define XPOSED_LIB_DALVIK        XPOSED_LIB_DIR "libxposed_dalvik.so"
    // #define XPOSED_LIB_ART           XPOSED_LIB_DIR "libxposed_art.so"
    if (!determineRuntime(&xposedLibPath)) {
        ALOGE("Could not determine runtime, not loading Xposed");
        return;
    }
    // 通过dlopen so文件,so文件由之前的determineRuntime函数配置
    // Load the suitable libxposed_*.so for it
    void* xposedLibHandle = dlopen(xposedLibPath, RTLD_NOW);
    if (!xposedLibHandle) {
        ALOGE("Could not load libxposed: %s", dlerror());
        return;
    }
 
    // Clear previous errors
    dlerror();
 
    // Initialize the library
    // dlsym 执行so文件中xposedInitLib函数,so文件就是上面被赋值的文件
    bool (*xposedInitLib)(XposedShared* shared) = NULL;
    *(void **) (&xposedInitLib) = dlsym(xposedLibHandle, "xposedInitLib");
    if (!xposedInitLib)  {
        ALOGE("Could not find function xposedInitLib");
        return;
    }
    // xposedInitLib函数如下,赋予xposed的onVmCreated为onVmCreatedCommon
    // 也就是libxposed_common.cpp的onVmCreatedCommon方法
 
    // bool xposedInitLib(XposedShared* shared) {
    //     xposed = shared;
    //     xposed->onVmCreated = &onVmCreatedCommon;
    //     return true;
    // }
 
#if XPOSED_WITH_SELINUX
    xposed->zygoteservice_accessFile = &service::membased::accessFile;
    xposed->zygoteservice_statFile   = &service::membased::statFile;
    xposed->zygoteservice_readFile   = &service::membased::readFile;
#endif  // XPOSED_WITH_SELINUX
    // 方法返回true,执行onVmCreatedCommon方法,到目前为止,流程都是相同的
    if (xposedInitLib(xposed)) {
        xposed->onVmCreated(env);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// libxposed_common.cpp
// 两份文件公有部分
 
void onVmCreatedCommon(JNIEnv* env) {
    // 判断xposed_bridge.jar是否正常载入以及zygote服务启动是否正常
    if (!initXposedBridge(env) || !initZygoteService(env)) {
        return;
    }
    // 判断虚拟机是否正常启动,这里调用onVmCreated就是libxposed_xx.so文件中自己的onVmCreated函数了,这里应该就是第一个变化点
    if (!onVmCreated(env)) {
        return;
    }
    // 多重判断之后,返回xposed已正确安装标识
    xposedLoadedSuccessfully = true;
    return;
}
 
bool initXposedBridge(JNIEnv* env) {
    // #define CLASS_XPOSED_BRIDGE  "de/robv/android/xposed/XposedBridge"
    // 通过FindClass获取XposedBridge类,判断xposed_bridge类是否正常加载
    classXposedBridge = env->FindClass(CLASS_XPOSED_BRIDGE);
    if (classXposedBridge == NULL) {
        ALOGE("Error while loading Xposed class '%s':", CLASS_XPOSED_BRIDGE);
        logExceptionStackTrace();
        env->ExceptionClear();
        return false;
    }
    // PS:这里没有理解做了什么
    classXposedBridge = reinterpret_cast<jclass>(env->NewGlobalRef(classXposedBridge));
 
    ALOGI("Found Xposed class '%s', now initializing", CLASS_XPOSED_BRIDGE);
    // xposed_bridge的函数是否通过RegisterNatives动态注册成功
    if (register_natives_XposedBridge(env, classXposedBridge) != JNI_OK) {
        ALOGE("Could not register natives for '%s'", CLASS_XPOSED_BRIDGE);
        logExceptionStackTrace();
        env->ExceptionClear();
        return false;
    }
    // 判断通过jni获取handleHookedMethod函数是否成功
    methodXposedBridgeHandleHookedMethod = env->GetStaticMethodID(classXposedBridge, "handleHookedMethod",
        "(Ljava/lang/reflect/Member;ILjava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
    if (methodXposedBridgeHandleHookedMethod == NULL) {
        ALOGE("ERROR: could not find method %s.handleHookedMethod(Member, int, Object, Object, Object[])", CLASS_XPOSED_BRIDGE);
        logExceptionStackTrace();
        env->ExceptionClear();
        return false;
    }
 
    return true;
}
 
int register_natives_XposedBridge(JNIEnv* env, jclass clazz) {
    // 动态注册XposedBridge相关的函数,形式如XposedBridge_hookMethodNative
    const JNINativeMethod methods[] = {
        NATIVE_METHOD(XposedBridge, hadInitErrors, "()Z"),
        NATIVE_METHOD(XposedBridge, getStartClassName, "()Ljava/lang/String;"),
        NATIVE_METHOD(XposedBridge, getRuntime, "()I"),
        NATIVE_METHOD(XposedBridge, startsSystemServer, "()Z"),
        NATIVE_METHOD(XposedBridge, getXposedVersion, "()I"),
        NATIVE_METHOD(XposedBridge, initXResourcesNative, "()Z"),
        // 关键函数,之后在findandhook中会涉及
        NATIVE_METHOD(XposedBridge, hookMethodNative, "(Ljava/lang/reflect/Member;Ljava/lang/Class;ILjava/lang/Object;)V"),
        NATIVE_METHOD(XposedBridge, setObjectClassNative, "(Ljava/lang/Object;Ljava/lang/Class;)V"),
        NATIVE_METHOD(XposedBridge, dumpObjectNative, "(Ljava/lang/Object;)V"),
        NATIVE_METHOD(XposedBridge, cloneToSubclassNative, "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;"),
        NATIVE_METHOD(XposedBridge, removeFinalFlagNative, "(Ljava/lang/Class;)V"),
#if PLATFORM_SDK_VERSION >= 21
        NATIVE_METHOD(XposedBridge, invokeOriginalMethodNative,
            "!(Ljava/lang/reflect/Member;I[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),
        NATIVE_METHOD(XposedBridge, closeFilesBeforeForkNative, "()V"),
        NATIVE_METHOD(XposedBridge, reopenFilesAfterForkNative, "()V"),
#endif
#if PLATFORM_SDK_VERSION >= 24
        NATIVE_METHOD(XposedBridge, invalidateCallersNative, "([Ljava/lang/reflect/Member;)V"),
#endif
    };
    return env->RegisterNatives(clazz, methods, NELEM(methods));
}

2.1.1 onVmCreated函数变更

到目前为止可以看到关于xposed::onVmCreated的调用流程最终走到了两份文件自己的onVmCreated方法,下面来看看这两个方法的差异

2.1.1.1 Dalvik时期的onVmCreated
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// libxposed_dalvik.cpp
 
/** Called very early during VM startup. */
bool onVmCreated(JNIEnv* env) {
    if (!initMemberOffsets(env))
        return false;
    // #define CLASS_MIUI_RESOURCES "android/content/res/MiuiResources"
    jclass classMiuiResources = env->FindClass(CLASS_MIUI_RESOURCES);
    if (classMiuiResources != NULL) {
        ClassObject* clazz = (ClassObject*)dvmDecodeIndirectRef(dvmThreadSelf(), classMiuiResources);
        if (dvmIsFinalClass(clazz)) {
            ALOGD("Removing final flag for class '%s'", CLASS_MIUI_RESOURCES);
            clazz->accessFlags &= ~ACC_FINAL;
        }
    }
    env->ExceptionClear();
    // 关键点
    // 获取invokeOriginalMethodNative方法的jmethodId
    // 将invokeOriginalMethodNative的native方法关联到XposedBridge_invokeOriginalMethodNative方法,为后续调用的时候使用
    Method* xposedInvokeOriginalMethodNative = (Method*) env->GetStaticMethodID(classXposedBridge, "invokeOriginalMethodNative",
        "(Ljava/lang/reflect/Member;I[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
    if (xposedInvokeOriginalMethodNative == NULL) {
        ALOGE("ERROR: could not find method %s.invokeOriginalMethodNative(Member, int, Class[], Class, Object, Object[])", CLASS_XPOSED_BRIDGE);
        dvmLogExceptionStackTrace();
        env->ExceptionClear();
        return false;
    }
    dvmSetNativeFunc(xposedInvokeOriginalMethodNative, XposedBridge_invokeOriginalMethodNative, NULL);
 
    objectArrayClass = dvmFindArrayClass("[Ljava/lang/Object;", NULL);
    if (objectArrayClass == NULL) {
        ALOGE("Error while loading Object[] class");
        dvmLogExceptionStackTrace();
        env->ExceptionClear();
        return false;
    }
 
    return true;
}
 
void XposedBridge_invokeOriginalMethodNative(const u4* args, JValue* pResult,
            const Method* method, ::Thread* self) {
    // 获取method
    Method* meth = (Method*) args[1];
    if (meth == NULL) {
        // 反射获取
        meth = dvmGetMethodFromReflectObj((Object*) args[0]);
        if (isMethodHooked(meth)) {
            meth = (Method*) meth->insns;
        }
    }
    ArrayObject* params = (ArrayObject*) args[2];
    ClassObject* returnType = (ClassObject*) args[3];
    Object* thisObject = (Object*) args[4]; // null for static methods
    ArrayObject* argList = (ArrayObject*) args[5];
 
    // invoke the method
    // 通过dvmInvokeMethod执行方法,dvmInvokeMethod是在虚拟机中执行java方法的方法,可以理解为c语言执行java方法
    pResult->l = dvmInvokeMethod(thisObject, meth, argList, params, returnType, true);
    return;
}

Dalvik版本的onVmCreated函数做的是为Java层invokeOriginalMethodNative设置Native方法,将原本的方法转成nativeXposedBridge_invokeOriginalMethodNative方法,再回调Java层的方法

2.1.1.2 ART时期的onVmCreated
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// libxposed_art.cpp
 
/** Called very early during VM startup. */
bool onVmCreated(JNIEnv*) {
    // 没有针对Resource的操作
    // TODO: Handle CLASS_MIUI_RESOURCES?
    // 为ArtMethod的两个属性赋值,而这个ArtMethod定义来自于Xposed的android_art
    // classXposedBridge和methodXposedBridgeHandleHookedMethod被赋值是在libxposed_common的initXposedBridge函数中
    // classXposedBridge = env->FindClass(CLASS_XPOSED_BRIDGE);
    // methodXposedBridgeHandleHookedMethod = env->GetStaticMethodID(classXposedBridge, "handleHookedMethod",
        "(Ljava/lang/reflect/Member;ILjava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
    ArtMethod::xposed_callback_class = classXposedBridge;
    ArtMethod::xposed_callback_method = methodXposedBridgeHandleHookedMethod;
    return true;
}

ART版本的onVmCreated函数做的是为ArtMethod赋值,classXposedBridgemethodXposedBridgeHandleHookedMethod都是之前在initXposedBridge函数中设置好的

 

现在关于onVmCreated的函数变更已经分析好了,下面正式开始分析main函数

2.1.2 统一的initialize函数流程

 

同样都是调用xposed::initialize函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// xposed.cpp
 
/** Initialize Xposed (unless it is disabled). */
bool initialize(bool zygote, bool startSystemServer, const char* className, int argc, char* const argv[]) {
#if !defined(XPOSED_ENABLE_FOR_TOOLS)
    if (!zygote)
        return false;
#endif
 
    if (isMinimalFramework()) {
        ALOGI("Not loading Xposed for minimal framework (encrypted device)");
        return false;
    }
    // xposed结构体赋值
    xposed->zygote = zygote;
    xposed->startSystemServer = startSystemServer;
    xposed->startClassName = className;
    xposed->xposedVersionInt = xposedVersionInt;
// 针对selinux做的操作
#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
 
    if (startSystemServer) {
        xposed::logcat::printStartupMarker();
    } else if (zygote) {
        // TODO Find a better solution for this
        // Give the primary Zygote process a little time to start first.
        // This also makes the log easier to read, as logs for the two Zygotes are not mixed up.
        sleep(10);
    }
    // 打印rom信息
    printRomInfo();
 
    if (startSystemServer) {
        // 在Android中一个UID的对应的就是一个可执行的程序,对于普通的程序其UID就是对应与GID,程序在Android系统留存期间,其UID不变。
        // xposed::service::startAll() fork子进程启动system context service和app context service
        // 启动xposed_service_system xposed_service_app
        if (!determineXposedInstallerUidGid() || !xposed::service::startAll()) {
            return false;
        }
        // fork调用xposed logcat进程,负责打印xposed日志
        xposed::logcat::start();
#if XPOSED_WITH_SELINUX
    } else if (xposed->isSELinuxEnabled) {
        // 启动xposed_zygote_service
        if (!xposed::service::startMembased()) {
            return false;
        }
#endif  // XPOSED_WITH_SELINUX
    }
 
#if XPOSED_WITH_SELINUX
    // Don't let any further forks access the Zygote service
    if (xposed->isSELinuxEnabled) {
        xposed::service::membased::restrictMemoryInheritance();
    }
#endif  // XPOSED_WITH_SELINUX
 
    // FIXME Zygote has no access to input devices, this would need to be check in system_server context
    if (zygote && !isSafemodeDisabled() && detectSafemodeTrigger(shouldSkipSafemodeDelay()))
        disableXposed();
 
    if (isDisabled() || (!zygote && shouldIgnoreCommand(argc, argv)))
        return false;
    // 把jar包加入到classpath当中
    return addJarToClasspath();
}
 
/** Add XposedBridge.jar to the Java classpath. */
bool addJarToClasspath() {
    ALOGI("-----------------");
 
    // Do we have a new version and are (re)starting zygote? Then load it!
    /*
    FIXME if you can
    if (xposed->startSystemServer && access(XPOSED_JAR_NEWVERSION, R_OK) == 0) {
        ALOGI("Found new Xposed jar version, activating it");
        if (rename(XPOSED_JAR_NEWVERSION, XPOSED_JAR) != 0) {
            ALOGE("Could not move %s to %s", XPOSED_JAR_NEWVERSION, XPOSED_JAR);
            return false;
        }
    }
    */
 
    if (access(XPOSED_JAR, R_OK) == 0) {
        // #define XPOSED_JAR "/system/framework/XposedBridge.jar"
        将xposed_bridge的jar加入classpath
        if (!addPathToEnv("CLASSPATH", XPOSED_JAR))
            return false;
 
        ALOGI("Added Xposed (%s) to CLASSPATH", XPOSED_JAR);
        return true;
    } else {
        ALOGE("ERROR: Could not access Xposed jar '%s'", XPOSED_JAR);
        return false;
    }
}

xposed::initialize函数主要做了些初始化的工作:为xposed结构体赋值、启动各个子线程、最后将xposed_bridge.jar引入,执行完xposed::initialize函数之后会返回一个isXposedLoaded标识,会根据这个标识决定是否具体传入的包名,之前步骤执行正确的话传入的包名应该是"de.robv.android.xposed.XposedBridge",来看看具体的runtime.start函数是怎样执行的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// frameworks/base/core/jni/AndroidRuntime.cpp
 
// runtime.start()函数
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ALOGD(">>>>>> START %s uid %d <<<<<<\n",
            className != NULL ? className : "(unknown)", getuid());
 
    static const String8 startSystemServer("start-system-server");
 
    /*
     * 'startSystemServer == true' means runtime is obsolete and not run from
     * init.rc anymore, so we print out the boot start event here.
     */
    for (size_t i = 0; i < options.size(); ++i) {
        if (options[i] == startSystemServer) {
           /* track our progress through the boot sequence */
           const int LOG_BOOT_PROGRESS_START = 3000;
           LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
        }
    }
 
    const char* rootDir = getenv("ANDROID_ROOT");
    if (rootDir == NULL) {
        rootDir = "/system";
        if (!hasDir("/system")) {
            LOG_FATAL("No root directory specified, and /android does not exist.");
            return;
        }
        setenv("ANDROID_ROOT", rootDir, 1);
    }
 
    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
    //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
 
    /* start the virtual machine */
    JniInvocation jni_invocation;
    // 加载虚拟机的核心库
    // 没有具体分析,加载的是libart.so/libdalvik.so
    jni_invocation.Init(NULL);
    JNIEnv* env;
    // 创建虚拟机
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    // 这个函数被xposed替换
    onVmCreated(env);
 
    /*
     * Register android functions.
     */
    // 注册andorid native函数
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
 
    /*
     * We want to call main() with a String array with arguments in it.
     * At present we have two arguments, the class name and an option string.
     * Create an array to hold them.
     */
    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;
    // 可以理解为为字符串申请空间
    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    assert(strArray != NULL);
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr != NULL);
    env->SetObjectArrayElement(strArray, 0, classNameStr);
 
    for (size_t i = 0; i < options.size(); ++i) {
        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
        assert(optionsStr != NULL);
        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    }
 
    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    char* slashClassName = toSlashClassName(className);
    // 获取字符串对应的类,此时类为xposed_bridge类,由于在initialize方法中已经被加入到classpath中,因此可以获取到
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        // 获取类的main方法jmethodID
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            // 执行main函数
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
 
#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
    free(slashClassName);
 
    ALOGD("Shutting down VM\n");
    if (mJavaVM->DetachCurrentThread() != JNI_OK)
        ALOGW("Warning: unable to detach main thread\n");
    if (mJavaVM->DestroyJavaVM() != 0)
        ALOGW("Warning: VM did not shut down cleanly\n");
}

runtime.start函数调用的是AndroidRuntimestart函数,关键点在于startVm(虚拟机的创建)、onVmCreated(虚拟机创建完成之后的初始化),CallStaticVoidMethod main(反射调用类的main函数),onVmCreated已经分析过了,下面分析下XposedBridgemain函数

2.1.2.1 反射调用XposedBridge.main函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// XposedBridge/XposedBridge.java
 
@SuppressWarnings("deprecation")
protected static void main(String[] args) {
    // Initialize the Xposed framework and modules
    // XposedBridge的入口
    try {
        if (!hadInitErrors()) {
            // 获取资源文件
            initXResources();
 
            SELinuxHelper.initOnce();
            SELinuxHelper.initForProcess(null);
 
            runtime = getRuntime();
            XPOSED_BRIDGE_VERSION = getXposedVersion();
            // 三个关键步骤
            if (isZygote) {
                // 针对资源文件的hook
                XposedInit.hookResources();
                // 针对方法的hook
                XposedInit.initForZygote();
            }
            // 加载hook模块列表的模块
            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
    // 最后回到了基本的zygote启动流程,不影响正常的启动,之前的操作都是为了hook的初始化
    if (isZygote) {
        ZygoteInit.main(args);
    } else {
        RuntimeInit.main(args);
    }
}

XposedBridge.main函数关键在于三个函数的调用:

  • hookResources
  • initForZygote
  • loadModules

我们重点关注下initForZygoteloadModules两个方法

2.1.2.2 XposedInit.initForZygote

我们分成几部分来看

第一部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// XposedBridge/XposedInit.java
 
if (needsToCloseFilesForFork()) {
    // 匿名内部类实例化XC_MethodHook抽象类
    XC_MethodHook callback = new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            XposedBridge.closeFilesBeforeForkNative();
        }
 
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            XposedBridge.reopenFilesAfterForkNative();
        }
    };
 
    Class<?> zygote = findClass("com.android.internal.os.Zygote", null);
    // hook nativeForkAndSpecialize
    // nativeForkAndSpecialize是Zygote的forkAndSpecialize的底层实现,调用fork()创建新进程,设置新进程的主线程id,重置gc性能数据,设置信号处理函数等功能
    hookAllMethods(zygote, "nativeForkAndSpecialize", callback);
    // hook nativeForkSystemServer
    // forkSystemServer是由Zygote的forkSystemServer的底层实现,调用fork()创建system server服务
    hookAllMethods(zygote, "nativeForkSystemServer", callback);
}

nativeForkAndSpecializenativeForkSystemServer同样都是利用Zygote利用fork来创建子进程的,我们看下Xposed框架会对这两个方法做什么操作

 

closeFilesBeforeForkNativereopenFilesAfterForkNative这两个方法同属于native,属于XposedBridgenative方法一般都是在initXposedBridge中动态注册的,方法是存在于各自的libxposed_xxx.so文件当中,不过这两个方法只存在于高版本系统中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// libxposed_common.cpp
 
#if PLATFORM_SDK_VERSION >= 21
        NATIVE_METHOD(XposedBridge, invokeOriginalMethodNative,
            "!(Ljava/lang/reflect/Member;I[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),
        NATIVE_METHOD(XposedBridge, closeFilesBeforeForkNative, "()V"),
        NATIVE_METHOD(XposedBridge, reopenFilesAfterForkNative, "()V"),
#endif
 
// libxposed_art.cpp
 
// 不太清楚做了什么
void XposedBridge_closeFilesBeforeForkNative(JNIEnv*, jclass) {
    gClosedFdTable = FileDescriptorTable::Create();
}
 
void XposedBridge_reopenFilesAfterForkNative(JNIEnv*, jclass) {
    gClosedFdTable->Reopen();
    delete gClosedFdTable;
    gClosedFdTable = NULL;
}
第二部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// normal process initialization (for new Activity, Service, BroadcastReceiver etc.)
// hook ActivityThread.handleBindApplication()方法的hook
findAndHookMethod(ActivityThread.class, "handleBindApplication", "android.app.ActivityThread.AppBindData", new XC_MethodHook() {
    @Override
    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
        // 获取activityThread
        ActivityThread activityThread = (ActivityThread) param.thisObject;
        // 获取AppBindData的appInfo
        ApplicationInfo appInfo = (ApplicationInfo) getObjectField(param.args[0], "appInfo");
        String reportedPackageName = appInfo.packageName.equals("android") ? "system" : appInfo.packageName;
        SELinuxHelper.initForProcess(reportedPackageName);
        // 获取AppBindData的instrumentationName
        ComponentName instrumentationName = (ComponentName) getObjectField(param.args[0], "instrumentationName");
        if (instrumentationName != null) {
            Log.w(TAG, "Instrumentation detected, disabling framework for " + reportedPackageName);
            XposedBridge.disableHooks = true;
            return;
        }
        CompatibilityInfo compatInfo = (CompatibilityInfo) getObjectField(param.args[0], "compatInfo");
        if (appInfo.sourceDir == null)
            return;
        // 设置mBoundApplication属性为AppBindData
        setObjectField(activityThread, "mBoundApplication", param.args[0]);
        loadedPackagesInProcess.add(reportedPackageName);
        // 通过activityThread获取当前已加载的apk
        LoadedApk loadedApk = activityThread.getPackageInfoNoCheck(appInfo, compatInfo);
        XResources.setPackageNameForResDir(appInfo.packageName, loadedApk.getResDir());
        // 打包成LoadPackageParam对象
        XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
        lpparam.packageName = reportedPackageName;
        lpparam.processName = (String) getObjectField(param.args[0], "processName");
        lpparam.classLoader = loadedApk.getClassLoader();
        lpparam.appInfo = appInfo;
        lpparam.isFirstApplication = true;
        // 针对lpparam的所有callback函数进行调用
        XC_LoadPackage.callAll(lpparam);
 
        if (reportedPackageName.equals(INSTALLER_PACKAGE_NAME))
            hookXposedInstaller(lpparam.classLoader);
    }
});
 
// XCallback.java
public static void callAll(Param param) {
    if (param.callbacks == null)
        throw new IllegalStateException("This object was not created for use with callAll");
    // 调用每个参数的callbacks数组每个对象的call方法
    for (int i = 0; i < param.callbacks.length; i++) {
        try {
            ((XCallback) param.callbacks[i]).call(param);
        } catch (Throwable t) { XposedBridge.log(t); }
    }
}
 
// XC_LoadPackage.java
@Override
protected void call(Param param) throws Throwable {
    // 也就是调用callbacks数组每个对象的handleLoadPackage方法
    if (param instanceof LoadPackageParam)
        handleLoadPackage((LoadPackageParam) param);
}

这一部分的主要逻辑是针对ActivityThreadhandleBindApplication方法做了hook操作,具体的操作就是设置ActivityThreadmBoundApplication的值,并实例化LoadPackageParam进行赋值,这里的LoadPackageParam实例也就是我们在开发过程中的lpparam

1
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable

我们从代码中已经知道了当lpparam封装好之后会调用它的callbacks数组每个对象的handleLoadPackage方法,那这个数组是什么时候被赋值的呢?从代码中可以发现数组是XposedBridge.sLoadedPackageCallbacks,它在下面这段代码中被赋值

1
2
3
4
5
6
7
// XposedBridge/XposedBridge.java
 
public static void hookLoadPackage(XC_LoadPackage callback) {
    synchronized (sLoadedPackageCallbacks) {
        sLoadedPackageCallbacks.add(callback);
    }
}

hookLoadPackage是在loadModules方法中被调用,这个部分我们在loadModules的时候再说

第三部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// system_server initialization
// 主要是对system_server做处理
if (Build.VERSION.SDK_INT < 21) {
    findAndHookMethod("com.android.server.ServerThread", null,
                      Build.VERSION.SDK_INT < 19 ? "run" : "initAndLoop", new XC_MethodHook() {
                          @Override
                          protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                              SELinuxHelper.initForProcess("android");
                              loadedPackagesInProcess.add("android");
                              // 道理同上
                              XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
                              lpparam.packageName = "android";
                              lpparam.processName = "android"; // it's actually system_server, but other functions return this as well
                              lpparam.classLoader = XposedBridge.BOOTCLASSLOADER;
                              lpparam.appInfo = null;
                              lpparam.isFirstApplication = true;
                              XC_LoadPackage.callAll(lpparam);
                          }
                      });
} else if (startsSystemServer) {
    findAndHookMethod(ActivityThread.class, "systemMain", new XC_MethodHook() {
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            final ClassLoader cl = Thread.currentThread().getContextClassLoader();
            findAndHookMethod("com.android.server.SystemServer", cl, "startBootstrapServices", new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    SELinuxHelper.initForProcess("android");
                    loadedPackagesInProcess.add("android");
                    // 道理同上
                    XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
                    lpparam.packageName = "android";
                    lpparam.processName = "android"; // it's actually system_server, but other functions return this as well
                    lpparam.classLoader = cl;
                    lpparam.appInfo = null;
                    lpparam.isFirstApplication = true;
                    XC_LoadPackage.callAll(lpparam);
                }
            });
        }
    });
}

这一部分和上一部分道理相同,只是Hook点的不同,一个是针对App启动过程中,一个是针对system server

2.1.2.3 XposedInit.loadModules
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// XposedBridge/XposedInit
 
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;
    }
    // public static final ClassLoader BOOTCLASSLOADER = ClassLoader.getSystemClassLoader();
    // 获取classloader
    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;
    // 每行读取apk,调用loadMudle()
    while ((apk = apks.readLine()) != null) {
        loadModule(apk, topClassLoader);
    }
    apks.close();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// XposedBridge/XposedInit
 
private static void loadModule(String apk, ClassLoader topClassLoader) {
    Log.i(TAG, "Loading modules from " + apk);
    // 判断Xposed模块是否存在
    if (!new File(apk).exists()) {
        Log.e(TAG, "  File does not exist");
        return;
    }
 
    DexFile dexFile;
    try {
        dexFile = new DexFile(apk);
    } catch (IOException e) {
        Log.e(TAG, "  Cannot load module", e);
        return;
    }
 
    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;
    }
 
    closeSilently(dexFile);
 
    ZipFile zipFile = null;
    InputStream is;
    try {
        zipFile = new ZipFile(apk);
        // 获取模块中的assets/xposed_init,也就是我们开发过程中指定Xposed入口的文件
        ZipEntry zipEntry = zipFile.getEntry("assets/xposed_init");
        if (zipEntry == null) {
            Log.e(TAG, "  assets/xposed_init not found in the APK");
            closeSilently(zipFile);
            return;
        }
        is = zipFile.getInputStream(zipEntry);
    } catch (IOException e) {
        Log.e(TAG, "  Cannot read assets/xposed_init in the APK", e);
        closeSilently(zipFile);
        return;
    }
 
    ClassLoader mcl = new PathClassLoader(apk, XposedBridge.BOOTCLASSLOADER);
    // 读取assets/xposed_init文件
    BufferedReader moduleClassesReader = new BufferedReader(new InputStreamReader(is));
    try {
        String moduleClassName;
        while ((moduleClassName = moduleClassesReader.readLine()) != null) {
            moduleClassName = moduleClassName.trim();
            if (moduleClassName.isEmpty() || moduleClassName.startsWith("#"))
                continue;
 
            try {
                // 获取Xposed模块入口类名
                Log.i(TAG, "  Loading class " + moduleClassName);
                Class<?> moduleClass = mcl.loadClass(moduleClassName);
 
                if (!IXposedMod.class.isAssignableFrom(moduleClass)) {
                    Log.e(TAG, "    This class doesn't implement any sub-interface of IXposedMod, skipping it");
                    continue;
                } else if (disableResources && IXposedHookInitPackageResources.class.isAssignableFrom(moduleClass)) {
                    Log.e(TAG, "    This class requires resource-related hooks (which are disabled), skipping it.");
                    continue;
                }
                // 获取实例
                final Object moduleInstance = moduleClass.newInstance();
                if (XposedBridge.isZygote) {
                    if (moduleInstance instanceof IXposedHookZygoteInit) {
                        IXposedHookZygoteInit.StartupParam param = new IXposedHookZygoteInit.StartupParam();
                        param.modulePath = apk;
                        param.startsSystemServer = startsSystemServer;
                        ((IXposedHookZygoteInit) moduleInstance).initZygote(param);
                    }
 
                    if (moduleInstance instanceof IXposedHookLoadPackage)
                        // 调用内部类IXposedHookLoadPackage.Wrapper构造方法生成XC_LoadPackage类,就可以被hookLoadPackage调用
                        XposedBridge.hookLoadPackage(new IXposedHookLoadPackage.Wrapper((IXposedHookLoadPackage) moduleInstance));
 
                    if (moduleInstance instanceof IXposedHookInitPackageResources)
                        XposedBridge.hookInitPackageResources(new IXposedHookInitPackageResources.Wrapper((IXposedHookInitPackageResources) moduleInstance));
                } else {
                    if (moduleInstance instanceof IXposedHookCmdInit) {
                        IXposedHookCmdInit.StartupParam param = new IXposedHookCmdInit.StartupParam();
                        param.modulePath = apk;
                        param.startClassName = startClassName;
                        ((IXposedHookCmdInit) moduleInstance).initCmdApp(param);
                    }
                }
            } catch (Throwable t) {
                Log.e(TAG, "    Failed to load class " + moduleClassName, t);
            }
        }
    } catch (IOException e) {
        Log.e(TAG, "  Failed to load module from " + apk, e);
    } finally {
        closeSilently(is);
        closeSilently(zipFile);
    }
}
}

对于loadModules的流程我们也大致了解了

 

那么,对于xposed::initialize函数的分析就到这里,到目前为止,我们梳理完了Xposed框架的启动流程以及它在启动过程中做了哪些工作,当然,我们的主题是ART/Dalvik环境下Xposed框架实现的异同,我们在app_main文件变更这个步骤只发现了它们对于onVmCreated的实现做了改变

2.2 findAndHookMethod的实现变更

从刚才的initForZygote函数中,我们可以发现使用了大量的findAndHookMethod,当然,这个函数也是我们在接触Xposed框架的时候最先学会的函数,标准的模板调用是这么来使用的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// use.java
 
import android.app.Application;
import android.content.Context;
 
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
 
// 继承IXposedHookLoadPackage接口类
public class XposedHook implements IXposedHookLoadPackage {
    @Override
    // 重写handleLoadPackage方法
    public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        XposedHelpers.findAndHookMethod(
                Application.class,
                "attach",
                Context.class,
//                匿名内部类实现XC_MethodHook回调函数
                new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
                        super.afterHookedMethod(param);
                    }
                }
        );
    }
}

我们跟踪下findAndHookMethod的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// XpsoedBridge/XposedHelper.java
 
public static XC_MethodHook.Unhook findAndHookMethod(Class<?> clazz, String methodName, Object... parameterTypesAndCallback) {
    // 没有回调函数或是回调函数的类型不是XC_MethodHook都会报错
    if (parameterTypesAndCallback.length == 0 || !(parameterTypesAndCallback[parameterTypesAndCallback.length-    1] instanceof XC_MethodHook))
        throw new IllegalArgumentException("no callback defined");
    // 获取回调函数
    XC_MethodHook callback = (XC_MethodHook) parameterTypesAndCallback[parameterTypesAndCallback.length-1];
    // 通过类、方法名,参数准确定位需要hook的方法
    Method m = findMethodExact(clazz, methodName, getParameterClasses(clazz.getClassLoader(),                     parameterTypesAndCallback));
    // 调用XposedBridge.hookMethod,传入方法和回调函数
    return XposedBridge.hookMethod(m, callback);
}
 
public static Method findMethodExact(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
    // private static final HashMap<String, Method> methodCache = new HashMap<>();
    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);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// XpsoedBridge/XpsoedBridge.java
 
public static XC_MethodHook.Unhook hookMethod(Member hookMethod, XC_MethodHook callback) {
    // hook函数合法性检查
    // 必须是普通函数或者是构造函数
    if (!(hookMethod instanceof Method) && !(hookMethod instanceof Constructor<?>)) {
        throw new IllegalArgumentException("Only methods and constructors can be hooked: " + hookMethod.toString());
        // 函数的类不能是接口类,可以寻找接口类的实现类,hook实现类的函数
    } else if (hookMethod.getDeclaringClass().isInterface()) {
        throw new IllegalArgumentException("Cannot hook interfaces: " + hookMethod.toString());
        // 函数不能是抽象函数
    } else if (Modifier.isAbstract(hookMethod.getModifiers())) {
        throw new IllegalArgumentException("Cannot hook abstract methods: " + hookMethod.toString());
    }
 
    boolean newMethod = false;
    CopyOnWriteSortedSet<XC_MethodHook> callbacks;
    // sHookedMethodCallbacks保存回调函数的cow setmap
    // 考虑针对某一个method有多个回调函数
    // private static final Map<Member, CopyOnWriteSortedSet<XC_MethodHook>> sHookedMethodCallbacks = new HashMap<>();
    synchronized (sHookedMethodCallbacks) {
        callbacks = sHookedMethodCallbacks.get(hookMethod);
        if (callbacks == null) {
            callbacks = new CopyOnWriteSortedSet<>();
            sHookedMethodCallbacks.put(hookMethod, callbacks);
            newMethod = true;
        }
    }
    callbacks.add(callback);
 
    if (newMethod) {
        // 如果是新添加的回调方法,获取类、参数、返回值等
        Class<?> declaringClass = hookMethod.getDeclaringClass();
        int slot;
        Class<?>[] parameterTypes;
        Class<?> returnType;
        if (runtime == RUNTIME_ART) {
            slot = 0;
            parameterTypes = null;
            returnType = null;
        } else if (hookMethod instanceof Method) {
            slot = getIntField(hookMethod, "slot");
            parameterTypes = ((Method) hookMethod).getParameterTypes();
            returnType = ((Method) hookMethod).getReturnType();
        } else {
            slot = getIntField(hookMethod, "slot");
            parameterTypes = ((Constructor<?>) hookMethod).getParameterTypes();
            returnType = null;
        }
        AdditionalHookInfo additionalInfo = new AdditionalHookInfo(callbacks, parameterTypes, returnType);
        // 调用hookMethodNative
        hookMethodNative(hookMethod, declaringClass, slot, additionalInfo);
    }
 
    return callback.new Unhook(hookMethod);
}
 
// native函数,动态注册在initXposedBridge函数调用时,有两个版本的libxposed_xx实现
private native synchronized static void hookMethodNative(Member method, Class<?> declaringClass, int slot, Object additionalInfo);

2.2.1 Dalvik时期的hookMethodNative

先来看看Dalvik时期的,XposedBridge_hookMethodNative实现在libxposed_dalvik.cpp文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
// libxposed_dalvik.cpp
 
void XposedBridge_hookMethodNative(JNIEnv* env, jclass clazz, jobject reflectedMethodIndirect,
            jobject declaredClassIndirect, jint slot, jobject additionalInfoIndirect) {
    // Usage errors?
    if (declaredClassIndirect == NULL || reflectedMethodIndirect == NULL) {
        dvmThrowIllegalArgumentException("method and declaredClass must not be null");
        return;
    }
 
    // Find the internal representation of the method
    // dvmDecodeIndirectRef 将间接引用jobject转换为对象引用Object*
    ClassObject* declaredClass = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), declaredClassIndirect);
    // dvmSlotToMethod 根据偏移量,从ClassLoader中获取函数指针
    Method* method = dvmSlotToMethod(declaredClass, slot);
    if (method == NULL) {
        dvmThrowNoSuchMethodError("Could not get internal representation for method");
        return;
    }
 
    if (isMethodHooked(method)) {
        // already hooked
        return;
    }
 
    // Save a copy of the original method and other hook info
    // hookInfo属性配置
    XposedHookInfo* hookInfo = (XposedHookInfo*) calloc(1, sizeof(XposedHookInfo));
    memcpy(hookInfo, method, sizeof(hookInfo->originalMethodStruct));
    hookInfo->reflectedMethod = dvmDecodeIndirectRef(dvmThreadSelf(), env->NewGlobalRef(reflectedMethodIndirect));
    hookInfo->additionalInfo = dvmDecodeIndirectRef(dvmThreadSelf(), env->NewGlobalRef(additionalInfoIndirect));
 
    // Replace method with our own code
    // 修改method变成native方法
    SET_METHOD_FLAG(method, ACC_NATIVE);
    // 赋予method对象的native方法为hookedMethodCallback
    method->nativeFunc = &hookedMethodCallback;
    // method的insns数组保存method信息
    method->insns = (const u2*) hookInfo;
    method->registersSize = method->insSize;
    method->outsSize = 0;
 
    if (PTR_gDvmJit != NULL) {
        // reset JIT cache
        char currentValue = *((char*)PTR_gDvmJit + MEMBER_OFFSET_VAR(DvmJitGlobals,codeCacheFull));
        if (currentValue == 0 || currentValue == 1) {
            MEMBER_VAL(PTR_gDvmJit, DvmJitGlobals, codeCacheFull) = true;
        } else {
            ALOGE("Unexpected current value for codeCacheFull: %d", currentValue);
        }
    }
}
 
void hookedMethodCallback(const u4* args, JValue* pResult, const Method* method, ::Thread* self) {
    if (!isMethodHooked(method)) {
        dvmThrowNoSuchMethodError("Could not find Xposed original method - how did you even get here?");
        return;
    }
    // 获取属性
    XposedHookInfo* hookInfo = (XposedHookInfo*) method->insns;
    Method* original = (Method*) hookInfo;
    Object* originalReflected = hookInfo->reflectedMethod;
    Object* additionalInfo = hookInfo->additionalInfo;
 
    // convert/box arguments
    const char* desc = &method->shorty[1]; // [0] is the return type.
    Object* thisObject = NULL;
    size_t srcIndex = 0;
    size_t dstIndex = 0;
 
    // for non-static methods determine the "this" pointer
    if (!dvmIsStaticMethod(original)) {
        thisObject = (Object*) args[0];
        srcIndex++;
    }
 
    ArrayObject* argsArray = dvmAllocArrayByClass(objectArrayClass, strlen(method->shorty) - 1, ALLOC_DEFAULT);
    if (argsArray == NULL) {
        return;
    }
 
    while (*desc != '\0') {
        char descChar = *(desc++);
        JValue value;
        Object* obj;
 
        switch (descChar) {
        case 'Z':
        case 'C':
        case 'F':
        case 'B':
        case 'S':
        case 'I':
            value.i = args[srcIndex++];
            obj = (Object*) dvmBoxPrimitive(value, dvmFindPrimitiveClass(descChar));
            dvmReleaseTrackedAlloc(obj, self);
            break;
        case 'D':
        case 'J':
            value.j = dvmGetArgLong(args, srcIndex);
            srcIndex += 2;
            obj = (Object*) dvmBoxPrimitive(value, dvmFindPrimitiveClass(descChar));
            dvmReleaseTrackedAlloc(obj, self);
            break;
        case '[':
        case 'L':
            obj  = (Object*) args[srcIndex++];
            break;
        default:
            ALOGE("Unknown method signature description character: %c", descChar);
            obj = NULL;
            srcIndex++;
        }
        setObjectArrayElement(argsArray, dstIndex++, obj);
    }
 
    // call the Java handler function
    // JValue result;
    // dvmCallMethod调用函数methodXposedBridgeHandleHookedMethod
    // methodXposedBridgeHandleHookedMethod在initXposedBridge时候已经被赋值了,值为XposedBridge.handleHookedMethod函数
    dvmCallMethod(self, (Method*) methodXposedBridgeHandleHookedMethod, NULL, &result,
        originalReflected, (int) original, additionalInfo, thisObject, argsArray);
 
    dvmReleaseTrackedAlloc(argsArray, self);
 
    // exceptions are thrown to the caller
    if (dvmCheckException(self)) {
        return;
    }
 
    // return result with proper type
    ClassObject* returnType = dvmGetBoxedReturnType(method);
    if (returnType->primitiveType == PRIM_VOID) {
        // ignored
    } else if (result.l == NULL) {
        if (dvmIsPrimitiveClass(returnType)) {
            dvmThrowNullPointerException("null result when primitive expected");
        }
        pResult->l = NULL;
    } else {
        if (!dvmUnboxPrimitive(result.l, returnType, pResult)) {
            dvmThrowClassCastException(result.l->clazz, returnType);
        }
    }
}
 
private static Object handleHookedMethod(Member method, int originalMethodId, Object additionalInfoObj,
            Object thisObject, Object[] args) throws Throwable {
        AdditionalHookInfo additionalInfo = (AdditionalHookInfo) additionalInfoObj;
 
    if (disableHooks) {
        try {
            return invokeOriginalMethodNative(method, originalMethodId, additionalInfo.parameterTypes,
                                              additionalInfo.returnType, thisObject, args);
        } catch (InvocationTargetException e) {
            throw e.getCause();
        }
    }
 
    // 获取callback函数的副本
    Object[] callbacksSnapshot = additionalInfo.callbacks.getSnapshot();
    final int callbacksLength = callbacksSnapshot.length;
    // 没有回调函数直接直接原始函数
    if (callbacksLength == 0) {
        try {
            return invokeOriginalMethodNative(method, originalMethodId, additionalInfo.parameterTypes,
                                              additionalInfo.returnType, thisObject, args);
        } catch (InvocationTargetException e) {
            throw e.getCause();
        }
    }
    // 获取method的参数
    MethodHookParam param = new MethodHookParam();
    param.method = method;
    param.thisObject = thisObject;
    param.args = args;
 
    // 执行@beforeHookedMethod的函数
    // call "before method" callbacks
    int beforeIdx = 0;
    do {
        try {
            ((XC_MethodHook) callbacksSnapshot[beforeIdx]).beforeHookedMethod(param);
        } catch (Throwable t) {
            XposedBridge.log(t);
 
            // reset result (ignoring what the unexpectedly exiting callback did)
            param.setResult(null);
            param.returnEarly = false;
            continue;
        }
 
        if (param.returnEarly) {
            // skip remaining "before" callbacks and corresponding "after" callbacks
            beforeIdx++;
            break;
        }
    } while (++beforeIdx < callbacksLength);
 
    // call original method if not requested otherwise
    if (!param.returnEarly) {
        try {
            // invokeOriginalMethodNative也是native函数
            param.setResult(invokeOriginalMethodNative(method, originalMethodId,
                                                       additionalInfo.parameterTypes, additionalInfo.returnType, param.thisObject, param.args));
        } catch (InvocationTargetException e) {
            param.setThrowable(e.getCause());
        }
    }
 
    // 执行@afterHookedMethod的函数
    // call "after method" callbacks
    int afterIdx = beforeIdx - 1;
    do {
        Object lastResult =  param.getResult();
        Throwable lastThrowable = param.getThrowable();
 
        try {
            ((XC_MethodHook) callbacksSnapshot[afterIdx]).afterHookedMethod(param);
        } catch (Throwable t) {
            XposedBridge.log(t);
 
            // reset to last result (ignoring what the unexpectedly exiting callback did)
            if (lastThrowable == null)
                param.setResult(lastResult);
            else
                param.setThrowable(lastThrowable);
        }
    } while (--afterIdx >= 0);
 
    // return
    if (param.hasThrowable())
        throw param.getThrowable();
    else
        return param.getResult();
}

invokeOriginalMethodNativenative函数,想想它是在什么时候变成native函数的呢?

 

onVmCreated函数执行的时候,回顾一下

1
2
3
4
5
6
7
8
9
Method* xposedInvokeOriginalMethodNative = (Method*) env->GetStaticMethodID(classXposedBridge, "invokeOriginalMethodNative",
        "(Ljava/lang/reflect/Member;I[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
    if (xposedInvokeOriginalMethodNative == NULL) {
        ALOGE("ERROR: could not find method %s.invokeOriginalMethodNative(Member, int, Class[], Class, Object, Object[])", CLASS_XPOSED_BRIDGE);
        dvmLogExceptionStackTrace();
        env->ExceptionClear();
        return false;
    }
    dvmSetNativeFunc(xposedInvokeOriginalMethodNative, XposedBridge_invokeOriginalMethodNative, NULL);

通过dvmSetNativeFuncxposedInvokeOriginalMethodNative的真正执行函数变为xposedInvokeOriginalMethodNative

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void dvmSetNativeFunc(Method* method, DalvikBridgeFunc func,
    const u2* insns)
{
    ClassObject* clazz = method->clazz;
    assert(func != NULL);
    /* just open up both; easier that way */
    dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);
    dvmLinearReadWrite(clazz->classLoader, clazz->directMethods);
    if (insns != NULL) {
        /* update both, ensuring that "insns" is observed first */
        method->insns = insns;
        android_atomic_release_store((int32_t) func,
            (volatile int32_t*)(void*) &method->nativeFunc);
    } else {
        /* only update nativeFunc */
        没有insns数组,设置method的nativeFunc方法
        method->nativeFunc = func;
    }
    dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
    dvmLinearReadOnly(clazz->classLoader, clazz->directMethods);
}

xposedInvokeOriginalMethodNative方法我们之前也分析过,主要是通过dvmInvokeMethod来反射调用Java层的方法

2.2.2 知识点插入:Dalvik虚拟机执行Java方法流程

2.2.3 ART时期的hookMethodNative

分析完了Dalvik时期的hookMethodNative流程,下面来看看ART时期的hookMethodNative做了哪些改变,省略掉相同的步骤,我们直接看libxposed_art.cppXposedBridge_hookMethodNative函数实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// libxposed_art.cpp
 
void XposedBridge_hookMethodNative(JNIEnv* env, jclass, jobject javaReflectedMethod,
            jobject, jint, jobject javaAdditionalInfo) {
    // Detect usage errors.
    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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// android_art/art_method.cc
 
void ArtMethod::EnableXposedHook(ScopedObjectAccess& soa, jobject additional_info) {
  if (UNLIKELY(IsXposedHookedMethod())) {
    // Already hooked
    return;
  } else if (UNLIKELY(IsXposedOriginalMethod())) {
    // This should never happen
    ThrowIllegalArgumentException(StringPrintf("Cannot hook the method backup: %s", PrettyMethod(this).c_str()).c_str());
    return;
  }
 
  // Create a backup of the ArtMethod object
  // 获取classloader
  auto* cl = Runtime::Current()->GetClassLinker();
  auto* linear_alloc = cl->GetAllocatorForClassLoader(GetClassLoader());
  // 获取method
  ArtMethod* backup_method = cl->CreateRuntimeMethod(linear_alloc);
  // 备份并标记
  backup_method->CopyFrom(this, cl->GetImagePointerSize());
  backup_method->SetAccessFlags(backup_method->GetAccessFlags() | kAccXposedOriginalMethod);
 
  // Create a Method/Constructor object for the backup ArtMethod object
  mirror::AbstractMethod* reflected_method;
  if (IsConstructor()) {
    reflected_method = mirror::Constructor::CreateFromArtMethod(soa.Self(), backup_method);
  } else {
    reflected_method = mirror::Method::CreateFromArtMethod(soa.Self(), backup_method);
  }
  reflected_method->SetAccessible<false>(true);
 
  // Save extra information in a separate structure, stored instead of the native method
  // hookInfo结构体属性配置,与dalvik版本类似
  XposedHookInfo* hook_info = reinterpret_cast<XposedHookInfo*>(linear_alloc->Alloc(soa.Self(), sizeof(XposedHookInfo)));
  hook_info->reflected_method = soa.Vm()->AddGlobalRef(soa.Self(), reflected_method);
  hook_info->additional_info = soa.Env()->NewGlobalRef(additional_info);
  hook_info->original_method = backup_method;
 
  ScopedThreadSuspension sts(soa.Self(), kSuspended);
  // 停止JIT即时编译
  jit::ScopedJitSuspend sjs;
  // 防止死锁
  gc::ScopedGCCriticalSection gcs(soa.Self(),
                                  gc::kGcCauseXposed,
                                  gc::kCollectorTypeXposed);
  ScopedSuspendAll ssa(__FUNCTION__);
  // 取消所有调用
  cl->InvalidateCallersForMethod(soa.Self(), this);
  // 去除JIT编译的结果
  jit::Jit* jit = art::Runtime::Current()->GetJit();
  if (jit != nullptr) {
    jit->GetCodeCache()->MoveObsoleteMethod(this, backup_method);
  }
  // 将hook_info存到entry_point_from_jni这个指针
  SetEntryPointFromJniPtrSize(reinterpret_cast<uint8_t*>(hook_info), sizeof(void*));
  // 替换函数入口点entry_point_from_quick_compiled_code_为自己的GetQuickProxyInvokeHandler
  SetEntryPointFromQuickCompiledCode(GetQuickProxyInvokeHandler());
  // 设置函数在CodeItem偏移
  SetCodeItemOffset(0);
 
  // Adjust access flags.
  const uint32_t kRemoveFlags = kAccNative | kAccSynchronized | kAccAbstract | kAccDefault | kAccDefaultConflict;
  SetAccessFlags((GetAccessFlags() & ~kRemoveFlags) | kAccXposedHookedMethod);
 
  MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
  Runtime::Current()->GetThreadList()->ForEach(StackReplaceMethodAndInstallInstrumentation, this);
}

关键点在于函数的入口点的替换,由entry_point_from_quick_compiled_code_替换成了GetQuickProxyInvokeHandler

 

看看GetQuickProxyInvokeHandler的实现

1
2
3
4
5
6
7
// android_art/runtime/entrypoints/quick/runtime_asm_entrypoints.h
 
// Return the address of quick stub code for handling transitions into the proxy invoke handler.
extern "C" void art_quick_proxy_invoke_handler();
static inline const void* GetQuickProxyInvokeHandler() {
  return reinterpret_cast<const void*>(art_quick_proxy_invoke_handler);
}

GetQuickProxyInvokeHandler的具体逻辑由art_quick_proxy_invoke_handler方法来实现

 

从汇编文件入手

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
android_art\runtime\arch\arm\quick_entrypoints_arm.S
*/
 
/*
* Called by managed code that is attempting to call a method on a proxy class. On entry
* r0 holds the proxy method and r1 holds the receiver; r2 and r3 may contain arguments. The
* frame size of the invoked proxy method agrees with a ref and args callee save frame.
*/
     .extern artQuickProxyInvokeHandler
ENTRY art_quick_proxy_invoke_handler
    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_R0
    mov     r2, r9                 @ pass Thread::Current
    mov     r3, sp                 @ pass SP
    /*
    调用了artQuickProxyInvokeHandler函数
    */
    blx     artQuickProxyInvokeHandler  @ (Method* proxy method, receiver, Thread*, SP)
    ldr     r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
    // Tear down the callee-save frame. Skip arg registers.
    add     sp, #(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
    .cfi_adjust_cfa_offset -(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
    cbnz    r2, 1f                 @ success if no exception is pending
    vmov    d0, r0, r1             @ store into fpr, for when it's a fpr return...
    bx      lr                     @ return on success
1:
    DELIVER_PENDING_EXCEPTION
END art_quick_proxy_invoke_handler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// android_art/quick_trampoline_entrypoints.cc
 
extern "C" uint64_t artQuickProxyInvokeHandler(
    ArtMethod* proxy_method, mirror::Object* receiver, Thread* self, ArtMethod** sp)
    SHARED_REQUIRES(Locks::mutator_lock_) {
  // 判断是否是Xposed hook的函数,通过method标记来识别
  // Xposed
  // bool IsXposedHookedMethod() {
  //   return (GetAccessFlags() & kAccXposedHookedMethod) != 0;
  // }
  const bool is_xposed = proxy_method->IsXposedHookedMethod();
  if (!is_xposed) {
    DCHECK(proxy_method->IsRealProxyMethod()) << PrettyMethod(proxy_method);
    DCHECK(receiver->GetClass()->IsProxyClass()) << PrettyMethod(proxy_method);
  }
  // Ensure we don't get thread suspension until the object arguments are safely in jobjects.
  const char* old_cause =
      self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
  // Register the top of the managed stack, making stack crawlable.
  DCHECK_EQ((*sp), proxy_method) << PrettyMethod(proxy_method);
  self->VerifyStack();
  // Start new JNI local reference state.
  JNIEnvExt* env = self->GetJniEnv();
  ScopedObjectAccessUnchecked soa(env);
  ScopedJniEnvLocalRefState env_state(env);
  // Create local ref. copies of proxy method and the receiver.
  const bool is_static = proxy_method->IsStatic();
  jobject rcvr_jobj = is_static ? nullptr : soa.AddLocalReference<jobject>(receiver);
 
  // Placing arguments into args vector and remove the receiver.
  ArtMethod* non_proxy_method = proxy_method->GetInterfaceMethodIfProxy(sizeof(void*));
  CHECK(is_xposed || !non_proxy_method->IsStatic()) << PrettyMethod(proxy_method) << " "
                                                    << PrettyMethod(non_proxy_method);
  std::vector<jvalue> args;
  uint32_t shorty_len = 0;
  const char* shorty = non_proxy_method->GetShorty(&shorty_len);
  BuildQuickArgumentVisitor local_ref_visitor(sp, is_static, shorty, shorty_len, &soa, &args);
 
  local_ref_visitor.VisitArguments();
  if (!is_static) {
    DCHECK_GT(args.size(), 0U) << PrettyMethod(proxy_method);
    args.erase(args.begin());
  }
 
  if (is_xposed) {
    jmethodID proxy_methodid = soa.EncodeMethod(proxy_method);
    self->EndAssertNoThreadSuspension(old_cause);
    // 调用InvokeXposedHandleHookedMethod方法
    JValue result = InvokeXposedHandleHookedMethod(soa, shorty, rcvr_jobj, proxy_methodid, args);
    local_ref_visitor.FixupReferences();
    return result.GetJ();
  }
 
  // Convert proxy method into expected interface method.
  ArtMethod* interface_method = proxy_method->FindOverriddenMethod(sizeof(void*));
  DCHECK(interface_method != nullptr) << PrettyMethod(proxy_method);
  DCHECK(!interface_method->IsRealProxyMethod()) << PrettyMethod(interface_method);
  self->EndAssertNoThreadSuspension(old_cause);
  jobject interface_method_jobj = soa.AddLocalReference<jobject>(
      mirror::Method::CreateFromArtMethod(soa.Self(), interface_method));
 
  // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code
  // that performs allocations.
  JValue result = InvokeProxyInvocationHandler(soa, shorty, rcvr_jobj, interface_method_jobj, args);
  // Restore references which might have moved.
  local_ref_visitor.FixupReferences();
  return result.GetJ();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// android_art/entrypoint_utils.cc
 
JValue InvokeXposedHandleHookedMethod(ScopedObjectAccessAlreadyRunnable& soa, const char* shorty,
                                      jobject rcvr_jobj, jmethodID method,
                                      std::vector<jvalue>& args) {
  // Build argument array possibly triggering GC.
  soa.Self()->AssertThreadSuspensionIsAllowable();
  jobjectArray args_jobj = nullptr;
  const JValue zero;
  int32_t target_sdk_version = Runtime::Current()->GetTargetSdkVersion();
  // Do not create empty arrays unless needed to maintain Dalvik bug compatibility.
  if (args.size() > 0 || (target_sdk_version > 0 && target_sdk_version <= 21)) {
    args_jobj = soa.Env()->NewObjectArray(args.size(), WellKnownClasses::java_lang_Object, nullptr);
    if (args_jobj == nullptr) {
      CHECK(soa.Self()->IsExceptionPending());
      return zero;
    }
    for (size_t i = 0; i < args.size(); ++i) {
      if (shorty[i + 1] == 'L') {
        jobject val = args.at(i).l;
        soa.Env()->SetObjectArrayElement(args_jobj, i, val);
      } else {
        JValue jv;
        jv.SetJ(args.at(i).j);
        mirror::Object* val = BoxPrimitive(Primitive::GetType(shorty[i + 1]), jv);
        if (val == nullptr) {
          CHECK(soa.Self()->IsExceptionPending());
          return zero;
        }
        soa.Decode<mirror::ObjectArray<mirror::Object>* >(args_jobj)->Set<false>(i, val);
      }
    }
  }
  // 获取hook_info的数据
  const XposedHookInfo* hook_info = soa.DecodeMethod(method)->GetXposedHookInfo();
 
  // Call XposedBridge.handleHookedMethod(Member method, int originalMethodId, Object additionalInfoObj,
  //                                      Object thisObject, Object[] args)
  jvalue invocation_args[5];
  invocation_args[0].l = hook_info->reflected_method;
  invocation_args[1].i = 1;
  invocation_args[2].l = hook_info->additional_info;
  invocation_args[3].l = rcvr_jobj;
  invocation_args[4].l = args_jobj;
  jobject result =
      // 调用ArtMethod::xposed_callback_class类的ArtMethod::xposed_callback_method方法
      // 之前在onVmCreated中赋值过
      // ArtMethod::xposed_callback_class = classXposedBridge;
      // ArtMethod::xposed_callback_method = methodXposedBridgeHandleHookedMethod;
      // 最终调用的是XposedBridge的HandleHookedMethod方法
      soa.Env()->CallStaticObjectMethodA(ArtMethod::xposed_callback_class,
                                         ArtMethod::xposed_callback_method,
                                         invocation_args);
 
 
  // Unbox the result if necessary and return it.
  if (UNLIKELY(soa.Self()->IsExceptionPending())) {
    return zero;
  } else {
    if (shorty[0] == 'V' || (shorty[0] == 'L' && result == nullptr)) {
      return zero;
    }
    // This can cause thread suspension.
    size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
    mirror::Class* result_type = soa.DecodeMethod(method)->GetReturnType(true /* resolve */, pointer_size);
    mirror::Object* result_ref = soa.Decode<mirror::Object*>(result);
    JValue result_unboxed;
    if (!UnboxPrimitiveForResult(result_ref, result_type, &result_unboxed)) {
      DCHECK(soa.Self()->IsExceptionPending());
      return zero;
    }
    return result_unboxed;
  }
}

回到handleHookedMethod方法之后就和dalvik的执行逻辑一样了

2.2.4 知识点插入:ART虚拟机执行Java方法流程

3. 参考

[1] https://bbs.pediy.com/thread-257844.htm

 

[2] https://blog.csdn.net/zjx839524906/article/details/81046844


看雪招聘平台创建简历并且简历完整度达到90%及以上可获得500看雪币~

收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回