Android Hook 系列教程(一) Xposed Hook

2019-05-10  本文已影响0人  mahongyin

章节内容

一. Android Hook 系列教程(一) Xposed Hook 原理分析
二. Android Hook 系列教程(二) 自己写APK实现Hook Java层函数
三. Android Hook 系列教程(三) Cydia Hook Native 原理分析
四. Android Hook 系列教程(四) 自己写APK实现Hook Native层函数
五. Android Hook 系列教程(五) 更多Hook方法
六. Andoird Hook 系列教程(六) Hook的总结
Java层:https://github.com/rovo89/XposedBridge

Native层:https://github.com/rovo89/Xposed

一个好的开始等于成功了一半.

为了分析Xposed Hook是怎么实现的,选取了findAndHookMethod函数作为研究对象.

在分析过程中,我们应该做到有详有略,我将以关键代码(略过对分析目的无关紧要的部分,留下必须部分).

当然在关键代码后面会贴出全部代码以供参照.

Jave层分析

findAndHookMethod

从源代码:XposedHelpers.java处找到findAndHookMethod

findAndHookMethod关键代码

public static XC_MethodHook.Unhook findAndHookMethod(Class<?> clazz, String methodName, ``Object``... parameterTypesAndCallback) {

...

XC_MethodHook callback ``= (XC_MethodHook) parameterTypesAndCallback[parameterTypesAndCallback.length``-``1``];``/``/``获取回调函数

Method m ``= findMethodExact(clazz, methodName, getParameterClasses(clazz.getClassLoader(), parameterTypesAndCallback));``/``/``获取Method

return XposedBridge.hookMethod(m, callback);

}

public static XC_MethodHook.Unhook findAndHookMethod(Class<?> clazz, String methodName, ``Object``... parameterTypesAndCallback) {

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``];``/``/``获取回调函数

Method m ``= findMethodExact(clazz, methodName, getParameterClasses(clazz.getClassLoader(), parameterTypesAndCallback));``/``/``获取Method

return XposedBridge.hookMethod(m, callback);

}

上面的代码都很容易懂,简单说一下几个函数

getParameterClasses

功能:把函数所有参数转换为Class<?>数组返回.

比如参数列表为
String.``class``,``int``.``class``,``"java.util.Map"``,回调函数
返回结果相当于
Class<?> []``=``{

String.``class``,

int``.``class``,

Map``.``class

};
findMethodExact

功能:根据方法名和方法参数类获取Method

关键代码:

public static Method findMethodExact(Class<?> clazz, String methodName, Class<?>... parameterTypes) {

...

Method method ``= clazz.getDeclaredMethod(methodName, parameterTypes);``/``/``获取方法声明

method.setAccessible(true);

methodCache.put(fullMethodName, method);

return method;

}
完整代码:
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);

}

}
让我们继续跟进hookMethod

hookMethod

功能:把方法的参数类型,返回类型,回调函数记录到AdditionalHookInfo类里

并通过hookMethodNative方法进入Native层进行Hook.

在这个方法里面差不多都是关键代码,也就不省略,全部贴出.

​ 完整代码:
public static XC_MethodHook.Unhook hookMethod(Member hookMethod, XC_MethodHook callback) {

/``*``检测是否是支持的Method类型``*``/

if (!(hookMethod instanceof Method) && !(hookMethod instanceof Constructor<?>)) {

throw new IllegalArgumentException(``"Only methods and constructors can be hooked: " + hookMethod.toString());

} ``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;

synchronized (sHookedMethodCallbacks) {

callbacks ``= sHookedMethodCallbacks.get(hookMethod);

if (callbacks ``=``= null) {``/``/``如果为null则函数没有被Hook,否则已经Hook

callbacks ``= new CopyOnWriteSortedSet<>();

sHookedMethodCallbacks.put(hookMethod, callbacks);

newMethod ``= true;

}

}

callbacks.add(callback);``/``/``记录回调函数

if (newMethod) {``/``/``建立新Hook

Class<?> declaringClass ``= hookMethod.getDeclaringClass();``/``/``获取类声明

int slot;

Class<?>[] parameterTypes;

Class<?> returnType;

if (runtime ``=``= RUNTIME_ART) {``/``/``判断是否是ART模式

slot ``= 0``;

parameterTypes ``= null;

returnType ``= null;

} ``else if (hookMethod instanceof Method) {``/``/``实例方法

slot ``= getIntField(hookMethod, ``"slot"``);``/``/``获取slot

parameterTypes ``= ((Method) hookMethod).getParameterTypes();``/``/``获取参数类型Class<?>数组 和前面相同

returnType ``= ((Method) hookMethod).getReturnType();``/``/``获取返回类型

} ``else {``/``/``构造函数

slot ``= getIntField(hookMethod, ``"slot"``);``/``/``获取slot

parameterTypes ``= ((Constructor<?>) hookMethod).getParameterTypes();``/``/``获取参数类型Class<?>数组 和前面相同

returnType ``= null;``/``/``构造参数返回类型为null

}

/``/``把回调函数,参数类型,返回类型 记录在一个AdditionalHookInfo类里

AdditionalHookInfo additionalInfo ``= new AdditionalHookInfo(callbacks, parameterTypes, returnType);

/``/``Native方法

hookMethodNative(hookMethod, declaringClass, slot, additionalInfo);

}

return callback.new Unhook(hookMethod);

}
看一下AdditionalHookInfo构造函数
private AdditionalHookInfo(CopyOnWriteSortedSet<XC_MethodHook> callbacks, Class<?>[] parameterTypes, Class<?> returnType) {

this.callbacks ``= callbacks;

this.parameterTypes ``= parameterTypes;

this.returnType ``= returnType;

}

Native层分析

hookMethodNative

<pre class="" style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 13.475px; margin-top: 0px; margin-bottom: 1rem; overflow: auto; display: block; color: rgb(33, 37, 41); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(250, 250, 250); text-decoration-style: initial; text-decoration-color: initial;">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
ClassObject* declaredClass = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), declaredClassIndirect);
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
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
SET_METHOD_FLAG(method, ACC_NATIVE);
method->nativeFunc = &hookedMethodCallback;
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);
    }
}

}
</pre>

详细分析:

  1. 得到Native层的Method

    <pre class="" style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 13.475px; margin-top: 0px; margin-bottom: 1rem; overflow: auto; display: block; color: rgb(33, 37, 41);"> ClassObject* declaredClass = (ClassObject) dvmDecodeIndirectRef(dvmThreadSelf(), declaredClassIndirect);
    Method
    method = dvmSlotToMethod(declaredClass, slot);
    </pre>

    从Android源代码的Dalvik虚拟机代码里找到dvmSlotToMethod实现如下

    实现非常简单,所以slot相等于记录Method的下标

    <pre class="" style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 13.475px; margin-top: 0px; margin-bottom: 1rem; overflow: auto; display: block; color: rgb(33, 37, 41);">Method* dvmSlotToMethod(ClassObject* clazz, int slot)
    {
    if (slot < 0) {
    slot = -(slot+1);
    assert(slot < clazz->directMethodCount);
    return &clazz->directMethods[slot];
    } else {
    assert(slot < clazz->virtualMethodCount);
    return &clazz->virtualMethods[slot];
    }
    }
    </pre>

Method结构
struct Method {

/``* the ``class we are a part of ``*``/

ClassObject``* clazz;

/``* access flags; low ``16 bits are defined by spec (could be u2?) ``*``/

u4 accessFlags;

/``*

* For concrete virtual methods, this ``is the offset of the method

* in "vtable"``.

*

* For abstract methods ``in an interface ``class``, this ``is the offset

* of the method ``in "iftable[n]->methodIndexArray"``.

*``/

u2 methodIndex;

/``*

* Method bounds; ``not needed ``for an abstract method.

*

* For a native method, we compute the size of the argument ``list``, ``and

* set "insSize" and "registerSize" equal to it.

*``/

u2 registersSize; ``/``* ins ``+ locals *``/

u2 outsSize;

u2 insSize;

/``* method name, e.g. ``"<init>" or "eatLunch" *``/

const char``* name;

/``*

* Method prototype descriptor string (``return and argument types).

*

* TODO: This currently must specify the DexFile as well as the proto_ids

* index, because generated Proxy classes don't have a DexFile. We can

* remove the DexFile``* and reduce the size of this struct ``if we generate

* a DEX ``for proxies.

*``/

DexProto prototype;

/``* short``-``form method descriptor string ``*``/

const char``* shorty;

/``*

* The remaining items are ``not used ``for abstract ``or native methods.

* (JNI ``is currently hijacking ``"insns" as a function pointer, ``set

* after the first call. For internal``-``native this stays null.)

*``/

/``* the actual code ``*``/

const u2``* insns; ``/``* instructions, ``in memory``-``mapped .dex ``*``/

/``* JNI: cached argument ``and return``-``type hints ``*``/

int jniArgInfo;

/``*

* JNI: native method ptr; could be actual function ``or a JNI bridge. We

* don't currently discriminate between DalvikBridgeFunc ``and

* DalvikNativeFunc; the former takes an argument superset (i.e. two

* extra args) which will be ignored. If necessary we can use

* insns``=``=``NULL to detect JNI bridge vs. internal native.

*``/

DalvikBridgeFunc nativeFunc;

/``*

* JNI: true ``if this static non``-``synchronized native method (that has no

* reference arguments) needs a JNIEnv``* and jclass``/``jobject. Libcore

* uses this.

*``/

bool fastJni;

/``*

* JNI: true ``if this method has no reference arguments. This lets the JNI

* bridge avoid scanning the shorty ``for direct pointers that need to be

* converted to local references.

*

* TODO: replace this with a ``list of indexes of the reference arguments.

*``/

bool noRef;

/``*

* JNI: true ``if we should log entry ``and exit. This ``is the only way

* developers can log the local references that are passed into their code.

* Used ``for debugging JNI problems ``in third``-``party code.

*``/

bool shouldTrace;

/``*

* Register ``map data, ``if available. This will point into the DEX ``file

* if the data was computed during pre``-``verification, ``or into the

* linear alloc area ``if not``.

*``/

const RegisterMap``* registerMap;

/``* set if method was called during method profiling ``*``/

bool inProfile;

};

  1. 保存一些Hook信息

    <pre class="" style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 13.475px; margin-top: 0px; margin-bottom: 1rem; overflow: auto; display: block; color: rgb(33, 37, 41);">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));
    </pre>

  2. 替换方法(最关键的一步)
    SET_METHOD_FLAG(method, ACC_NATIVE);

    method``-``>nativeFunc ``= &hookedMethodCallback;``/``/``替换方法为这个

    method``-``>insns ``= (const u2``*``) hookInfo;

    method``-``>registersSize ``= method``-``>insSize;

    method``-``>outsSize ``= 0``;
    到这里我们已经分析完了,就是保存一些信息,并把方法替换为hookedMethodCallback.

hookedMethodCallback

<pre class="" style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 13.475px; margin-top: 0px; margin-bottom: 1rem; overflow: auto; display: block; color: rgb(33, 37, 41); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(250, 250, 250); text-decoration-style: initial; text-decoration-color: initial;">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(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);
    }
}

}

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
ClassObject* declaredClass = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), declaredClassIndirect);
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
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
SET_METHOD_FLAG(method, ACC_NATIVE);
method->nativeFunc = &hookedMethodCallback;
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);
    }
}

}
</pre>

相信到了这里读者已经可以根据注释自己看懂了,我在把流程梳理一下

Java层函数handleHookedMethod

功能:

  1. 调用Hook该方法的所有beforeHookedMethod

  2. 调用原始方法

  3. 调用Hook该方法的所有afterHookedMethod

关键代码
private static ``Object handleHookedMethod(Member method, ``int originalMethodId, ``Object additionalInfoObj,

Object thisObject, ``Object``[] args) throws Throwable {

AdditionalHookInfo additionalInfo ``= (AdditionalHookInfo) additionalInfoObj;

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) {

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 {

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) {

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();

}
完整代码
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();

}

}

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) {

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 {

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) {

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();

}
好了,到这里我们已经分析完成.

简单总结一下:

上一篇下一篇

猜你喜欢

热点阅读