ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
原文出处——>[Xposed源码剖析——hook具体实现](http://blog.csdn.net/yzzst/article/details/47913867) 承接上文[Xposed源码剖析——Xposed初始化](http://blog.csdn.net/yzzst/article/details/47834077) 之前我们看到了xposed各种初始化的工作,其实都是完成了针对系统中各种method的hook和替换工作。 那么具体如何替换,其实都是调用了其中的。XposedBridge_hookMethodNative函数。这里,我们详细的看看XposedBridge_hookMethodNative函数中,做了一些什么操作。 ~~~ /** * * 将输入的Class中的Method方法的nativeFunc替换为xposedCallHandler * * @param env JniEnv * @param reflectedMethodIndirect 待反射的函数 * @param declaredClassIndirect 定义的class * @param slot 函数偏移量 * @param additionalInfoIndirect 添加的函数 * */ void XposedBridge_hookMethodNative(JNIEnv* env, jclass clazz, jobject reflectedMethodIndirect, jobject declaredClassIndirect, jint slot, jobject additionalInfoIndirect) { // 容错 if (declaredClassIndirect == NULL || reflectedMethodIndirect == NULL) { dvmThrowIllegalArgumentException("method and declaredClass must not be null"); return; } // 根据函数的偏移量,从classloader中找到准备替换的函数。 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; } // 保存替换前的数据信息 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)); // 替换函数方法 , 让nativeFunction指向本地的hookedMethodCallback 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); } } } ~~~ 对vm不熟悉的,解释一下几个不怎么常用的函数。 |名称 |说明| | --- | --- | |dvmDecodeIndirectRef| 将间接引用jobject转换为对象引用Object*| |dvmSlotToMethod |根据偏移量,从ClassLoader中获取函数指针| ~~~ /** * hook方法调用时的回调 */ 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); } // 调用Java中的对应方法,即之前我们用到,的handleHookedMethod JValue result; dvmCallMethod(self, xposedHandleHookedMethod, 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); } } } ~~~