/* * Convert an array of char* into a String[]. * * Returns NULL on failure, with an exception raised. */ static ArrayObject* convertStringArray(char** strings, size_t count) { Thread* self = dvmThreadSelf(); /* * Allocate an array to hold the String objects. */ ClassObject* stringArrayClass = dvmFindArrayClass("[Ljava/lang/String;", NULL); if (stringArrayClass == NULL) { /* shouldn't happen */ LOGE("Unable to find [Ljava/lang/String;\n"); dvmAbort(); } ArrayObject* stringArray = dvmAllocArrayByClass(stringArrayClass, count, ALLOC_DEFAULT); if (stringArray == NULL) { /* probably OOM */ LOGD("Failed allocating array of %d strings\n", count); assert(dvmCheckException(self)); return NULL; } /* * Create the individual String objects and add them to the array. */ size_t i; for (i = 0; i < count; i++) { Object *str = (Object *)dvmCreateStringFromCstr(strings[i]); if (str == NULL) { /* probably OOM; drop out now */ assert(dvmCheckException(self)); dvmReleaseTrackedAlloc((Object*)stringArray, self); return NULL; } dvmSetObjectArrayElement(stringArray, i, str); /* stored in tracked array, okay to release */ dvmReleaseTrackedAlloc(str, self); } dvmReleaseTrackedAlloc((Object*)stringArray, self); return stringArray; }
static bool initClassReference(ClassObject** pClass, const char* name) { ClassObject* result; assert(*pClass == NULL); if (name[0] == '[') { result = dvmFindArrayClass(name, NULL); } else { result = dvmFindSystemClassNoInit(name); } if (result == NULL) { ALOGE("Could not find essential class %s", name); return false; } *pClass = result; return true; }
/* * Find the named class object. We have to trim "*pSignature" down to just * the first token, do the lookup, and then restore anything important * that we've stomped on. * * "pSig" will be advanced to the start of the next token. */ static ClassObject* convertSignaturePartToClass(char** pSignature, const ClassObject* defClass) { ClassObject* clazz = NULL; char* signature = *pSignature; if (*signature == '[') { /* looks like "[[[Landroid/debug/Stuff;"; we want the whole thing */ char savedChar; while (*++signature == '[') ; if (*signature == 'L') { while (*++signature != ';') ; } /* advance past ';', and stomp on whatever comes next */ savedChar = *++signature; *signature = '\0'; clazz = dvmFindArrayClass(*pSignature, defClass->classLoader); *signature = savedChar; } else if (*signature == 'L') { /* looks like 'Landroid/debug/Stuff;"; we want the whole thing */ char savedChar; while (*++signature != ';') ; savedChar = *++signature; *signature = '\0'; clazz = dvmFindClassNoInit(*pSignature, defClass->classLoader); *signature = savedChar; } else { clazz = dvmFindPrimitiveClass(*signature++); } if (clazz == NULL) { ALOGW("Unable to match class for part: '%s'", *pSignature); } *pSignature = signature; return clazz; }
static jboolean de_robv_android_xposed_XposedBridge_initNative(JNIEnv* env, jclass clazz) { if (!keepLoadingXposed) { ALOGE("Not initializing Xposed because of previous errors\n"); return false; } ::Thread* self = dvmThreadSelf(); xposedHandleHookedMethod = (Method*) env->GetStaticMethodID(xposedClass, "handleHookedMethod", "(Ljava/lang/reflect/Member;ILjava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); if (xposedHandleHookedMethod == NULL) { ALOGE( "ERROR: could not find method %s.handleHookedMethod(Member, int, Object, Object, Object[])\n", XPOSED_CLASS); dvmLogExceptionStackTrace(); env->ExceptionClear(); keepLoadingXposed = false; return false; } Method* xposedInvokeOriginalMethodNative = (Method*) env->GetStaticMethodID(xposedClass, "invokeOriginalMethodNative", "(Ljava/lang/reflect/Member;I[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); if (xposedInvokeOriginalMethodNative == NULL) { ALOGE( "ERROR: could not find method %s.invokeOriginalMethodNative(Member, int, Class[], Class, Object, Object[])\n", XPOSED_CLASS); dvmLogExceptionStackTrace(); env->ExceptionClear(); keepLoadingXposed = false; return false; } dvmSetNativeFunc(xposedInvokeOriginalMethodNative, de_robv_android_xposed_XposedBridge_invokeOriginalMethodNative, NULL); objectArrayClass = dvmFindArrayClass("[Ljava/lang/Object;", NULL); if (objectArrayClass == NULL) { ALOGE("Error while loading Object[] class"); dvmLogExceptionStackTrace(); env->ExceptionClear(); keepLoadingXposed = false; return false; } //It's not found here? xresourcesClass = env->FindClass(XRESOURCES_CLASS); xresourcesClass = reinterpret_cast<jclass>(env->NewGlobalRef( xresourcesClass)); if (xresourcesClass == NULL) { ALOGE("Error while loading XResources class '%s':\n", XRESOURCES_CLASS); dvmLogExceptionStackTrace(); env->ExceptionClear(); keepLoadingXposed = false; return false; } if (register_android_content_res_XResources(env) != JNI_OK) { ALOGE("Could not register natives for '%s'\n", XRESOURCES_CLASS); return false; } xresourcesTranslateResId = env->GetStaticMethodID(xresourcesClass, "translateResId", "(ILandroid/content/res/XResources;Landroid/content/res/Resources;)I"); if (xresourcesTranslateResId == NULL) { ALOGE( "ERROR: could not find method %s.translateResId(int, Resources, Resources)\n", XRESOURCES_CLASS); dvmLogExceptionStackTrace(); env->ExceptionClear(); keepLoadingXposed = false; return false; } xresourcesTranslateAttrId = env->GetStaticMethodID(xresourcesClass, "translateAttrId", "(Ljava/lang/String;Landroid/content/res/XResources;)I"); if (xresourcesTranslateAttrId == NULL) { ALOGE( "ERROR: could not find method %s.findAttrId(String, Resources, Resources)\n", XRESOURCES_CLASS); dvmLogExceptionStackTrace(); env->ExceptionClear(); keepLoadingXposed = false; return false; } return true; }
/* * Cache pointers to some of the exception classes we use locally. * * Note this is NOT called during dexopt optimization. Some of the fields * are initialized by the verifier (dvmVerifyCodeFlow). */ bool dvmExceptionStartup(void) { gDvm.classJavaLangThrowable = dvmFindSystemClassNoInit("Ljava/lang/Throwable;"); gDvm.classJavaLangRuntimeException = dvmFindSystemClassNoInit("Ljava/lang/RuntimeException;"); gDvm.classJavaLangStackOverflowError = dvmFindSystemClassNoInit("Ljava/lang/StackOverflowError;"); gDvm.classJavaLangError = dvmFindSystemClassNoInit("Ljava/lang/Error;"); gDvm.classJavaLangStackTraceElement = dvmFindSystemClassNoInit("Ljava/lang/StackTraceElement;"); gDvm.classJavaLangStackTraceElementArray = dvmFindArrayClass("[Ljava/lang/StackTraceElement;", NULL); if (gDvm.classJavaLangThrowable == NULL || gDvm.classJavaLangStackTraceElement == NULL || gDvm.classJavaLangStackTraceElementArray == NULL) { LOGE("Could not find one or more essential exception classes\n"); return false; } /* * Find the constructor. Note that, unlike other saved method lookups, * we're using a Method* instead of a vtable offset. This is because * constructors don't have vtable offsets. (Also, since we're creating * the object in question, it's impossible for anyone to sub-class it.) */ Method* meth; meth = dvmFindDirectMethodByDescriptor(gDvm.classJavaLangStackTraceElement, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V"); if (meth == NULL) { LOGE("Unable to find constructor for StackTraceElement\n"); return false; } gDvm.methJavaLangStackTraceElement_init = meth; /* grab an offset for the stackData field */ gDvm.offJavaLangThrowable_stackState = dvmFindFieldOffset(gDvm.classJavaLangThrowable, "stackState", "Ljava/lang/Object;"); if (gDvm.offJavaLangThrowable_stackState < 0) { LOGE("Unable to find Throwable.stackState\n"); return false; } /* and one for the message field, in case we want to show it */ gDvm.offJavaLangThrowable_message = dvmFindFieldOffset(gDvm.classJavaLangThrowable, "detailMessage", "Ljava/lang/String;"); if (gDvm.offJavaLangThrowable_message < 0) { LOGE("Unable to find Throwable.detailMessage\n"); return false; } /* and one for the cause field, just 'cause */ gDvm.offJavaLangThrowable_cause = dvmFindFieldOffset(gDvm.classJavaLangThrowable, "cause", "Ljava/lang/Throwable;"); if (gDvm.offJavaLangThrowable_cause < 0) { LOGE("Unable to find Throwable.cause\n"); return false; } return true; }