Пример #1
0
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;
}
Пример #2
0
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);
}
Пример #4
0
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;
}
Пример #5
0
bool xposedOnVmCreated(JNIEnv* env, const char* className) {
    startClassName = className;

    keepLoadingXposed = keepLoadingXposed && xposedInitMemberOffsets(env);
    if (!keepLoadingXposed)
        return false;

    jclass miuiResourcesClass = env->FindClass(MIUI_RESOURCES_CLASS);
    if (miuiResourcesClass != NULL) {
        ClassObject* clazz = (ClassObject*)dvmDecodeIndirectRef(dvmThreadSelf(), miuiResourcesClass);
        if (dvmIsFinalClass(clazz)) {
            ALOGD("Removing final flag for class '%s'", MIUI_RESOURCES_CLASS);
            clazz->accessFlags &= ~ACC_FINAL;
        }
    }
    env->ExceptionClear();

    jclass xTypedArrayClass = env->FindClass(XTYPEDARRAY_CLASS);
    if (xTypedArrayClass == NULL) {
        ALOGE("Error while loading XTypedArray class '%s':\n", XTYPEDARRAY_CLASS);
        dvmLogExceptionStackTrace();
        env->ExceptionClear();
        return false;
    }
    xposedPrepareSubclassReplacement(xTypedArrayClass);

    xposedClass = env->FindClass(XPOSED_CLASS);
    xposedClass = reinterpret_cast<jclass>(env->NewGlobalRef(xposedClass));
    
    if (xposedClass == NULL) {
        ALOGE("Error while loading Xposed class '%s':\n", XPOSED_CLASS);
        dvmLogExceptionStackTrace();
        env->ExceptionClear();
        return false;
    }
    
    ALOGI("Found Xposed class '%s', now initializing\n", XPOSED_CLASS);
    if (register_de_robv_android_xposed_XposedBridge(env) != JNI_OK) {
        ALOGE("Could not register natives for '%s'\n", XPOSED_CLASS);
        env->ExceptionClear();
        return false;
    }
    return true;
}
Пример #6
0
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);
    }
}
Пример #7
0
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;
}
Пример #8
0
bool xposedOnVmCreated(JNIEnv* env, const char* className) {
	startClassName = className;

	keepLoadingXposed = keepLoadingXposed && xposedInitMemberOffsets(env);
	if (!keepLoadingXposed)
		return false;

	// disable some access checks
	patchReturnTrue((uintptr_t) & dvmCheckClassAccess);
	patchReturnTrue((uintptr_t) & dvmCheckFieldAccess);
	patchReturnTrue((uintptr_t) & dvmInSamePackage);
	if (access(XPOSED_DIR "conf/do_not_hook_dvmCheckMethodAccess", F_OK) != 0)
		patchReturnTrue((uintptr_t) & dvmCheckMethodAccess);

	jclass miuiResourcesClass = env->FindClass(MIUI_RESOURCES_CLASS);
	if (miuiResourcesClass != NULL) {
		ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(
				dvmThreadSelf(), miuiResourcesClass);
		if (dvmIsFinalClass(clazz)) {
			ALOGD("Removing final flag for class '%s'", MIUI_RESOURCES_CLASS);
			clazz->accessFlags &= ~ACC_FINAL;
		}
	}
	env->ExceptionClear();

	xposedClass = env->FindClass(XPOSED_CLASS);
	xposedClass = reinterpret_cast<jclass>(env->NewGlobalRef(xposedClass));

	if (xposedClass == NULL) {
		ALOGE("Error while loading Xposed class '%s':\n", XPOSED_CLASS);
		dvmLogExceptionStackTrace();
		env->ExceptionClear();
		return false;
	}

	ALOGI("Found Xposed class '%s', now initializing\n", XPOSED_CLASS);
	if (register_de_robv_android_xposed_XposedBridge(env) != JNI_OK) {
		ALOGE("Could not register natives for '%s'\n", XPOSED_CLASS);
		return false;
	}

	return true;
}
Пример #9
0
static bool xposedInitMemberOffsets(JNIEnv* env) {
    PTR_gDvmJit = dlsym(RTLD_DEFAULT, "gDvmJit");

    if (PTR_gDvmJit == NULL) {
        offsetMode = MEMBER_OFFSET_MODE_NO_JIT;
    } else {
        offsetMode = MEMBER_OFFSET_MODE_WITH_JIT;
    }
    ALOGD("Using structure member offsets for mode %s", xposedOffsetModesDesc[offsetMode]);

    MEMBER_OFFSET_COPY(DvmJitGlobals, codeCacheFull);

    int overrideCodeCacheFull = xposedReadIntConfig(XPOSED_OVERRIDE_JIT_RESET_OFFSET, -1);
    if (overrideCodeCacheFull > 0 && overrideCodeCacheFull < 0x400) {
        ALOGI("Offset for DvmJitGlobals.codeCacheFull is overridden, new value is 0x%x", overrideCodeCacheFull);
        MEMBER_OFFSET_VAR(DvmJitGlobals, codeCacheFull) = overrideCodeCacheFull;
    }

    // detect offset of ArrayObject->contents
    jintArray dummyArray = env->NewIntArray(1);
    if (dummyArray == NULL) {
        ALOGE("Could allocate int array for testing");
        dvmLogExceptionStackTrace();
        env->ExceptionClear();
        return false;
    }

    jint* dummyArrayElements = env->GetIntArrayElements(dummyArray, NULL);
    arrayContentsOffset = (size_t)dummyArrayElements - (size_t)dvmDecodeIndirectRef(dvmThreadSelf(), dummyArray);
    env->ReleaseIntArrayElements(dummyArray,dummyArrayElements, 0);
    env->DeleteLocalRef(dummyArray);

    if (arrayContentsOffset < 12 || arrayContentsOffset > 128) {
        ALOGE("Detected strange offset %d of ArrayObject->contents", arrayContentsOffset);
        return false;
    }

    return true;
}
Пример #10
0
/*
 * 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:
    ;
}
Пример #11
0
/*
 * "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;
}
Пример #12
0
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;
}