static void de_robv_android_xposed_XposedBridge_setObjectClassNative(JNIEnv* env, jclass clazz, jobject objIndirect, jclass clzIndirect) { Object* obj = (Object*) dvmDecodeIndirectRef(dvmThreadSelf(), objIndirect); ClassObject* clz = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), clzIndirect); if (clz->status < CLASS_INITIALIZED && !dvmInitClass(clz)) { ALOGE("Could not initialize class %s", clz->descriptor); return; } obj->clazz = clz; }
static void de_robv_android_xposed_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 (xposedIsHooked(method)) { ALOGD("Hook: Ignored! [%s] [%s]\n", declaredClass->descriptor, method->name); // already hooked return; } else { ALOGD("Hook: [%s] [%s]\n", declaredClass->descriptor, method->name); } // 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 = &xposedCallHandler; method->insns = (const u2*) hookInfo; method->registersSize = method->insSize; method->outsSize = 0; if (PTR_gDvmJit != NULL) { // reset JIT cache MEMBER_VAL(PTR_gDvmJit, DvmJitGlobals, codeCacheFull) = true; } }
static void de_robv_android_xposed_XposedBridge_hookMethodNative(JNIEnv* env, jclass clazz, jobject declaredClassIndirect, jint slot) { // Usage errors? if (declaredClassIndirect == NULL) { dvmThrowIllegalArgumentException("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 (findXposedOriginalMethod(method) != xposedOriginalMethods.end()) { // already hooked return; } // Save a copy of the original method xposedOriginalMethods.push_front(*((MethodXposedExt*)method)); // Replace method with our own code SET_METHOD_FLAG(method, ACC_NATIVE); method->nativeFunc = &xposedCallHandler; method->registersSize = method->insSize; method->outsSize = 0; if (PTR_gDvmJit != NULL) { // reset JIT cache MEMBER_VAL(PTR_gDvmJit, DvmJitGlobals, codeCacheFull) = true; } }
static void miui_dexspy_DexspyInstaller_hookMethodNative(JNIEnv* env, jclass clazz, jobject declaredClassIndirect, jint slot) { // Usage errors? if (declaredClassIndirect == NULL) { dvmThrowIllegalArgumentException("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 (findOriginalMethod(method) != dexspyOriginalMethods.end()) { ALOGD("why this method already hooked: %s:%s(%s)", method->clazz->descriptor, method->name, method->shorty); // already hooked return; } // Save a copy of the original method dexspyOriginalMethods.push_front(*method); // Replace method with our own code SET_METHOD_FLAG(method, ACC_NATIVE); method->nativeFunc = &dexspyCallHandler; method->registersSize = method->insSize; method->outsSize = 0; #ifdef WITH_JIT // reset JIT cache gDvmJit.codeCacheFull = true; #endif }
static jobject de_robv_android_xposed_XposedBridge_cloneToSubclassNative(JNIEnv* env, jclass clazz, jobject objIndirect, jclass clzIndirect) { Object* obj = (Object*) dvmDecodeIndirectRef(dvmThreadSelf(), objIndirect); ClassObject* clz = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), clzIndirect); jobject copyIndirect = env->AllocObject(clzIndirect); if (copyIndirect == NULL) return NULL; Object* copy = (Object*) dvmDecodeIndirectRef(dvmThreadSelf(), copyIndirect); size_t size = obj->clazz->objectSize; size_t offset = sizeof(Object); memcpy((char*)copy + offset, (char*)obj + offset, size - offset); if (IS_CLASS_FLAG_SET(clz, CLASS_ISFINALIZABLE)) dvmSetFinalizable(copy); return copyIndirect; }
// simplified copy of Method.invokeNative, but calls the original (non-hooked) method and has no access checks // used when a method has been hooked static jobject miui_dexspy_DexspyInstaller_invokeOriginalMethodNative(JNIEnv* env, jclass clazz, jobject reflectedMethod, jobjectArray params1, jclass returnType1, jobject thisObject1, jobjectArray args1) { // try to find the original method Method* method = (Method*)env->FromReflectedMethod(reflectedMethod); OriginalMethodsIt original = findOriginalMethod(method); if (original != dexspyOriginalMethods.end()) { method = &(*original); } // dereference parameters ::Thread* self = dvmThreadSelf(); Object* thisObject = dvmDecodeIndirectRef(self, thisObject1); ArrayObject* args = (ArrayObject*)dvmDecodeIndirectRef(self, args1); ArrayObject* params = (ArrayObject*)dvmDecodeIndirectRef(self, params1); ClassObject* returnType = (ClassObject*)dvmDecodeIndirectRef(self, returnType1); // invoke the method dvmChangeStatus(self, THREAD_RUNNING); Object* result = dvmInvokeMethod(thisObject, method, args, params, returnType, true); dvmChangeStatus(self, THREAD_NATIVE); return dexspyAddLocalReference(self, result); }
bool xposedOnVmCreated(JNIEnv* env, const char* className) { startClassName = className; keepLoadingXposed = keepLoadingXposed && xposedInitMemberOffsets(env); if (!keepLoadingXposed) return false; jclass miuiResourcesClass = env->FindClass(MIUI_RESOURCES_CLASS); if (miuiResourcesClass != NULL) { ClassObject* clazz = (ClassObject*)dvmDecodeIndirectRef(dvmThreadSelf(), miuiResourcesClass); if (dvmIsFinalClass(clazz)) { ALOGD("Removing final flag for class '%s'", MIUI_RESOURCES_CLASS); clazz->accessFlags &= ~ACC_FINAL; } } env->ExceptionClear(); jclass xTypedArrayClass = env->FindClass(XTYPEDARRAY_CLASS); if (xTypedArrayClass == NULL) { ALOGE("Error while loading XTypedArray class '%s':\n", XTYPEDARRAY_CLASS); dvmLogExceptionStackTrace(); env->ExceptionClear(); return false; } xposedPrepareSubclassReplacement(xTypedArrayClass); xposedClass = env->FindClass(XPOSED_CLASS); xposedClass = reinterpret_cast<jclass>(env->NewGlobalRef(xposedClass)); if (xposedClass == NULL) { ALOGE("Error while loading Xposed class '%s':\n", XPOSED_CLASS); dvmLogExceptionStackTrace(); env->ExceptionClear(); return false; } ALOGI("Found Xposed class '%s', now initializing\n", XPOSED_CLASS); if (register_de_robv_android_xposed_XposedBridge(env) != JNI_OK) { ALOGE("Could not register natives for '%s'\n", XPOSED_CLASS); env->ExceptionClear(); return false; } return true; }
bool xposedOnVmCreated(JNIEnv* env, const char* className) { startClassName = className; keepLoadingXposed = keepLoadingXposed && xposedInitMemberOffsets(env); if (!keepLoadingXposed) return false; // disable some access checks patchReturnTrue((uintptr_t) & dvmCheckClassAccess); patchReturnTrue((uintptr_t) & dvmCheckFieldAccess); patchReturnTrue((uintptr_t) & dvmInSamePackage); if (access(XPOSED_DIR "conf/do_not_hook_dvmCheckMethodAccess", F_OK) != 0) patchReturnTrue((uintptr_t) & dvmCheckMethodAccess); jclass miuiResourcesClass = env->FindClass(MIUI_RESOURCES_CLASS); if (miuiResourcesClass != NULL) { ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef( dvmThreadSelf(), miuiResourcesClass); if (dvmIsFinalClass(clazz)) { ALOGD("Removing final flag for class '%s'", MIUI_RESOURCES_CLASS); clazz->accessFlags &= ~ACC_FINAL; } } env->ExceptionClear(); xposedClass = env->FindClass(XPOSED_CLASS); xposedClass = reinterpret_cast<jclass>(env->NewGlobalRef(xposedClass)); if (xposedClass == NULL) { ALOGE("Error while loading Xposed class '%s':\n", XPOSED_CLASS); dvmLogExceptionStackTrace(); env->ExceptionClear(); return false; } ALOGI("Found Xposed class '%s', now initializing\n", XPOSED_CLASS); if (register_de_robv_android_xposed_XposedBridge(env) != JNI_OK) { ALOGE("Could not register natives for '%s'\n", XPOSED_CLASS); return false; } return true; }
static bool xposedInitMemberOffsets(JNIEnv* env) { PTR_gDvmJit = dlsym(RTLD_DEFAULT, "gDvmJit"); if (PTR_gDvmJit == NULL) { offsetMode = MEMBER_OFFSET_MODE_NO_JIT; } else { offsetMode = MEMBER_OFFSET_MODE_WITH_JIT; } ALOGD("Using structure member offsets for mode %s", xposedOffsetModesDesc[offsetMode]); MEMBER_OFFSET_COPY(DvmJitGlobals, codeCacheFull); int overrideCodeCacheFull = xposedReadIntConfig(XPOSED_OVERRIDE_JIT_RESET_OFFSET, -1); if (overrideCodeCacheFull > 0 && overrideCodeCacheFull < 0x400) { ALOGI("Offset for DvmJitGlobals.codeCacheFull is overridden, new value is 0x%x", overrideCodeCacheFull); MEMBER_OFFSET_VAR(DvmJitGlobals, codeCacheFull) = overrideCodeCacheFull; } // detect offset of ArrayObject->contents jintArray dummyArray = env->NewIntArray(1); if (dummyArray == NULL) { ALOGE("Could allocate int array for testing"); dvmLogExceptionStackTrace(); env->ExceptionClear(); return false; } jint* dummyArrayElements = env->GetIntArrayElements(dummyArray, NULL); arrayContentsOffset = (size_t)dummyArrayElements - (size_t)dvmDecodeIndirectRef(dvmThreadSelf(), dummyArray); env->ReleaseIntArrayElements(dummyArray,dummyArrayElements, 0); env->DeleteLocalRef(dummyArray); if (arrayContentsOffset < 12 || arrayContentsOffset > 128) { ALOGE("Detected strange offset %d of ArrayObject->contents", arrayContentsOffset); return false; } return true; }
static void xposedPrepareSubclassReplacement(jclass clazz) { // clazz is supposed to replace its superclass, so make sure enough memory is allocated ClassObject* sub = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), clazz); ClassObject* super = sub->super; super->objectSize = sub->objectSize; }
/* * Issue a method call with arguments provided in an array. We process * the contents of "args" by scanning the method signature. * * The values were likely placed into an uninitialized jvalue array using * the field specifiers, which means that sub-32-bit fields (e.g. short, * boolean) may not have 32 or 64 bits of valid data. This is different * from the varargs invocation where the C compiler does a widening * conversion when calling a function. As a result, we have to be a * little more precise when pulling stuff out. * * "args" may be NULL if the method has no arguments. */ void dvmCallMethodA(Thread* self, const Method* method, Object* obj, bool fromJni, JValue* pResult, const jvalue* args) { //salma // __android_log_print(ANDROID_LOG_DEBUG, "DVM DEBUG", "dvmCallMethodA method name = %s, clazz name: %s", method->name, method->clazz->descriptor); //end salma const char* desc = &(method->shorty[1]); // [0] is the return type. int verifyCount = 0; ClassObject* clazz; u4* ins; clazz = callPrep(self, method, obj, false); if (clazz == NULL) return; /* "ins" for new frame start at frame pointer plus locals */ ins = ((u4*)self->interpSave.curFrame) + (method->registersSize - method->insSize); /* put "this" pointer into in0 if appropriate */ if (!dvmIsStaticMethod(method)) { assert(obj != NULL); *ins++ = (u4) obj; /* obj is a "real" ref */ verifyCount++; } while (*desc != '\0') { switch (*desc++) { case 'D': /* 64-bit quantity; have to use */ case 'J': /* memcpy() in case of mis-alignment */ memcpy(ins, &args->j, 8); ins += 2; verifyCount++; /* this needs an extra push */ break; case 'L': /* includes array refs */ if (fromJni) *ins++ = (u4) dvmDecodeIndirectRef(self, args->l); else *ins++ = (u4) args->l; break; case 'F': case 'I': *ins++ = args->i; /* full 32 bits */ break; case 'S': *ins++ = args->s; /* 16 bits, sign-extended */ break; case 'C': *ins++ = args->c; /* 16 bits, unsigned */ break; case 'B': *ins++ = args->b; /* 8 bits, sign-extended */ break; case 'Z': *ins++ = args->z; /* 8 bits, zero or non-zero */ break; default: ALOGE("Invalid char %c in short signature of %s.%s", *(desc-1), clazz->descriptor, method->name); assert(false); goto bail; } verifyCount++; args++; } #ifndef NDEBUG if (verifyCount != method->insSize) { ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount, method->insSize, clazz->descriptor, method->name); assert(false); goto bail; } #endif if (dvmIsNativeMethod(method)) { TRACE_METHOD_ENTER(self, method); /* * Because we leave no space for local variables, "curFrame" points * directly at the method arguments. */ (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult, method, self); TRACE_METHOD_EXIT(self, method); } else { dvmInterpret(self, method, pResult); } bail: dvmPopFrame(self); }
static void dexspyCallHandler(const u4* args, JValue* pResult, const Method* method, ::Thread* self) { OriginalMethodsIt original = findOriginalMethod(method); if (original == dexspyOriginalMethods.end()) { dvmThrowNoSuchMethodError("could not find Dexspy original method - how did you even get here?"); return; } ThreadStatus oldThreadStatus = self->status; JNIEnv* env = self->jniEnv; // get java.lang.reflect.Method object for original method jobject originalReflected = env->ToReflectedMethod( (jclass)dexspyAddLocalReference(self, original->clazz), (jmethodID)method, true); // 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*) dexspyAddLocalReference(self, (Object*)args[0]); srcIndex++; } jclass objectClass = env->FindClass("java/lang/Object"); jobjectArray argsArray = env->NewObjectArray(strlen(method->shorty) - 1, objectClass, NULL); 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, NULL); break; case 'D': case 'J': value.j = dvmGetArgLong(args, srcIndex); srcIndex += 2; obj = (Object*) dvmBoxPrimitive(value, dvmFindPrimitiveClass(descChar)); dvmReleaseTrackedAlloc(obj, NULL); break; case '[': case 'L': obj = (Object*) args[srcIndex++]; break; default: ALOGE("Unknown method signature description character: %c\n", descChar); obj = NULL; srcIndex++; } env->SetObjectArrayElement(argsArray, dstIndex++, dexspyAddLocalReference(self, obj)); } // call the Java handler function jobject resultRef = env->CallStaticObjectMethod( dexspyClass, dexspyHandleHookedMethod, originalReflected, thisObject, argsArray); // exceptions are thrown to the caller if (env->ExceptionCheck()) { dvmChangeStatus(self, oldThreadStatus); return; } // return result with proper type Object* result = dvmDecodeIndirectRef(self, resultRef); ClassObject* returnType = dvmGetBoxedReturnType(method); if (returnType->primitiveType == PRIM_VOID) { // ignored } else if (result == NULL) { if (dvmIsPrimitiveClass(returnType)) { dvmThrowNullPointerException("null result when primitive expected"); } pResult->l = NULL; } else { if (!dvmUnboxPrimitive(result, returnType, pResult)) { dvmThrowClassCastException(result->clazz, returnType); } } // set the thread status back to running. must be done after the last env->...() dvmChangeStatus(self, oldThreadStatus); }
/* * Issue a method call with a variable number of arguments. We process * the contents of "args" by scanning the method signature. * * Pass in NULL for "obj" on calls to static methods. * * We don't need to take the class as an argument because, in Dalvik, * we don't need to worry about static synchronized methods. */ void dvmCallMethodV(Thread* self, const Method* method, Object* obj, bool fromJni, JValue* pResult, va_list args) { //salma //__android_log_print(ANDROID_LOG_DEBUG, "DVM DEBUG", "dvmCallMethodV method name = %s, clazz name: %s", method->name, method->clazz->descriptor); //end salma const char* desc = &(method->shorty[1]); // [0] is the return type. int verifyCount = 0; ClassObject* clazz; u4* ins; clazz = callPrep(self, method, obj, false); if (clazz == NULL) return; /* "ins" for new frame start at frame pointer plus locals */ ins = ((u4*)self->interpSave.curFrame) + (method->registersSize - method->insSize); //ALOGD(" FP is %p, INs live at >= %p", self->interpSave.curFrame, ins); /* put "this" pointer into in0 if appropriate */ if (!dvmIsStaticMethod(method)) { #ifdef WITH_EXTRA_OBJECT_VALIDATION assert(obj != NULL && dvmIsHeapAddress(obj)); #endif *ins++ = (u4) obj; verifyCount++; } while (*desc != '\0') { switch (*(desc++)) { case 'D': case 'J': { u8 val = va_arg(args, u8); memcpy(ins, &val, 8); // EABI prevents direct store ins += 2; verifyCount += 2; break; } case 'F': { /* floats were normalized to doubles; convert back */ float f = (float) va_arg(args, double); *ins++ = dvmFloatToU4(f); verifyCount++; break; } case 'L': { /* 'shorty' descr uses L for all refs, incl array */ void* arg = va_arg(args, void*); assert(obj == NULL || dvmIsHeapAddress(obj)); jobject argObj = reinterpret_cast<jobject>(arg); if (fromJni) *ins++ = (u4) dvmDecodeIndirectRef(self, argObj); else *ins++ = (u4) argObj; verifyCount++; break; } default: { /* Z B C S I -- all passed as 32-bit integers */ *ins++ = va_arg(args, u4); verifyCount++; break; } } } #ifndef NDEBUG if (verifyCount != method->insSize) { ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount, method->insSize, clazz->descriptor, method->name); assert(false); goto bail; } #endif //dvmDumpThreadStack(dvmThreadSelf()); if (dvmIsNativeMethod(method)) { TRACE_METHOD_ENTER(self, method); /* * Because we leave no space for local variables, "curFrame" points * directly at the method arguments. */ (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult, method, self); TRACE_METHOD_EXIT(self, method); } else { dvmInterpret(self, method, pResult); } #ifndef NDEBUG bail: #endif dvmPopFrame(self); }
static void de_robv_android_xposed_XposedBridge_dumpObjectNative(JNIEnv* env, jclass clazz, jobject objIndirect) { Object* obj = (Object*) dvmDecodeIndirectRef(dvmThreadSelf(), objIndirect); dvmDumpObject(obj); }
long GetObjectId(Thread* self, jobject jo){ return dvmDecodeIndirectRef(self, jo)->uuid; }
/* * Issue a method call with a variable number of arguments. We process * the contents of "args" by scanning the method signature. * * Pass in NULL for "obj" on calls to static methods. * * We don't need to take the class as an argument because, in Dalvik, * we don't need to worry about static synchronized methods. */ void dvmCallMethodV(Thread* self, const Method* method, Object* obj, bool fromJni, JValue* pResult, va_list args) { const char* desc = &(method->shorty[1]); // [0] is the return type. int verifyCount = 0; ClassObject* clazz; u4* ins; #ifdef WITH_TAINT_TRACKING int slot_cnt = 0; bool nativeTarget = dvmIsNativeMethod(method); #endif clazz = callPrep(self, method, obj, false); if (clazz == NULL) return; /* "ins" for new frame start at frame pointer plus locals */ #ifdef WITH_TAINT_TRACKING if (nativeTarget) { /* native target, no taint tag interleaving */ ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize); } else { /* interpreted target, taint tags are interleaved */ ins = ((u4*)self->curFrame) + ((method->registersSize - method->insSize) << 1); } #else ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize); #endif //LOGD(" FP is %p, INs live at >= %p\n", self->curFrame, ins); /* put "this" pointer into in0 if appropriate */ if (!dvmIsStaticMethod(method)) { #ifdef WITH_EXTRA_OBJECT_VALIDATION assert(obj != NULL && dvmIsValidObject(obj)); #endif *ins++ = (u4) obj; #ifdef WITH_TAINT_TRACKING if (!nativeTarget) { *ins++ = TAINT_CLEAR; } slot_cnt++; #endif verifyCount++; } JNIEnv* env = self->jniEnv; while (*desc != '\0') { switch (*(desc++)) { case 'D': case 'J': { u8 val = va_arg(args, u8); memcpy(ins, &val, 8); // EABI prevents direct store #ifdef WITH_TAINT_TRACKING if (nativeTarget) { ins += 2; } else { /* adjust for taint tag interleaving */ ins[2] = ins[1]; ins[1] = TAINT_CLEAR; ins[3] = TAINT_CLEAR; ins += 4; } slot_cnt += 2; #else ins += 2; #endif verifyCount += 2; break; } case 'F': { /* floats were normalized to doubles; convert back */ float f = (float) va_arg(args, double); *ins++ = dvmFloatToU4(f); #ifdef WITH_TAINT_TRACKING if (!nativeTarget) { *ins++ = TAINT_CLEAR; } slot_cnt++; #endif verifyCount++; break; } case 'L': { /* 'shorty' descr uses L for all refs, incl array */ void* argObj = va_arg(args, void*); assert(obj == NULL || dvmIsValidObject(obj)); if (fromJni) *ins++ = (u4) dvmDecodeIndirectRef(env, argObj); else *ins++ = (u4) argObj; #ifdef WITH_TAINT_TRACKING if (!nativeTarget) { *ins++ = TAINT_CLEAR; } slot_cnt++; #endif verifyCount++; break; } default: { /* Z B C S I -- all passed as 32-bit integers */ *ins++ = va_arg(args, u4); #ifdef WITH_TAINT_TRACKING if (!nativeTarget) { *ins++ = TAINT_CLEAR; } slot_cnt++; #endif verifyCount++; break; } } } #ifdef WITH_TAINT_TRACKING /* native hack spacer */ *ins++ = TAINT_CLEAR; /* if nativeTarget, this is return taint */ { int i; if (nativeTarget) { for (i = 0; i < slot_cnt; i++) { *ins++ = TAINT_CLEAR; } } } #endif #ifndef NDEBUG if (verifyCount != method->insSize) { LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount, method->insSize, clazz->descriptor, method->name); assert(false); goto bail; } #endif //dvmDumpThreadStack(dvmThreadSelf()); if (dvmIsNativeMethod(method)) { TRACE_METHOD_ENTER(self, method); /* * Because we leave no space for local variables, "curFrame" points * directly at the method arguments. */ (*method->nativeFunc)(self->curFrame, pResult, method, self); TRACE_METHOD_EXIT(self, method); } else { #ifdef WITH_TAINT_TRACKING u4 rtaint; /* not used */ dvmInterpret(self, method, pResult, &rtaint); #else dvmInterpret(self, method, pResult); #endif } #ifndef NDEBUG bail: #endif dvmPopFrame(self); }
/* * Issue a method call with arguments provided in an array. We process * the contents of "args" by scanning the method signature. * * The values were likely placed into an uninitialized jvalue array using * the field specifiers, which means that sub-32-bit fields (e.g. short, * boolean) may not have 32 or 64 bits of valid data. This is different * from the varargs invocation where the C compiler does a widening * conversion when calling a function. As a result, we have to be a * little more precise when pulling stuff out. * * "args" may be NULL if the method has no arguments. */ void dvmCallMethodA(Thread* self, const Method* method, Object* obj, bool fromJni, JValue* pResult, const jvalue* args) { const char* desc = &(method->shorty[1]); // [0] is the return type. int verifyCount = 0; ClassObject* clazz; u4* ins; #ifdef WITH_TAINT_TRACKING int slot_cnt = 0; bool nativeTarget = dvmIsNativeMethod(method); #endif clazz = callPrep(self, method, obj, false); if (clazz == NULL) return; /* "ins" for new frame start at frame pointer plus locals */ #ifdef WITH_TAINT_TRACKING if (nativeTarget) { /* native target, no taint tag interleaving */ ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize); } else { /* interpreted target, taint tags are interleaved */ ins = ((u4*)self->curFrame) + ((method->registersSize - method->insSize) << 1); } #else ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize); #endif /* put "this" pointer into in0 if appropriate */ if (!dvmIsStaticMethod(method)) { assert(obj != NULL); *ins++ = (u4) obj; /* obj is a "real" ref */ #ifdef WITH_TAINT_TRACKING if (!nativeTarget) { *ins++ = TAINT_CLEAR; } slot_cnt++; #endif verifyCount++; } JNIEnv* env = self->jniEnv; while (*desc != '\0') { switch (*desc++) { case 'D': /* 64-bit quantity; have to use */ case 'J': /* memcpy() in case of mis-alignment */ memcpy(ins, &args->j, 8); #ifdef WITH_TAINT_TRACKING if (nativeTarget) { ins += 2; } else { /* adjust for taint tag interleaving */ ins[2] = ins[1]; ins[1] = TAINT_CLEAR; ins[3] = TAINT_CLEAR; ins += 4; } slot_cnt += 2; #else ins += 2; #endif verifyCount++; /* this needs an extra push */ break; case 'L': /* includes array refs */ if (fromJni) *ins++ = (u4) dvmDecodeIndirectRef(env, args->l); else *ins++ = (u4) args->l; #ifdef WITH_TAINT_TRACKING if (!nativeTarget) { *ins++ = TAINT_CLEAR; } slot_cnt++; #endif break; case 'F': case 'I': *ins++ = args->i; /* full 32 bits */ #ifdef WITH_TAINT_TRACKING if (!nativeTarget) { *ins++ = TAINT_CLEAR; } slot_cnt++; #endif break; case 'S': *ins++ = args->s; /* 16 bits, sign-extended */ #ifdef WITH_TAINT_TRACKING if (!nativeTarget) { *ins++ = TAINT_CLEAR; } slot_cnt++; #endif break; case 'C': *ins++ = args->c; /* 16 bits, unsigned */ #ifdef WITH_TAINT_TRACKING if (!nativeTarget) { *ins++ = TAINT_CLEAR; } slot_cnt++; #endif break; case 'B': *ins++ = args->b; /* 8 bits, sign-extended */ #ifdef WITH_TAINT_TRACKING if (!nativeTarget) { *ins++ = TAINT_CLEAR; } slot_cnt++; #endif break; case 'Z': *ins++ = args->z; /* 8 bits, zero or non-zero */ #ifdef WITH_TAINT_TRACKING if (!nativeTarget) { *ins++ = TAINT_CLEAR; } slot_cnt++; #endif break; default: LOGE("Invalid char %c in short signature of %s.%s\n", *(desc-1), clazz->descriptor, method->name); assert(false); goto bail; } verifyCount++; args++; } #ifdef WITH_TAINT_TRACKING /* native hack spacer */ *ins++ = TAINT_CLEAR; /* if nativeTarget, this is return taint */ { int i; if (nativeTarget) { for (i = 0; i < slot_cnt; i++) { *ins++ = TAINT_CLEAR; } } } #endif #ifndef NDEBUG if (verifyCount != method->insSize) { LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount, method->insSize, clazz->descriptor, method->name); assert(false); goto bail; } #endif if (dvmIsNativeMethod(method)) { TRACE_METHOD_ENTER(self, method); /* * Because we leave no space for local variables, "curFrame" points * directly at the method arguments. */ (*method->nativeFunc)(self->curFrame, pResult, method, self); TRACE_METHOD_EXIT(self, method); } else { #ifdef WITH_TAINT_TRACKING u4 rtaint; /* not used */ dvmInterpret(self, method, pResult, &rtaint); #else dvmInterpret(self, method, pResult); #endif } bail: dvmPopFrame(self); }