Example #1
0
/*
 * Get an array with all constructors declared by a class.
 */
ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly)
{
    if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor))
        dvmInitClass(gDvm.classJavaLangReflectConstructor);

    /*
     * Ordinarily we init the class the first time we resolve a method.
     * We're bypassing the normal resolution mechanism, so we init it here.
     */
    if (!dvmIsClassInitialized(clazz))
        dvmInitClass(clazz);

    /*
     * Count up the #of relevant methods.
     */
    size_t count = 0;
    for (int i = 0; i < clazz->directMethodCount; ++i) {
        Method* meth = &clazz->directMethods[i];
        if ((!publicOnly || dvmIsPublicMethod(meth)) &&
            dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
        {
            count++;
        }
    }

    /*
     * Create an array of Constructor objects.
     */
    ClassObject* arrayClass = gDvm.classJavaLangReflectConstructorArray;
    ArrayObject* ctorArray = dvmAllocArrayByClass(arrayClass, count, ALLOC_DEFAULT);
    if (ctorArray == NULL)
        return NULL;

    /*
     * Fill out the array.
     */
    size_t ctorObjCount = 0;
    for (int i = 0; i < clazz->directMethodCount; ++i) {
        Method* meth = &clazz->directMethods[i];
        if ((!publicOnly || dvmIsPublicMethod(meth)) &&
            dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
        {
            Object* ctorObj = createConstructorObject(meth);
            if (ctorObj == NULL) {
              dvmReleaseTrackedAlloc((Object*) ctorArray, NULL);
              return NULL;
            }
            dvmSetObjectArrayElement(ctorArray, ctorObjCount, ctorObj);
            ++ctorObjCount;
            dvmReleaseTrackedAlloc(ctorObj, NULL);
        }
    }

    assert(ctorObjCount == ctorArray->length);

    /* caller must call dvmReleaseTrackedAlloc */
    return ctorArray;
}
u4 getEntryTaint(const char* entry, const u4* args, const Method* method)
{
    u4 tag = TAINT_CLEAR;
    char *pos;

    /* Determine split point if any */
    pos = index((char *) entry, '.');

    switch (getEntryType(entry)) {
	case kTaintProfileClass:
	    if (dvmIsStaticMethod(method)) {
		tag = getFieldEntryTaint(pos+1, method->clazz, NULL);
	    } else {
		tag = getFieldEntryTaint(pos+1, method->clazz, (Object*)args[0]);
	    }
	    break;

	case kTaintProfileParam:
	    tag = getParamEntryTaint(entry, args, method);
	    break;

	default:
	    ALOGW("TaintPolicy: Invalid from type: [%s]", entry);
    }
    
    return tag;
}
u4 addEntryTaint(u4 tag, const char* entry, const u4* args, const Method* method)
{
    u4 rtaint = TAINT_CLEAR;

    switch (getEntryType(entry)) {
	case kTaintProfileClass:
	    if (dvmIsStaticMethod(method)) {
		addFieldEntryTaint(tag, entry, method->clazz, NULL);
	    } else {
		addFieldEntryTaint(tag, entry, method->clazz, (Object*)args[0]);
	    }
	    break;

	case kTaintProfileParam:
	    addParamEntryTaint(tag, entry, args, method);
	    break;

	case kTaintProfileReturn:
	    if (entry[7] == '\0') { /* taint the return itself */
		rtaint = tag;
	    } else {
		// TODO: implement return field tainting (need pResult)
		ALOGW("TaintPolicy: tainting return fields not supported");
	    }
	    break;

	default:
	    ALOGW("TaintPolicy: Invalid from type: [%s]", entry);
    }

    return rtaint;
}
/*
 * Resolve a native method and invoke it.
 *
 * This is executed as if it were a native bridge or function.  If the
 * resolution succeeds, method->insns is replaced, and we don't go through
 * here again.
 *
 * Initializes method's class if necessary.
 *
 * An exception is thrown on resolution failure.
 */
void dvmResolveNativeMethod(const u4* args, JValue* pResult,
    const Method* method, Thread* self)
{
    ClassObject* clazz = method->clazz;
    void* func;

    /*
     * If this is a static method, it could be called before the class
     * has been initialized.
     */
    if (dvmIsStaticMethod(method)) {
        if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
            assert(dvmCheckException(dvmThreadSelf()));
            return;
        }
    } else {
        assert(dvmIsClassInitialized(clazz) ||
               dvmIsClassInitializing(clazz));
    }

    /* start with our internal-native methods */
    func = dvmLookupInternalNativeMethod(method);
    if (func != NULL) {
        /* resolution always gets the same answer, so no race here */
        IF_LOGVV() {
            char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
            LOGVV("+++ resolved native %s.%s %s, invoking\n",
                clazz->descriptor, method->name, desc);
            free(desc);
        }
Example #5
0
/*
 * 在'clazz'中,我们有一个方法指向另一个方法,但它可能指向派生类中的一个方法,我们想要从虚拟函数表中找到实际入口,如果'class'是一个接口,我们不得不在短时间内做更多的挖掘
 *
 * 对于'direct'方法(private / constructor).我们仅仅返回原生态方法
 *  
 * (这里被适用于反射和JNI调用)
 */
const Method* dvmGetVirtualizedMethod(const ClassObject* clazz,
    const Method* meth)
{
    Method* actualMeth;
    int methodIndex;

    if (dvmIsDirectMethod(meth)) {
        /* no vtable entry for these */
        assert(!dvmIsStaticMethod(meth));
        return meth;
    }

    /*
     * If the method was declared in an interface, we need to scan through
     * the class' list of interfaces for it, and find the vtable index
     * from that.
     *
     * TODO: use the interface cache.
     */
    if (dvmIsInterfaceClass(meth->clazz)) {
        int i;

        for (i = 0; i < clazz->iftableCount; i++) {
            if (clazz->iftable[i].clazz == meth->clazz)
                break;
        }
        if (i == clazz->iftableCount) {
            dvmThrowIncompatibleClassChangeError(
                "invoking method from interface not implemented by class");
            return NULL;
        }

        methodIndex = clazz->iftable[i].methodIndexArray[meth->methodIndex];
    } else {
        methodIndex = meth->methodIndex;
    }

    assert(methodIndex >= 0 && methodIndex < clazz->vtableCount);
    actualMeth = clazz->vtable[methodIndex];

    /*
     * Make sure there's code to execute.
     */
    if (dvmIsAbstractMethod(actualMeth)) {
        dvmThrowAbstractMethodError(NULL);
        return NULL;
    }
    assert(!dvmIsMirandaMethod(actualMeth));

    return actualMeth;
}
Example #6
0
bool HookDalvikMethod(jmethodID jmethod){
	Method *method = (Method*)jmethod;
	//关键!!将目标方法修改为native方法
	SET_METHOD_FLAG(method, ACC_NATIVE);

	int argsSize = dvmComputeMethodArgsSize(method);
    if (!dvmIsStaticMethod(method))
        argsSize++;

    method->registersSize = method->insSize = argsSize;

    if (dvmIsNativeMethod(method)) {
        method->nativeFunc = dvmResolveNativeMethod;
        method->jniArgInfo = computeJniArgInfo(&method->prototype);
    }
}
/* Returns the index in args[] corresponding to the parameter
 * string entry.
 * - It doesn't matter if the entry has multiple parts, e.g.,
 *   "param1.foo.bar", as long as the variable name after the first
 *   "." is not a number. Since the signature comes next, we can 
 *   safely assume this is the case.
 * - returns -1 on parsing error
 * - If descriptor is not NULL, it will point to a newly allocated 
 *   descriptor that needs to be free()'d (unless there was an error)
 */
int paramToArgIndex(const char* entry, const Method* method, char** descriptor) {
    int pIdx, aIdx, i;
    char* endptr;
    const char* num = entry + 5; /* "param" is the first 5 characters */
    const DexProto* proto = &method->prototype;
    DexParameterIterator pIterator;

    /* Step 1: determine the parameter index (pIdx) */
    pIdx = strtol(num, &endptr, 10);
    if (num == endptr) {
	/* error parsing */
	return -1;
    } 

    /* Step 2: translate parameter index into args array index */
    dexParameterIteratorInit(&pIterator, proto);
    aIdx = (dvmIsStaticMethod(method)?0:1); /* index where params start */
    for (i=0; i<=pIdx ; i++) {
	const char* desc = dexParameterIteratorNextDescriptor(&pIterator);

	if (desc == NULL) {
	    /* This index doesn't exist, error */
	    return -1;
	} 

	if (i == pIdx) {
	    /* This is the index */
	    if (descriptor != NULL) {
		*descriptor = strdup(desc);
	    }
	    break;
	}

	/* increment the args array index */
	aIdx++;

	if (desc[0] == 'J' || desc[0] == 'D') {
	    /* wide argument, increment index one more */
	    aIdx++;
	}
    }

    return aIdx;
}
extern void __attribute__ ((visibility ("hidden"))) dalvik_replaceMethod(
		JNIEnv* env, jobject src, jobject dest) {
	jobject clazz = env->CallObjectMethod(dest, jClassMethod);
	ClassObject* clz = (ClassObject*) dvmDecodeIndirectRef_fnPtr(
			dvmThreadSelf_fnPtr(), clazz);
	clz->status = CLASS_INITIALIZED;

	Method* meth = (Method*) env->FromReflectedMethod(src);
	Method* target = (Method*) env->FromReflectedMethod(dest);
	LOGD("dalvikMethod: %s", meth->name);

	meth->jniArgInfo = 0x80000000;
	meth->accessFlags |= ACC_NATIVE;

	int argsSize = dvmComputeMethodArgsSize_fnPtr(meth);
	if (!dvmIsStaticMethod(meth))
		argsSize++;
	meth->registersSize = meth->insSize = argsSize;
	meth->insns = (void*) target;//在Dalvik中,每个方法都是一个Method的结构体,其中当这个方法是native的时候,Method的insns这个指针会指向native方法的起始地址。

	meth->nativeFunc = dalvik_dispatcher;
}
/**
 * 使用jni GetMethodID 方法获取jmethodID 强制转为 Method 的hook 方法 示例
 */
static void newTestMethod(const u4* args, JValue* pResult,
                          const Method* method, struct Thread* self) {

    // args 是原来函数的参数数组, 原来test函数只有一个String型参数
    // 并且要注意, 如果是不是static函数, 下标0 是函数所在类的实例obj
    // 在dvm中Object,  jni 中的jobject 和 java 中的 Object类 都不是同一个东西
    // String类对应StringObject
    // 取出参数打印出来看看
    StringObject* param1 = NULL;

    if(dvmIsStaticMethod(method))
        param1 = (StringObject*)args[0];
    else
        param1 = (StringObject*)args[1];
    LOGD("param1:%s",dvmCreateCstrFromString(param1));

    //JValue 是个union ,要返回int 就 pResult->i=1; 返回Object对象就 pResult->l = ojb;
    // 但是, 在dvm中的Object,  jni 中的jobject 和 java 中的 Object类 都不是同一个东西
    // 所以, 我们这里使用dvm的函数来创建一个StringObject*
    pResult->l = dvmCreateStringFromCstr("newTestMethod");

    // 一般情况应该使用宏 : RETURN_XXX(result);
    return;
}
Example #10
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 #11
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);
}
/* Used to propagate taint for JNI methods
 * Two types of propagation:
 *  1) simple conservative propagation based on parameters
 *  2) propagation based on function profile policies
 */
void dvmTaintPropJniMethod(const u4* args, JValue* pResult, const Method* method, const int nativeTaint)
{
    const DexProto* proto = &method->prototype;
    DexParameterIterator pIterator;
    int nParams = dexProtoGetParameterCount(proto);
    int pStart = (dvmIsStaticMethod(method)?0:1); /* index where params start */

    /* Consider 3 arguments. [x] indicates return taint index
     * 0 1 2 [3] 4 5 6
     */
    int nArgs = method->insSize;
    u4* rtaint = (u4*) &args[nArgs]; /* The return taint value */
    int tStart = nArgs+1; /* index of args[] where taint values start */
    int tEnd   = nArgs*2; /* index of args[] where taint values end */
    u4	tag = TAINT_CLEAR;
    int i;

#if 0
    {
        char *desc = dexProtoCopyMethodDescriptor(proto);
        ALOGW("Jni: %s.%s%s, descriptor: %s", 
            method->clazz->descriptor, method->name, 
            dvmIsStaticMethod(method)?"[static]":"", desc);
        free(desc);
    }
#endif

#ifdef TAINT_JNI_LOG
    /* JNI logging for debugging purposes */
    if (gJniLog) {
	u4 hash;
	int len;
	char *inStr, *outStr;

	len = strlen(method->clazz->descriptor) + 1 + strlen(method->name);
	inStr = (char*) malloc(len+1);
	strcpy(inStr, method->clazz->descriptor);
	strcat(inStr, ".");
	strcat(inStr, method->name);
	hash = dvmComputeUtf8Hash(inStr);

	dvmHashTableLock(gJniLogSeen);

	outStr = (char*) dvmHashTableLookup(gJniLogSeen, hash, inStr, 
		(HashCompareFunc) strcmp, false);

	if (outStr == NULL) {
	    /* New method! */
	    /* add it */
	    dvmHashTableLookup(gJniLogSeen, hash, inStr, 
		(HashCompareFunc) strcmp, true);
	} else {
	    free(inStr); /* don't need this anymore */
	}

	dvmHashTableUnlock(gJniLogSeen);
    }
#endif

    /* Union the taint tags, this includes object ref tags 
     * - we don't need to worry about static vs. not static, because getting
     *	 the taint tag on the "this" object reference is a good
     * - we don't need to worry about wide registers, because the stack
     *	 interleaving of taint tags makes it transparent
     */
    /*for (i = tStart; i <= tEnd; i++) {
    	tag |= args[i];
    	if (args[i]!=0 && args[i]!=TAINT_ACCELEROMETER) //found a taint, and its not the accelerometer spam either
    		ALOGD("dvmTaintPropJNIMethod found taint %08x in method=%s:%s(%s) for arg[%d]=%08x",
    				args[i], method->clazz->descriptor, method->name, method->shorty, i-nArgs, args[i-nArgs]);
    }*/

    /* If not static, pull any taint from the "this" object */
    /*if (!dvmIsStaticMethod(method)) {
	tag |= getObjectTaint((Object*)args[0], method->clazz->descriptor);
    }*/

    /* Union taint from Objects we care about */
    dexParameterIteratorInit(&pIterator, proto);
    for (i=pStart; ; i++) {
	const char* desc = dexParameterIteratorNextDescriptor(&pIterator);

	if (desc == NULL) {
	    break;
	} 
	
	if (desc[0] == '[' || desc[0] == 'L') {
	    tag |= getObjectTaint((Object*) args[i], desc);
	}

	if (desc[0] == 'J' || desc[0] == 'D') {
	    /* wide argument, increment index one more */
	    i++;
	}
    }

    /* Look at the taint policy profiles (may have return taint) */
    //tag |= propMethodProfile(args, method);

    /* Update return taint according to the return type */
    //Native Tainting: get taint Value from native code
    //if (tag) {
    if (nativeTaint) {
	const char* desc = dexProtoGetReturnType(proto);
	//setReturnTaint(tag, rtaint, pResult, desc);
	ALOGD("dvmTaintPropJniMethod: setting result taint to %x", nativeTaint);
	setReturnTaint(nativeTaint, rtaint, pResult, desc);
    }
}
Example #13
0
/* Dalvik puts private, static, and constructors into non-virtual table */
INLINE bool dvmIsDirectMethod(const Method* method) {
    return dvmIsPrivateMethod(method) ||
           dvmIsStaticMethod(method) ||
           dvmIsConstructorMethod(method);
}
Example #14
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,
    JValue* pResult, va_list args)
{
    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->curFrame) + (method->registersSize - method->insSize);

    //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;
        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;
            }
#ifdef WITH_EXTRA_OBJECT_VALIDATION
            case 'L': {     /* 'shorty' descr uses L for all refs, incl array */
                Object* argObj = (Object*) va_arg(args, u4);
                assert(obj == NULL || dvmIsValidObject(obj));
                *ins++ = (u4) argObj;
                verifyCount++;
                break;
            }
#endif
            default: {
                *ins++ = va_arg(args, u4);
                verifyCount++;
                break;
            }
        }
    }

#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)) {
        /*
         * Because we leave no space for local variables, "curFrame" points
         * directly at the method arguments.
         */
        (*method->nativeFunc)(self->curFrame, pResult, method, self);
    } else {
        dvmInterpret(self, method, pResult);
    }

bail:
    dvmPopFrame(self);
}
Example #15
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,
    JValue* pResult, const jvalue* args)
{
    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->curFrame) + (method->registersSize - method->insSize);

    /* put "this" pointer into in0 if appropriate */
    if (!dvmIsStaticMethod(method)) {
        assert(obj != NULL);
        *ins++ = (u4) obj;
        verifyCount++;
    }

    while (*desc != '\0') {
        switch (*(desc++)) {
            case 'D': case 'J': {
                memcpy(ins, &args->j, 8);   /* EABI prevents direct store */
                ins += 2;
                verifyCount += 2;
                args++;
                break;
            }
            case 'F': case 'I': case 'L': { /* (no '[' in short signatures) */
                *ins++ = args->i;           /* get all 32 bits */
                verifyCount++;
                args++;
                break;
            }
            case 'S': {
                *ins++ = args->s;           /* 16 bits, sign-extended */
                verifyCount++;
                args++;
                break;
            }
            case 'C': {
                *ins++ = args->c;           /* 16 bits, unsigned */
                verifyCount++;
                args++;
                break;
            }
            case 'B': {
                *ins++ = args->b;           /* 8 bits, sign-extended */
                verifyCount++;
                args++;
                break;
            }
            case 'Z': {
                *ins++ = args->z;           /* 8 bits, zero or non-zero */
                verifyCount++;
                args++;
                break;
            }
            default: {
                LOGE("Invalid char %c in short signature of %s.%s\n",
                    *(desc-1), clazz->descriptor, method->name);
                assert(false);
                goto bail;
            }
        }
    }

#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)) {
        /*
         * Because we leave no space for local variables, "curFrame" points
         * directly at the method arguments.
         */
        (*method->nativeFunc)(self->curFrame, pResult, method, self);
    } else {
        dvmInterpret(self, method, pResult);
    }

bail:
    dvmPopFrame(self);
}
Example #16
0
/*
 * Alternate version of dvmResolveMethod().
 *
 * Doesn't throw exceptions, and checks access on every lookup.
 *
 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
 */
Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
    MethodType methodType, VerifyError* pFailure)
{
    DvmDex* pDvmDex = referrer->pDvmDex;
    Method* resMethod;

    assert(methodType == METHOD_DIRECT ||
           methodType == METHOD_VIRTUAL ||
           methodType == METHOD_STATIC);

    LOGVV("--- resolving method %u (referrer=%s)", methodIdx,
        referrer->descriptor);

    resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
    if (resMethod == NULL) {
        const DexMethodId* pMethodId;
        ClassObject* resClass;

        pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);

        resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
        if (resClass == NULL) {
            /*
             * Can't find the class that the method is a part of, or don't
             * have permission to access the class.
             */
            ALOGV("DexOpt: can't find called method's class (?.%s)",
                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
            return NULL;
        }
        if (dvmIsInterfaceClass(resClass)) {
            /* method is part of an interface; this is wrong method for that */
            ALOGW("DexOpt: method is in an interface");
            if (pFailure != NULL)
                *pFailure = VERIFY_ERROR_GENERIC;
            return NULL;
        }

        /*
         * We need to chase up the class hierarchy to find methods defined
         * in super-classes.  (We only want to check the current class
         * if we're looking for a constructor.)
         */
        DexProto proto;
        dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);

        if (methodType == METHOD_DIRECT) {
            resMethod = dvmFindDirectMethod(resClass,
                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
        } else {
            /* METHOD_STATIC or METHOD_VIRTUAL */
            resMethod = dvmFindMethodHier(resClass,
                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
        }

        if (resMethod == NULL) {
            ALOGV("DexOpt: couldn't find method '%s'",
                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
            if (pFailure != NULL)
                *pFailure = VERIFY_ERROR_NO_METHOD;
            return NULL;
        }
        if (methodType == METHOD_STATIC) {
            if (!dvmIsStaticMethod(resMethod)) {
                ALOGD("DexOpt: wanted static, got instance for method %s.%s",
                    resClass->descriptor, resMethod->name);
                if (pFailure != NULL)
                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
                return NULL;
            }
        } else if (methodType == METHOD_VIRTUAL) {
            if (dvmIsStaticMethod(resMethod)) {
                ALOGD("DexOpt: wanted instance, got static for method %s.%s",
                    resClass->descriptor, resMethod->name);
                if (pFailure != NULL)
                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
                return NULL;
            }
        }

        /* see if this is a pure-abstract method */
        if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
            ALOGW("DexOpt: pure-abstract method '%s' in %s",
                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
                resClass->descriptor);
            if (pFailure != NULL)
                *pFailure = VERIFY_ERROR_GENERIC;
            return NULL;
        }

        /*
         * Add it to the resolved table so we're faster on the next lookup.
         *
         * We can only do this for static methods if we're not in "dexopt",
         * because the presence of a valid value in the resolution table
         * implies that the class containing the static field has been
         * initialized.
         */
        if (methodType != METHOD_STATIC || gDvm.optimizing)
            dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
    }

    LOGVV("--- found method %d (%s.%s)",
        methodIdx, resMethod->clazz->descriptor, resMethod->name);

    /* access allowed? */
    tweakLoader(referrer, resMethod->clazz);
    bool allowed = dvmCheckMethodAccess(referrer, resMethod);
    untweakLoader(referrer, resMethod->clazz);
    if (!allowed) {
        IF_ALOGI() {
            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
            ALOGI("DexOpt: illegal method access (call %s.%s %s from %s)",
                resMethod->clazz->descriptor, resMethod->name, desc,
                referrer->descriptor);
            free(desc);
        }
/*
 * private Object invokeNative(Object obj, Object[] args, Class declaringClass,
 *   Class[] parameterTypes, Class returnType, int slot, boolean noAccessCheck)
 *
 * Invoke a static or virtual method via reflection.
 */
static void Dalvik_java_lang_reflect_Method_invokeNative(const u4* args,
    JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* methObj = (Object*) args[1];        // null for static methods
    ArrayObject* argList = (ArrayObject*) args[2];
    ClassObject* declaringClass = (ClassObject*) args[3];
    ArrayObject* params = (ArrayObject*) args[4];
    ClassObject* returnType = (ClassObject*) args[5];
    int slot = args[6];
    bool noAccessCheck = (args[7] != 0);
    const Method* meth;
    Object* result;

    /*
     * "If the underlying method is static, the class that declared the
     * method is initialized if it has not already been initialized."
     */
    meth = dvmSlotToMethod(declaringClass, slot);
    assert(meth != NULL);

    if (dvmIsStaticMethod(meth)) {
        if (!dvmIsClassInitialized(declaringClass)) {
            if (!dvmInitClass(declaringClass))
                goto init_failed;
        }
    } else {
        /* looks like interfaces need this too? */
        if (dvmIsInterfaceClass(declaringClass) &&
            !dvmIsClassInitialized(declaringClass))
        {
            if (!dvmInitClass(declaringClass))
                goto init_failed;
        }

        /* make sure the object is an instance of the expected class */
        if (!dvmVerifyObjectInClass(methObj, declaringClass)) {
            assert(dvmCheckException(dvmThreadSelf()));
            RETURN_VOID();
        }

        /* do the virtual table lookup for the method */
        meth = dvmGetVirtualizedMethod(methObj->clazz, meth);
        if (meth == NULL) {
            assert(dvmCheckException(dvmThreadSelf()));
            RETURN_VOID();
        }
    }

    /*
     * If the method has a return value, "result" will be an object or
     * a boxed primitive.
     */
    result = dvmInvokeMethod(methObj, meth, argList, params, returnType,
                noAccessCheck);

    RETURN_PTR(result);

init_failed:
    /*
     * If initialization failed, an exception will be raised.
     */
    ALOGD("Method.invoke() on bad class %s failed",
        declaringClass->descriptor);
    assert(dvmCheckException(dvmThreadSelf()));
    RETURN_VOID();
}
Example #18
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);
}
static void dalvik_dispatcher(const u4* args, jvalue* pResult,
		const Method* method, void* self) {
	ClassObject* returnType;
	jvalue result;
	ArrayObject* argArray;

	LOGD("dalvik_dispatcher source method: %s %s", method->name,
			method->shorty);
	Method* meth = (Method*) method->insns;
	meth->accessFlags = meth->accessFlags | ACC_PUBLIC;
	LOGD("dalvik_dispatcher target method: %s %s", method->name,
			method->shorty);

	returnType = dvmGetBoxedReturnType_fnPtr(method);
	if (returnType == NULL) {
		assert(dvmCheckException_fnPtr(self));
		goto bail;
	}
	LOGD("dalvik_dispatcher start call->");

	if (!dvmIsStaticMethod(meth)) {
		Object* thisObj = (Object*) args[0];
		ClassObject* tmp = thisObj->clazz;
		thisObj->clazz = meth->clazz;
		argArray = boxMethodArgs(meth, args + 1);
		if (dvmCheckException_fnPtr(self))
			goto bail;

		dvmCallMethod_fnPtr(self, (Method*) jInvokeMethod,
				dvmCreateReflectMethodObject_fnPtr(meth), &result, thisObj,
				argArray);

		thisObj->clazz = tmp;
	} else {
		argArray = boxMethodArgs(meth, args);
		if (dvmCheckException_fnPtr(self))
			goto bail;

		dvmCallMethod_fnPtr(self, (Method*) jInvokeMethod,
				dvmCreateReflectMethodObject_fnPtr(meth), &result, NULL,
				argArray);
	}
	if (dvmCheckException_fnPtr(self)) {
		Object* excep = dvmGetException_fnPtr(self);
		jni_env->Throw((jthrowable) excep);
		goto bail;
	}

	if (returnType->primitiveType == PRIM_VOID) {
		LOGD("+++ ignoring return to void");
	} else if (result.l == NULL) {
		if (dvmIsPrimitiveClass(returnType)) {
			jni_env->ThrowNew(NPEClazz, "null result when primitive expected");
			goto bail;
		}
		pResult->l = NULL;
	} else {
		if (!dvmUnboxPrimitive_fnPtr(result.l, returnType, pResult)) {
			char msg[1024] = { 0 };
			snprintf(msg, sizeof(msg) - 1, "%s!=%s\0",
					((Object*) result.l)->clazz->descriptor,
					returnType->descriptor);
			jni_env->ThrowNew(CastEClazz, msg);
			goto bail;
		}
	}

	bail: dvmReleaseTrackedAlloc_fnPtr((Object*) argArray, self);
}
Example #20
0
/*
 * Invoke a method, using the specified arguments and return type, through
 * one of the reflection interfaces.  Could be a virtual or direct method
 * (including constructors).  Used for reflection.
 *
 * Deals with boxing/unboxing primitives and performs widening conversions.
 *
 * "invokeObj" will be null for a static method.
 *
 * If the invocation returns with an exception raised, we have to wrap it.
 */
Object* dvmInvokeMethod(Object* obj, const Method* method,
    ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
    bool noAccessCheck)
{
    ClassObject* clazz;
    Object* retObj = NULL;
    Thread* self = dvmThreadSelf();
    s4* ins;
    int verifyCount, argListLength;
    JValue retval;
    bool needPop = false;

#ifdef WITH_TAINT_TRACKING
    u4 rtaint = TAINT_CLEAR;
    int slot_cnt = 0;
    bool nativeTarget = dvmIsNativeMethod(method);
    /* For simplicity, argument tags for native targets
     * are unioned. This may cause false positives, but
     * it is the easiest way to handle this for now.
     */
    u4 nativeTag = TAINT_CLEAR;
#endif

    /* verify arg count */
    if (argList != NULL)
        argListLength = argList->length;
    else
        argListLength = 0;
    if (argListLength != (int) params->length) {
        LOGI("invoke: expected %d args, received %d args\n",
            params->length, argListLength);
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "wrong number of arguments");
        return NULL;
    }

    clazz = callPrep(self, method, obj, !noAccessCheck);
    if (clazz == NULL)
        return NULL;
    needPop = true;

    /* "ins" for new frame start at frame pointer plus locals */
#ifdef WITH_TAINT_TRACKING
    if (nativeTarget) {
	/* native target, no taint tag interleaving */
	ins = ((s4*)self->curFrame) + (method->registersSize - method->insSize);
    } else {
	/* interpreted target, taint tags are interleaved */
	ins = ((s4*)self->curFrame) + 
	    ((method->registersSize - method->insSize) << 1);
    }
#else
    ins = ((s4*)self->curFrame) + (method->registersSize - method->insSize);
#endif
    verifyCount = 0;

    //LOGD("  FP is %p, INs live at >= %p\n", self->curFrame, ins);

    /* put "this" pointer into in0 if appropriate */
    if (!dvmIsStaticMethod(method)) {
        assert(obj != NULL);
        *ins++ = (s4) obj;
#ifdef WITH_TAINT_TRACKING
	if (!nativeTarget) {
	    *ins++ = TAINT_CLEAR;
	}
	slot_cnt++;
#endif
        verifyCount++;
    }

    /*
     * Copy the args onto the stack.  Primitive types are converted when
     * necessary, and object types are verified.
     */
    DataObject** args;
    ClassObject** types;
    int i;

    args = (DataObject**) argList->contents;
    types = (ClassObject**) params->contents;
    for (i = 0; i < argListLength; i++) {
        int width;
#ifdef WITH_TAINT_TRACKING
	int tag = dvmGetPrimitiveTaint(*args, *types);
#endif
        width = dvmConvertArgument(*args++, *types++, ins);
        if (width < 0) {
            if (*(args-1) != NULL) {
                LOGV("invoke: type mismatch on arg %d ('%s' '%s')\n",
                    i, (*(args-1))->obj.clazz->descriptor,
                    (*(types-1))->descriptor);
            }
            dvmPopFrame(self);      // throw wants to pull PC out of stack
            needPop = false;
            dvmThrowException("Ljava/lang/IllegalArgumentException;",
                "argument type mismatch");
            goto bail;
        }

#ifdef WITH_TAINT_TRACKING
	/* dvmConvertArgument() returns -1, 1, or 2 */
	if (nativeTarget) {
	    nativeTag |= tag; /* TODO: is there a better way to do this?*/
	    ins += width;
	} else {
	    if (width == 2) {
		ins[2] = ins[1];
		ins[1] = tag;
		ins[3] = tag;
		ins += 4;
	    } else if (width == 1) {
		ins[1] = tag;
		ins += 2;
	    } else { /* error condition duplicated from above */
		dvmPopFrame(self);
		dvmThrowException("Ljava/lang/IllegalArgumentException;",
		    "argument type mismatch");
		goto bail_popped;
	    }
	}
	slot_cnt += width;
#else
        ins += width;
#endif
        verifyCount += width;
    }

#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++ = nativeTag; /* TODO: better way? */
	    }
	}
    }
#endif

    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;
    }
    //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, &retval, method, self);
        TRACE_METHOD_EXIT(self, method);
#ifdef WITH_TAINT_TRACKING
	rtaint = ((u4*)self->curFrame)[slot_cnt];
#endif
    } else {
#ifdef WITH_TAINT_TRACKING
        dvmInterpret(self, method, &retval, &rtaint);
#else
        dvmInterpret(self, method, &retval);
#endif
    }

    /*
     * Pop the frame immediately.  The "wrap" calls below can cause
     * allocations, and we don't want the GC to walk the now-dead frame.
     */
    dvmPopFrame(self);
    needPop = false;

    /*
     * If an exception is raised, wrap and replace.  This is necessary
     * because the invoked method could have thrown a checked exception
     * that the caller wasn't prepared for.
     *
     * We might be able to do this up in the interpreted code, but that will
     * leave us with a shortened stack trace in the top-level exception.
     */
    if (dvmCheckException(self)) {
        dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
    } else {
        /*
         * If this isn't a void method or constructor, convert the return type
         * to an appropriate object.
         *
         * We don't do this when an exception is raised because the value
         * in "retval" is undefined.
         */
        if (returnType != NULL) {
            retObj = (Object*)dvmWrapPrimitive(retval, returnType);
#ifdef WITH_TAINT_TRACKING
	    dvmSetPrimitiveTaint((DataObject *)retObj, returnType, rtaint);
#endif
            dvmReleaseTrackedAlloc(retObj, NULL);
        }
    }

bail:
    if (needPop) {
        dvmPopFrame(self);
    }
bail_popped:
    return retObj;
}
Example #21
0
/*
 * Invoke a method, using the specified arguments and return type, through
 * one of the reflection interfaces.  Could be a virtual or direct method
 * (including constructors).  Used for reflection.
 *
 * Deals with boxing/unboxing primitives and performs widening conversions.
 *
 * "invokeObj" will be null for a static method.
 *
 * If the invocation returns with an exception raised, we have to wrap it.
 */
Object* dvmInvokeMethod(Object* obj, const Method* method,
    ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
    bool noAccessCheck)
{
    ClassObject* clazz;
    Object* retObj = NULL;
    Thread* self = dvmThreadSelf();
    s4* ins;
    int verifyCount, argListLength;
    JValue retval;

    /* verify arg count */
    if (argList != NULL)
        argListLength = argList->length;
    else
        argListLength = 0;
    if (argListLength != (int) params->length) {
        LOGI("invoke: expected %d args, received %d args\n",
            params->length, argListLength);
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "wrong number of arguments");
        return NULL;
    }

    clazz = callPrep(self, method, obj, !noAccessCheck);
    if (clazz == NULL)
        return NULL;

    /* "ins" for new frame start at frame pointer plus locals */
    ins = ((s4*)self->curFrame) + (method->registersSize - method->insSize);
    verifyCount = 0;

    //LOGD("  FP is %p, INs live at >= %p\n", self->curFrame, ins);

    /* put "this" pointer into in0 if appropriate */
    if (!dvmIsStaticMethod(method)) {
        assert(obj != NULL);
        *ins++ = (s4) obj;
        verifyCount++;
    }

    /*
     * Copy the args onto the stack.  Primitive types are converted when
     * necessary, and object types are verified.
     */
    DataObject** args;
    ClassObject** types;
    int i;

    args = (DataObject**) argList->contents;
    types = (ClassObject**) params->contents;
    for (i = 0; i < argListLength; i++) {
        int width;

        width = dvmConvertArgument(*args++, *types++, ins);
        if (width < 0) {
            if (*(args-1) != NULL) {
                LOGV("invoke: type mismatch on arg %d ('%s' '%s')\n",
                    i, (*(args-1))->obj.clazz->descriptor,
                    (*(types-1))->descriptor);
            }
            dvmPopFrame(self);      // throw wants to pull PC out of stack
            dvmThrowException("Ljava/lang/IllegalArgumentException;",
                "argument type mismatch");
            goto bail_popped;
        }

        ins += width;
        verifyCount += width;
    }

    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;
    }
    //dvmDumpThreadStack(dvmThreadSelf());

    if (dvmIsNativeMethod(method)) {
#ifdef WITH_PROFILER
        TRACE_METHOD_ENTER(self, method);
#endif
        /*
         * Because we leave no space for local variables, "curFrame" points
         * directly at the method arguments.
         */
        (*method->nativeFunc)(self->curFrame, &retval, method, self);
#ifdef WITH_PROFILER
        TRACE_METHOD_EXIT(self, method);
#endif
    } else {
        dvmInterpret(self, method, &retval);
    }

    /*
     * If an exception is raised, wrap and replace.  This is necessary
     * because the invoked method could have thrown a checked exception
     * that the caller wasn't prepared for.
     *
     * We might be able to do this up in the interpreted code, but that will
     * leave us with a shortened stack trace in the top-level exception.
     */
    if (dvmCheckException(self)) {
        dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
    } else {
        /*
         * If this isn't a void method or constructor, convert the return type
         * to an appropriate object.
         *
         * We don't do this when an exception is raised because the value
         * in "retval" is undefined.
         */
        if (returnType != NULL) {
            retObj = (Object*)dvmWrapPrimitive(retval, returnType);
            dvmReleaseTrackedAlloc(retObj, NULL);
        }
    }

bail:
    dvmPopFrame(self);
bail_popped:
    return retObj;
}
Example #22
0
/*
 * Invoke a method, using the specified arguments and return type, through
 * one of the reflection interfaces.  Could be a virtual or direct method
 * (including constructors).  Used for reflection.
 *
 * Deals with boxing/unboxing primitives and performs widening conversions.
 *
 * "invokeObj" will be null for a static method.
 *
 * If the invocation returns with an exception raised, we have to wrap it.
 */
Object* dvmInvokeMethod(Object* obj, const Method* method,
    ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
    bool noAccessCheck)
{

	//salma
//	__android_log_print(ANDROID_LOG_DEBUG, "DVM DEBUG", "dvmInvokeMethod method name = %s\n,clazz name: %s", method->name, method->clazz->descriptor);
	    //end salma


	ClassObject* clazz;
    Object* retObj = NULL;
    Thread* self = dvmThreadSelf();
    s4* ins;
    int verifyCount, argListLength;
    JValue retval;
    bool needPop = false;

    /* verify arg count */
    if (argList != NULL)
        argListLength = argList->length;
    else
        argListLength = 0;
    if (argListLength != (int) params->length) {
        dvmThrowExceptionFmt(gDvm.exIllegalArgumentException,
            "wrong number of arguments; expected %d, got %d",
            params->length, argListLength);
        return NULL;
    }

    clazz = callPrep(self, method, obj, !noAccessCheck);
    if (clazz == NULL)
        return NULL;
    needPop = true;

    /* "ins" for new frame start at frame pointer plus locals */
    ins = ((s4*)self->interpSave.curFrame) +
        (method->registersSize - method->insSize);
    verifyCount = 0;

    //ALOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);

    /* put "this" pointer into in0 if appropriate */
    if (!dvmIsStaticMethod(method)) {
        assert(obj != NULL);
        *ins++ = (s4) obj;
        verifyCount++;
    }

    /*
     * Copy the args onto the stack.  Primitive types are converted when
     * necessary, and object types are verified.
     */
    DataObject** args = (DataObject**)(void*)argList->contents;
    ClassObject** types = (ClassObject**)(void*)params->contents;
    for (int i = 0; i < argListLength; i++) {
        int width = dvmConvertArgument(*args++, *types++, ins);
        if (width < 0) {
            dvmPopFrame(self);      // throw wants to pull PC out of stack
            needPop = false;
            throwArgumentTypeMismatch(i, *(types-1), *(args-1));
            goto bail;
        }

        ins += width;
        verifyCount += width;
    }

#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, &retval,
                              method, self);
        TRACE_METHOD_EXIT(self, method);
    } else {
        dvmInterpret(self, method, &retval);
    }

    /*
     * Pop the frame immediately.  The "wrap" calls below can cause
     * allocations, and we don't want the GC to walk the now-dead frame.
     */
    dvmPopFrame(self);
    needPop = false;

    /*
     * If an exception is raised, wrap and replace.  This is necessary
     * because the invoked method could have thrown a checked exception
     * that the caller wasn't prepared for.
     *
     * We might be able to do this up in the interpreted code, but that will
     * leave us with a shortened stack trace in the top-level exception.
     */
    if (dvmCheckException(self)) {
        dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
    } else {
        /*
         * If this isn't a void method or constructor, convert the return type
         * to an appropriate object.
         *
         * We don't do this when an exception is raised because the value
         * in "retval" is undefined.
         */
        if (returnType != NULL) {
            retObj = (Object*)dvmBoxPrimitive(retval, returnType);
            dvmReleaseTrackedAlloc(retObj, NULL);
        }
    }

bail:
    if (needPop) {
        dvmPopFrame(self);
    }
    return retObj;
}
Example #23
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 #24
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 #25
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);
		}
	}
}