Example #1
0
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;
}
Example #2
0
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;
	}
}
Example #3
0
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;
    }
}
Example #4
0
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
}
Example #5
0
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;
}
Example #6
0
// 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);
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #9
0
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;
}
Example #10
0
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;
}
Example #11
0
/*
 * 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);
}
Example #12
0
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);
}
Example #13
0
/*
 * 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);
}
Example #14
0
static void de_robv_android_xposed_XposedBridge_dumpObjectNative(JNIEnv* env, jclass clazz, jobject objIndirect) {
    Object* obj = (Object*) dvmDecodeIndirectRef(dvmThreadSelf(), objIndirect);
    dvmDumpObject(obj);
}
Example #15
0
long GetObjectId(Thread* self, jobject jo){
	return dvmDecodeIndirectRef(self, jo)->uuid;
}
Example #16
0
/*
 * 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);
}
Example #17
0
/*
 * 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);
}