Alibaba-Dexposed Bug框架原理及源码解析

来源:互联网 发布:windows boot manager 编辑:程序博客网 时间:2024/05/16 18:48

转:http://blog.csdn.net/qxs965266509/article/details/50117137


Alibaba的AndFix热修复: 
Alibaba-AndFix Bug热修复框架的使用 
Alibaba-AndFix Bug热修复框架原理及源码解析

上一篇中已经介绍了Alibaba-Dexposed框架在线热补丁修复的使用 ,这篇主要是了解框架的原理和源码解析。

这里写图片描述

原理:

在Dalvik虚拟机下,主要是通过改变一个方法对象方法在Dalvik虚拟机中的定义来实现,具体做法就是将该方法的类型改变为Native并且将这个方法的实现链接到一个通用的Native Dispatch方法上。这个 Dispatch方法通过JNI回调到Java端的一个统一处理方法,最后在统一处理方法中调用before, after函数来实现AOP。在Art虚拟机上目前也是通过改变一个 ArtMethod的入口函数来实现。

在宿主项目的Application需要调用以下方法来判断手机是否支持Dexposed框架:

DexposedBridge.canDexposed(this);
  • 1
  • 1

canDexposed方法源码:

 public static synchronized boolean canDexposed(Context context) {        return !DeviceCheck.isDeviceSupport(context)?false:loadDexposedLib(context);    }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

可以看到,第一判断了机型是否支持,如果支持就加载lib文件。 
DeviceCheck.isDeviceSupport()源码:

 public static synchronized boolean isDeviceSupport(Context context) {        boolean var2;        try {            if(!isCheckedDeviceSupport) {                if(isDalvikMode() && isSupportSDKVersion() && !isX86CPU() && !isYunOS()) {                    isDeviceSupportable = true;                    return isDeviceSupportable;                }                isDeviceSupportable = false;                return isDeviceSupportable;            }            var2 = isDeviceSupportable;        } finally {            Log.d("hotpatch", "device support is " + isDeviceSupportable + "checked" + isCheckedDeviceSupport);            isCheckedDeviceSupport = true;        }        return var2;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

判断机型,主要判断的有是否是Dalvik虚拟机、sdk版本、是否是x86cpu架构、是否是YunOS系统。

loadDexposedLib加载lib的源码:

private static boolean loadDexposedLib(Context context) {        try {            if(VERSION.SDK_INT != 10 && VERSION.SDK_INT != 9) {                if(VERSION.SDK_INT > 19) {                    System.loadLibrary("dexposed_l");                } else {                    System.loadLibrary("dexposed");                }            } else {                System.loadLibrary("dexposed2.3");            }            return true;        } catch (Throwable var2) {            return false;        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

根据sdk的不同版本加载不同的so文件。

以上仅是判断当然机型是否支持Dexposed框架的运行环境。

接下,就是对Dexposed的使用原理进行源码分析:

在上一篇提到,当加载补丁文件时,会扫描补丁文件中实现IPatch接口的所有的类。 
IPatch定义如下:

public interface IPatch {    void handlePatch(PatchParam var1) throws Throwable;}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

就是说,修复bug的处理只能在handlePatch方法中实现。

官网也只提供了2种实现方式: 
第一:

 // Target class, method with parameter types, followed by the hook callback (XC_MethodHook).        DexposedBridge.findAndHookMethod(Activity.class, "onCreate", Bundle.class, new XC_MethodHook() {            // To be invoked before Activity.onCreate().            @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable {                // "thisObject" keeps the reference to the instance of target class.                Activity instance = (Activity) param.thisObject;                // The array args include all the parameters.                Bundle bundle = (Bundle) param.args[0];                Intent intent = new Intent();                // XposedHelpers provide useful utility methods.                XposedHelpers.setObjectField(param.thisObject, "mIntent", intent);                // Calling setResult() will bypass the original method body use the result as method return value directly.                if (bundle.containsKey("return"))                    param.setResult(null);            }            // To be invoked after Activity.onCreate()            @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable {                XposedHelpers.callMethod(param.thisObject, "sampleMethod", 2);            }        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

第二:

 DexposedBridge.findAndHookMethod(Activity.class, "onCreate", Bundle.class, new XC_MethodReplacement() {            @Override protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {                // Re-writing the method logic outside the original method context is a bit tricky but still viable.                ...            }        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

调用的接口是相同的,只不过传递的回调接口不同。 
第一种是在方法前后执行做一些处理,第二种就是直接把方法进行替换。

在这里,我们就重点看findAndHookMethod方法,跟着此方法追踪源码:

 public static Unhook findAndHookMethod(Class<?> clazz, String methodName, Object... parameterTypesAndCallback) {        if(parameterTypesAndCallback.length != 0 && parameterTypesAndCallback[parameterTypesAndCallback.length - 1] instanceof XC_MethodHook) {            XC_MethodHook callback = (XC_MethodHook)parameterTypesAndCallback[parameterTypesAndCallback.length - 1];            Method m = XposedHelpers.findMethodExact(clazz, methodName, parameterTypesAndCallback);//根据Java的反射机制获取到Method对象            Unhook unhook = hookMethod(m, callback);//见下方代码分析            if(!(callback instanceof XC_MethodKeepHook) && !(callback instanceof XC_MethodKeepReplacement)) {                ArrayList var6 = allUnhookCallbacks;                synchronized(allUnhookCallbacks) {                    allUnhookCallbacks.add(unhook);                }            }            return unhook;        } else {            throw new IllegalArgumentException("no callback defined");        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

hookMethod方法源码:

 public static Unhook hookMethod(Member hookMethod, XC_MethodHook callback) {        if(!(hookMethod instanceof Method) && !(hookMethod instanceof Constructor)) {            throw new IllegalArgumentException("only methods and constructors can be hooked");        } else {            boolean newMethod = false;            Map declaringClass = hookedMethodCallbacks;            DexposedBridge.CopyOnWriteSortedSet callbacks;            synchronized(hookedMethodCallbacks) {                callbacks = (DexposedBridge.CopyOnWriteSortedSet)hookedMethodCallbacks.get(hookMethod);                //如果没有修复此方法,就创建一个回调接口的集合                if(callbacks == null) {                    callbacks = new DexposedBridge.CopyOnWriteSortedSet();                    hookedMethodCallbacks.put(hookMethod, callbacks);                    newMethod = true;                }            }            callbacks.add(callback);            if(newMethod) {//如果是新方法,获取方法的参数列表和返回值                Class declaringClass1 = hookMethod.getDeclaringClass();                int slot = runtime == 1?XposedHelpers.getIntField(hookMethod, "slot"):0;                Class[] parameterTypes;                Class returnType;                if(hookMethod instanceof Method) {                    parameterTypes = ((Method)hookMethod).getParameterTypes();                    returnType = ((Method)hookMethod).getReturnType();                } else {                    parameterTypes = ((Constructor)hookMethod).getParameterTypes();                    returnType = null;                }                DexposedBridge.AdditionalHookInfo additionalInfo = new DexposedBridge.AdditionalHookInfo(callbacks, parameterTypes, returnType, (DexposedBridge.AdditionalHookInfo)null);                //调用Native方法,接口在下方                hookMethodNative(hookMethod, declaringClass1, slot, additionalInfo);            }            callback.getClass();            return new Unhook(callback, hookMethod);//返回一个Unhook实例对象        }    }
  • 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
  • 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

hookMethodNative Native方法生命:

private static synchronized native void hookMethodNative(Member var0, Class<?> var1, int var2, Object var3);
  • 1
  • 1

Dalvik虚拟机的Native方法实现:

hookMethodNative Native层的代码实现:

static void com_taobao_android_dexposed_DexposedBridge_hookMethodNative(JNIEnv* env, jclass clazz, jobject reflectedMethodIndirect,            jobject declaredClassIndirect, jint slot, jobject additionalInfoIndirect) {s    // Usage errors?    if (declaredClassIndirect == NULL || reflectedMethodIndirect == NULL) {        dvmThrowIllegalArgumentException("method and declaredClass must not be null");        return;    }    // Find the internal representation of the method    ClassObject* declaredClass = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), declaredClassIndirect);    Method* method = dvmSlotToMethod(declaredClass, slot);//把Java的Method映射为Native Method    if (method == NULL) {        dvmThrowNoSuchMethodError("could not get internal representation for method");        return;    }    if (dexposedIsHooked(method)) {//判断此方法是否已经被hook(钩)        // already hooked        return;    }    // Save a copy of the original method and other hook info    DexposedHookInfo* hookInfo = (DexposedHookInfo*) calloc(1, sizeof(DexposedHookInfo));//新申请一块内存    //备份method对象到hookInfo中    memcpy(hookInfo, method, sizeof(hookInfo->originalMethodStruct));    hookInfo->reflectedMethod = dvmDecodeIndirectRef(dvmThreadSelf(), env->NewGlobalRef(reflectedMethodIndirect));//把方法的实现指向native方法的实现,指针替换    hookInfo->additionalInfo = dvmDecodeIndirectRef(dvmThreadSelf(), env->NewGlobalRef(additionalInfoIndirect));    // Replace method with our own code    SET_METHOD_FLAG(method, ACC_NATIVE);//把method对象方法属性设置成native方法    method->insns = (const u2*) hookInfo;//把备份的method数据挂在这里传递数据    method->registersSize = method->insSize;    method->outsSize = 0;    if (PTR_gDvmJit != NULL) {        // reset JIT cache        MEMBER_VAL(PTR_gDvmJit, DvmJitGlobals, codeCacheFull) = true;    }}
  • 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
  • 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
method->nativeFunc = &dexposedCallHandler;//链接到Native方法的实现
  • 1
  • 1

当虚拟机调用到这个存在bug的方法时就会调用这个Native方法: 
dexposedCallHandler方法源码:

static void dexposedCallHandler(const u4* args, JValue* pResult, const Method* method, ::Thread* self) {    if (!dexposedIsHooked(method)) {        dvmThrowNoSuchMethodError("could not find Dexposed original method - how did you even get here?");        return;    }    DexposedHookInfo* hookInfo = (DexposedHookInfo*) 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\n", descChar);            obj = NULL;            srcIndex++;        }        dexposedSetObjectArrayElement(argsArray, dstIndex++, obj);    }    // call the Java handler function    JValue result;    //调用了Java层的方法    dvmCallMethod(self, dexposedHandleHookedMethod, NULL, &result,        originalReflected, (int) original, additionalInfo, thisObject, argsArray);    dvmReleaseTrackedAlloc((Object *)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((Object *)result.l, returnType, pResult)) {            dvmThrowClassCastException(((Object *)result.l)->clazz, returnType);        }    }}
  • 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
  • 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

这个方法主要就是调用Java的方法,实现调度。 
调用的Java的方法是:

private static Object handleHookedMethod(Member method, int originalMethodId, Object additionalInfoObj,            Object thisObject, Object[] args) throws Throwable {        AdditionalHookInfo additionalInfo = (AdditionalHookInfo) additionalInfoObj;        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();            }        }        MethodHookParam param = new MethodHookParam();        param.method  = method;        param.thisObject = thisObject;        param.args = args;        // call "before method" callbacks        int beforeIdx = 0;        do {            try {                ((XC_MethodHook) callbacksSnapshot[beforeIdx]).beforeHookedMethod(param);            } catch (Throwable t) {                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 {                param.setResult(invokeOriginalMethodNative(method, originalMethodId,                        additionalInfo.parameterTypes, additionalInfo.returnType, param.thisObject, param.args));            } catch (InvocationTargetException e) {                param.setThrowable(e.getCause());            }        }        // 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) {                DexposedBridge.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();    }
  • 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
  • 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

这个方法里面了实现了调度机制,调用回调接口的方法和备份的Java方法。 
本质上仍然是寻找被挂钩函数的 Method 结构体,将Method属性改为native ,然后对其成员 nativeFunc, 
registersize 等进行赋值,其中 insns 成员保存了挂钩的详细信息。所有被挂钩的函数,其nativeFunc都赋值为 dexposedCallHandler 函数,该函数最终执行 XposedBridge.class 里的 handleHookedMethod 。 handleHookedMethod 寻找dexposed模块及dexposed框架调用 findAndHookMethod 注册的 before,after 
函数,如果有,就执行,再通过invokeOriginalMethodNative 执行挂钩前函数。

MethodHookParam.thisObject:这个类的一个实例 
MethodHookParam.args:用于传递被注入函数的所有参数 
MethodHookParam.setResult:用于修改原函数调用的结果,如果在beforeHookedMethod回调函数中调用setResult,可以阻止对原函数的调用。但是如果有返回值的话仍然需要通过hook处理器进行return操作。

Art虚拟机的Native方法实现

static void com_taobao_android_dexposed_DexposedBridge_hookMethodNative(            JNIEnv* env, jclass, jobject java_method, jobject, jint,            jobject additional_info) {        ScopedObjectAccess soa(env);        art::Thread* self = art::Thread::Current();        jobject javaArtMethod = env->GetObjectField(java_method,                WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod);        ArtMethod* method = soa.Decode<mirror::ArtMethod*>(javaArtMethod);        LOG(INFO) << "dexposed: >>> hookMethodNative " << method << " " << PrettyMethod(method);        EnableXposedHook(env, method, additional_info);    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

EnableXposedHook:

static void EnableXposedHook(JNIEnv* env, ArtMethod* art_method, jobject additional_info)      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {      LOG(INFO) << "dexposed: >>> EnableXposedHook" << art_method << " " << PrettyMethod(art_method);      if (dexposedIsHooked(art_method)) {        // Already hooked        return;      }//    else if (UNLIKELY(art_method->IsXposedOriginalMethod())) {//      // This should never happen//      ThrowIllegalArgumentException(nullptr, StringPrintf("Cannot hook the method backup: %s", PrettyMethod(art_method).c_str()).c_str());//      return;//    }      ScopedObjectAccess soa(env);      // Create a backup of the ArtMethod object      ArtMethod* backup_method = down_cast<ArtMethod*>(art_method->Clone(soa.Self()));      // Set private flag to avoid virtual table lookups during invocation      backup_method->SetAccessFlags(backup_method->GetAccessFlags() /*| kAccXposedOriginalMethod*/);      // Create a Method/Constructor object for the backup ArtMethod object      jobject reflect_method;      if (art_method->IsConstructor()) {        reflect_method = env->AllocObject(WellKnownClasses::java_lang_reflect_Constructor);      } else {        reflect_method = env->AllocObject(WellKnownClasses::java_lang_reflect_Method);      }      env->SetObjectField(reflect_method, WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod,          env->NewGlobalRef(soa.AddLocalReference<jobject>(backup_method)));      // Save extra information in a separate structure, stored instead of the native method      DexposedHookInfo* hookInfo = reinterpret_cast<DexposedHookInfo*>(calloc(1, sizeof(DexposedHookInfo)));      hookInfo->reflectedMethod = env->NewGlobalRef(reflect_method);      hookInfo->additionalInfo = env->NewGlobalRef(additional_info);      hookInfo->originalMethod = backup_method;      jstring shorty = (jstring)env->GetObjectField(additional_info,additionalhookinfo_shorty_field);      hookInfo->shorty = env->GetStringUTFChars(shorty, 0);      LOG(INFO) << "dexposed: >>> EnableXposedHook shorty:" << hookInfo->shorty;#if PLATFORM_SDK_VERSION < 22        art_method->SetNativeMethod(reinterpret_cast<uint8_t *>(hookInfo));#else        art_method->SetEntryPointFromJni(reinterpret_cast<void *>(hookInfo));#endif      art_method->SetEntryPointFromQuickCompiledCode(GetQuickDexposedInvokeHandler());//    art_method->SetEntryPointFromInterpreter(art::artInterpreterToCompiledCodeBridge);      // Adjust access flags      art_method->SetAccessFlags((art_method->GetAccessFlags() & ~kAccNative) /*| kAccXposedHookedMethod*/);    }
  • 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
  • 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

通过: 
art_method->SetAccessFlags((art_method->GetAccessFlags()&~kAccNative)/| kAccXposedHookedMethod/); 
art_method->SetEntryPointFromQuickCompiledCode(GetQuickDexposedInvokeHandler()); 
同样也是把把实现指向native方法实现调度机制来达到目的。


0 0
原创粉丝点击