承接上文 http://blog.csdn.net/yzzst/article/details/47829657
之前我们看到了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);
}
}
}
/*
* @author zhoushengtao(周圣韬)
* @since 2015年8月24 日 8:55:32
* @weixin stchou_zst
* @blog http://blog.csdn.net/yzzst
* @交流学习QQ群:341989536
* @私人QQ:445914891
/