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; } xposedHandleHookedMethod = env->GetStaticMethodID(xposedClass, "handleHookedMethod", "(Ljava/lang/reflect/Member;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); if (xposedHandleHookedMethod == NULL) { ALOGE("ERROR: could not find method %s.handleHookedMethod(Method, Object, Object[])\n", XPOSED_CLASS); dvmLogExceptionStackTrace(); env->ExceptionClear(); keepLoadingXposed = false; return false; } 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; } 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; }
bool dexspyOnVmCreated(JNIEnv* env, const char* className) { if (!keepLoadingDexspy) return false; startClassName = className; /* The following codes is commented purpose through CTS and avoid to access private fields.. ** // disable some access checks ** char asmReturnTrue[] = { 0x01, 0x20, 0x70, 0x47 }; ** replaceAsm((void*) &dvmCheckClassAccess, asmReturnTrue, sizeof(asmReturnTrue)); ** replaceAsm((void*) &dvmCheckFieldAccess, asmReturnTrue, sizeof(asmReturnTrue)); ** replaceAsm((void*) &dvmInSamePackage, asmReturnTrue, sizeof(asmReturnTrue)); ** if (access(DEXSPY_DIR "do_not_hook_dvmCheckMethodAccess", F_OK) != 0) ** replaceAsm((void*) &dvmCheckMethodAccess, asmReturnTrue, sizeof(asmReturnTrue)); */ dexspyClass = env->FindClass(DEXSPY_CLASS); dexspyClass = reinterpret_cast<jclass>(env->NewGlobalRef(dexspyClass)); if (dexspyClass == NULL) { ALOGE("Error while loading Dexspy class '%s':\n", DEXSPY_CLASS); dvmLogExceptionStackTrace(); env->ExceptionClear(); return false; } ALOGI("Found Dexspy class '%s', now initializing\n", DEXSPY_CLASS); register_miui_dexspy_DexspyInstaller(env); return true; }
/* * public native int preloadClasses() */ static void Dalvik_dalvik_system_VMRuntime_preloadClasses(const u4* args, JValue* pResult) { ClassObject* caller = dvmGetCallerClass(dvmThreadSelf()->curFrame); Object* loader; int count = 0; unsigned int index; UNUSED_PARAMETER(args); if (caller == NULL) RETURN_INT(0); loader = (Object*)caller->classLoader; for (index = 0; index < sizeof(preloadClassesTable)/sizeof(char*); index ++) { ClassObject* clazz = dvmFindClassByCstrName(preloadClassesTable[index], loader); if (clazz == NULL) { dvmLogExceptionStackTrace(); dvmClearException(dvmThreadSelf()); continue; } count ++; } RETURN_INT(count); }
bool xposedOnVmCreated(JNIEnv* env, const char* className) { if (!keepLoadingXposed) return false; startClassName = className; xposedInitMemberOffsets(); // disable some access checks patchReturnTrue((void*) &dvmCheckClassAccess); patchReturnTrue((void*) &dvmCheckFieldAccess); patchReturnTrue((void*) &dvmInSamePackage); if (access(XPOSED_DIR "do_not_hook_dvmCheckMethodAccess", F_OK) != 0) patchReturnTrue((void*) &dvmCheckMethodAccess); 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); register_de_robv_android_xposed_XposedBridge(env); register_android_content_res_XResources(env); return true; }
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; }
static void callMethod(Thread *self, Object *obj, Method *method) { JValue unused; /* Keep track of the method we're about to call and * the current time so that other threads can detect * when this thread wedges and provide useful information. */ gDvm.gcHeap->heapWorkerInterpStartTime = dvmGetRelativeTimeUsec(); gDvm.gcHeap->heapWorkerInterpCpuStartTime = dvmGetThreadCpuTimeUsec(); gDvm.gcHeap->heapWorkerCurrentMethod = method; gDvm.gcHeap->heapWorkerCurrentObject = obj; /* Call the method. * * Don't hold the lock when executing interpreted * code. It may suspend, and the GC needs to grab * heapWorkerLock. */ dvmUnlockMutex(&gDvm.heapWorkerLock); if (false) { /* Log entry/exit; this will likely flood the log enough to * cause "logcat" to drop entries. */ char tmpTag[16]; sprintf(tmpTag, "HW%d", self->systemTid); LOG(LOG_DEBUG, tmpTag, "Call %s\n", method->clazz->descriptor); dvmCallMethod(self, method, obj, &unused); LOG(LOG_DEBUG, tmpTag, " done\n"); } else { dvmCallMethod(self, method, obj, &unused); } /* * Reacquire the heap worker lock in a suspend-friendly way. */ lockMutex(&gDvm.heapWorkerLock); gDvm.gcHeap->heapWorkerCurrentObject = NULL; gDvm.gcHeap->heapWorkerCurrentMethod = NULL; gDvm.gcHeap->heapWorkerInterpStartTime = 0LL; /* Exceptions thrown during these calls interrupt * the method, but are otherwise ignored. */ if (dvmCheckException(self)) { #if DVM_SHOW_EXCEPTION >= 1 LOGI("Uncaught exception thrown by finalizer (will be discarded):\n"); dvmLogExceptionStackTrace(); #endif dvmClearException(self); } }
static jboolean miui_dexspy_DexspyInstaller_initNative(JNIEnv* env, jclass clazz) { if (!keepLoadingDexspy) { ALOGE("Not initializing Dexspy because of previous errors\n"); return false; } dexspyHandleHookedMethod = env->GetStaticMethodID(dexspyClass, "handleHookedMethod", "(Ljava/lang/reflect/Member;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); if (dexspyHandleHookedMethod == NULL) { ALOGE("ERROR: could not find method %s.handleHookedMethod(Method, Object, Object[])\n", DEXSPY_CLASS); dvmLogExceptionStackTrace(); env->ExceptionClear(); keepLoadingDexspy = false; return false; } return true; }
bool xposedOnVmCreated(JNIEnv* env, const char* className) { startClassName = className; keepLoadingXposed = keepLoadingXposed && xposedInitMemberOffsets(env); if (!keepLoadingXposed) return false; // disable some access checks patchReturnTrue((uintptr_t) & dvmCheckClassAccess); patchReturnTrue((uintptr_t) & dvmCheckFieldAccess); patchReturnTrue((uintptr_t) & dvmInSamePackage); if (access(XPOSED_DIR "conf/do_not_hook_dvmCheckMethodAccess", F_OK) != 0) patchReturnTrue((uintptr_t) & dvmCheckMethodAccess); jclass miuiResourcesClass = env->FindClass(MIUI_RESOURCES_CLASS); if (miuiResourcesClass != NULL) { ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef( dvmThreadSelf(), miuiResourcesClass); if (dvmIsFinalClass(clazz)) { ALOGD("Removing final flag for class '%s'", MIUI_RESOURCES_CLASS); clazz->accessFlags &= ~ACC_FINAL; } } env->ExceptionClear(); xposedClass = env->FindClass(XPOSED_CLASS); xposedClass = reinterpret_cast<jclass>(env->NewGlobalRef(xposedClass)); if (xposedClass == NULL) { ALOGE("Error while loading Xposed class '%s':\n", XPOSED_CLASS); dvmLogExceptionStackTrace(); env->ExceptionClear(); return false; } ALOGI("Found Xposed class '%s', now initializing\n", XPOSED_CLASS); if (register_de_robv_android_xposed_XposedBridge(env) != JNI_OK) { ALOGE("Could not register natives for '%s'\n", XPOSED_CLASS); return false; } return true; }
static bool xposedInitMemberOffsets(JNIEnv* env) { PTR_gDvmJit = dlsym(RTLD_DEFAULT, "gDvmJit"); if (PTR_gDvmJit == NULL) { offsetMode = MEMBER_OFFSET_MODE_NO_JIT; } else { offsetMode = MEMBER_OFFSET_MODE_WITH_JIT; } ALOGD("Using structure member offsets for mode %s", xposedOffsetModesDesc[offsetMode]); MEMBER_OFFSET_COPY(DvmJitGlobals, codeCacheFull); int overrideCodeCacheFull = xposedReadIntConfig(XPOSED_OVERRIDE_JIT_RESET_OFFSET, -1); if (overrideCodeCacheFull > 0 && overrideCodeCacheFull < 0x400) { ALOGI("Offset for DvmJitGlobals.codeCacheFull is overridden, new value is 0x%x", overrideCodeCacheFull); MEMBER_OFFSET_VAR(DvmJitGlobals, codeCacheFull) = overrideCodeCacheFull; } // detect offset of ArrayObject->contents jintArray dummyArray = env->NewIntArray(1); if (dummyArray == NULL) { ALOGE("Could allocate int array for testing"); dvmLogExceptionStackTrace(); env->ExceptionClear(); return false; } jint* dummyArrayElements = env->GetIntArrayElements(dummyArray, NULL); arrayContentsOffset = (size_t)dummyArrayElements - (size_t)dvmDecodeIndirectRef(dvmThreadSelf(), dummyArray); env->ReleaseIntArrayElements(dummyArray,dummyArrayElements, 0); env->DeleteLocalRef(dummyArray); if (arrayContentsOffset < 12 || arrayContentsOffset > 128) { ALOGE("Detected strange offset %d of ArrayObject->contents", arrayContentsOffset); return false; } return true; }
/* * Broadcast an event to all handlers. */ static void broadcast(int event) { ClassObject* ddmServerClass; Method* bcast; ddmServerClass = dvmFindClass("Lorg/apache/harmony/dalvik/ddmc/DdmServer;", NULL); if (ddmServerClass == NULL) { LOGW("Unable to find org.apache.harmony.dalvik.ddmc.DdmServer\n"); goto bail; } bcast = dvmFindDirectMethodByDescriptor(ddmServerClass, "broadcast", "(I)V"); if (bcast == NULL) { LOGW("Unable to find DdmServer.broadcast\n"); goto bail; } Thread* self = dvmThreadSelf(); if (self->status != THREAD_RUNNING) { LOGE("ERROR: DDM broadcast with thread status=%d\n", self->status); /* try anyway? */ } JValue unused; dvmCallMethod(self, bcast, NULL, &unused, event); if (dvmCheckException(self)) { LOGI("Exception thrown by broadcast(%d)\n", event); dvmLogExceptionStackTrace(); dvmClearException(self); goto bail; } bail: ; }
/* * "buf" contains a full JDWP packet, possibly with multiple chunks. We * need to process each, accumulate the replies, and ship the whole thing * back. * * Returns "true" if we have a reply. The reply buffer is newly allocated, * and includes the chunk type/length, followed by the data. * * TODO: we currently assume that the request and reply include a single * chunk. If this becomes inconvenient we will need to adapt. */ bool dvmDdmHandlePacket(const u1* buf, int dataLen, u1** pReplyBuf, int* pReplyLen) { Thread* self = dvmThreadSelf(); const int kChunkHdrLen = 8; ArrayObject* dataArray = NULL; bool result = false; assert(dataLen >= 0); /* * Prep DdmServer. We could throw this in gDvm. */ ClassObject* ddmServerClass; Method* dispatch; ddmServerClass = dvmFindClass("Lorg/apache/harmony/dalvik/ddmc/DdmServer;", NULL); if (ddmServerClass == NULL) { LOGW("Unable to find org.apache.harmony.dalvik.ddmc.DdmServer\n"); goto bail; } dispatch = dvmFindDirectMethodByDescriptor(ddmServerClass, "dispatch", "(I[BII)Lorg/apache/harmony/dalvik/ddmc/Chunk;"); if (dispatch == NULL) { LOGW("Unable to find DdmServer.dispatch\n"); goto bail; } /* * Prep Chunk. */ int chunkTypeOff, chunkDataOff, chunkOffsetOff, chunkLengthOff; ClassObject* chunkClass; chunkClass = dvmFindClass("Lorg/apache/harmony/dalvik/ddmc/Chunk;", NULL); if (chunkClass == NULL) { LOGW("Unable to find org.apache.harmony.dalvik.ddmc.Chunk\n"); goto bail; } chunkTypeOff = dvmFindFieldOffset(chunkClass, "type", "I"); chunkDataOff = dvmFindFieldOffset(chunkClass, "data", "[B"); chunkOffsetOff = dvmFindFieldOffset(chunkClass, "offset", "I"); chunkLengthOff = dvmFindFieldOffset(chunkClass, "length", "I"); if (chunkTypeOff < 0 || chunkDataOff < 0 || chunkOffsetOff < 0 || chunkLengthOff < 0) { LOGW("Unable to find all chunk fields\n"); goto bail; } /* * The chunk handlers are written in the Java programming language, so * we need to convert the buffer to a byte array. */ dataArray = dvmAllocPrimitiveArray('B', dataLen, ALLOC_DEFAULT); if (dataArray == NULL) { LOGW("array alloc failed (%d)\n", dataLen); dvmClearException(self); goto bail; } memcpy(dataArray->contents, buf, dataLen); /* * Run through and find all chunks. [Currently just find the first.] */ unsigned int offset, length, type; type = get4BE((u1*)dataArray->contents + 0); length = get4BE((u1*)dataArray->contents + 4); offset = kChunkHdrLen; if (offset+length > (unsigned int) dataLen) { LOGW("WARNING: bad chunk found (len=%u pktLen=%d)\n", length, dataLen); goto bail; } /* * Call the handler. */ JValue callRes; dvmCallMethod(self, dispatch, NULL, &callRes, type, dataArray, offset, length); if (dvmCheckException(self)) { LOGI("Exception thrown by dispatcher for 0x%08x\n", type); dvmLogExceptionStackTrace(); dvmClearException(self); goto bail; } Object* chunk; ArrayObject* replyData; chunk = (Object*) callRes.l; if (chunk == NULL) goto bail; /* * Pull the pieces out of the chunk. We copy the results into a * newly-allocated buffer that the caller can free. We don't want to * continue using the Chunk object because nothing has a reference to it. * (If we do an alloc in here, we need to dvmAddTrackedAlloc it.) * * We could avoid this by returning type/data/offset/length and having * the caller be aware of the object lifetime issues, but that * integrates the JDWP code more tightly into the VM, and doesn't work * if we have responses for multiple chunks. * * So we're pretty much stuck with copying data around multiple times. */ type = dvmGetFieldInt(chunk, chunkTypeOff); replyData = (ArrayObject*) dvmGetFieldObject(chunk, chunkDataOff); offset = dvmGetFieldInt(chunk, chunkOffsetOff); length = dvmGetFieldInt(chunk, chunkLengthOff); LOGV("DDM reply: type=0x%08x data=%p offset=%d length=%d\n", type, replyData, offset, length); if (length == 0 || replyData == NULL) goto bail; if (offset + length > replyData->length) { LOGW("WARNING: chunk off=%d len=%d exceeds reply array len %d\n", offset, length, replyData->length); goto bail; } u1* reply; reply = (u1*) malloc(length + kChunkHdrLen); if (reply == NULL) { LOGW("malloc %d failed\n", length+kChunkHdrLen); goto bail; } set4BE(reply + 0, type); set4BE(reply + 4, length); memcpy(reply+kChunkHdrLen, (const u1*)replyData->contents + offset, length); *pReplyBuf = reply; *pReplyLen = length + kChunkHdrLen; result = true; LOGV("dvmHandleDdm returning type=%.4s buf=%p len=%d\n", (char*) reply, reply, length); bail: dvmReleaseTrackedAlloc((Object*) dataArray, NULL); return result; }
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; }