/*
 * Return a new Object[] array with the contents of "args".  We determine
 * the number and types of values in "args" based on the method signature.
 * Primitive types are boxed.
 *
 * Returns NULL if the method takes no arguments.
 *
 * The caller must call dvmReleaseTrackedAlloc() on the return value.
 *
 * On failure, returns with an appropriate exception raised.
 */
static ArrayObject* boxMethodArgs(const Method* method, const u4* args) {
	const char* desc = &method->shorty[1]; // [0] is the return type.

	/* count args */
	size_t argCount = dexProtoGetParameterCount_fnPtr(&method->prototype);

	/* allocate storage */
	ArrayObject* argArray = dvmAllocArrayByClass_fnPtr(classJavaLangObjectArray,
			argCount, ALLOC_DEFAULT);
	if (argArray == NULL)
		return NULL;
	Object** argObjects = (Object**) (void*) argArray->contents;

	/*
	 * Fill in the array.
	 */

	size_t srcIndex = 0;
	size_t dstIndex = 0;
	while (*desc != '\0') {
		char descChar = *(desc++);
		jvalue value;

		switch (descChar) {
		case 'Z':
		case 'C':
		case 'F':
		case 'B':
		case 'S':
		case 'I':
			value.i = args[srcIndex++];
			argObjects[dstIndex] = (Object*) dvmBoxPrimitive_fnPtr(value,
					dvmFindPrimitiveClass_fnPtr(descChar));
			/* argObjects is tracked, don't need to hold this too */
			dvmReleaseTrackedAlloc_fnPtr(argObjects[dstIndex], NULL);
			dstIndex++;
			break;
		case 'D':
		case 'J':
			value.j = dvmGetArgLong(args, srcIndex);
			srcIndex += 2;
			argObjects[dstIndex] = (Object*) dvmBoxPrimitive_fnPtr(value,
					dvmFindPrimitiveClass_fnPtr(descChar));
			dvmReleaseTrackedAlloc_fnPtr(argObjects[dstIndex], NULL);
			dstIndex++;
			break;
		case '[':
		case 'L':
			argObjects[dstIndex++] = (Object*) args[srcIndex++];
			LOGD("boxMethodArgs object: index = %d", dstIndex - 1);
			break;
		}
	}

	return argArray;
}
Exemple #2
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);
}
Exemple #3
0
/*
 * Return a new Object[] array with the contents of "args".  We determine
 * the number and types of values in "args" based on the method signature.
 * Primitive types are boxed.
 *
 * Returns NULL if the method takes no arguments.
 *
 * The caller must call dvmReleaseTrackedAlloc() on the return value.
 *
 * On failure, returns with an appropriate exception raised.
 */
static ArrayObject* boxMethodArgs(const Method* method, const u4* args)
{
    const char* desc = &method->shorty[1]; // [0] is the return type.
    ArrayObject* argArray = NULL;
    int argCount;
    Object** argObjects;
    bool failed = true;

    /* count args */
    argCount = dexProtoGetParameterCount(&method->prototype);

    /* allocate storage */
    argArray = dvmAllocArray(gDvm.classJavaLangObjectArray, argCount,
        kObjectArrayRefWidth, ALLOC_DEFAULT);
    if (argArray == NULL)
        goto bail;
    argObjects = (Object**) argArray->contents;

    /*
     * Fill in the array.
     */

    int srcIndex = 0;
    
    argCount = 0;
    while (*desc != '\0') {
        char descChar = *(desc++);
        JValue value;

        switch (descChar) {
        case 'Z':
        case 'C':
        case 'F':
        case 'B':
        case 'S':
        case 'I':
            value.i = args[srcIndex++];
            argObjects[argCount] = (Object*) dvmWrapPrimitive(value,
                dvmFindPrimitiveClass(descChar));
            /* argObjects is tracked, don't need to hold this too */
            dvmReleaseTrackedAlloc(argObjects[argCount], NULL);
            argCount++;
            break;
        case 'D':
        case 'J':
            value.j = dvmGetArgLong(args, srcIndex);
            srcIndex += 2;
            argObjects[argCount] = (Object*) dvmWrapPrimitive(value,
                dvmFindPrimitiveClass(descChar));
            dvmReleaseTrackedAlloc(argObjects[argCount], NULL);
            argCount++;
            break;
        case '[':
        case 'L':
            argObjects[argCount++] = (Object*) args[srcIndex++];
            break;
        }
    }

    failed = false;

bail:
    if (failed) {
        dvmReleaseTrackedAlloc((Object*)argArray, NULL);
        argArray = NULL;
    }
    return argArray;
}
Exemple #4
0
static void xposedCallHandler(const u4* args, JValue* pResult,
		const Method* method, ::Thread* self) {
	if (!xposedIsHooked(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\n",
					descChar);
			obj = NULL;
			srcIndex++;
		}
		xposedSetObjectArrayElement(argsArray, dstIndex++, obj);
	}

	// call the Java handler function
	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);
		}
	}
}