// simplified copy of Method.invokeNative, but calls the original (non-hooked) method and has no access checks // used when a method has been hooked static void de_robv_android_xposed_XposedBridge_invokeOriginalMethodNative(const u4* args, JValue* pResult, const Method* method, ::Thread* self) { Method* meth = (Method*) args[1]; if (meth == NULL) { meth = dvmGetMethodFromReflectObj((Object*) args[0]); if (xposedIsHooked(meth)) { meth = (Method*) meth->insns; } } ArrayObject* params = (ArrayObject*) args[2]; ClassObject* returnType = (ClassObject*) args[3]; Object* thisObject = (Object*) args[4]; // null for static methods ArrayObject* argList = (ArrayObject*) args[5]; // invoke the method pResult->l = dvmInvokeMethod(thisObject, meth, argList, params, returnType, true); return; }
/* * public int constructNative(Object[] args, Class declaringClass, * Class[] parameterTypes, int slot, boolean noAccessCheck) * * We get here through Constructor.newInstance(). The Constructor object * would not be available if the constructor weren't public (per the * definition of Class.getConstructor), so we can skip the method access * check. We can also safely assume the constructor isn't associated * with an interface, array, or primitive class. */ static void Dalvik_java_lang_reflect_Constructor_constructNative( const u4* args, JValue* pResult) { // ignore thisPtr in args[0] ArrayObject* argList = (ArrayObject*) args[1]; ClassObject* declaringClass = (ClassObject*) args[2]; ArrayObject* params = (ArrayObject*) args[3]; int slot = args[4]; bool noAccessCheck = (args[5] != 0); Object* newObj; Method* meth; if (dvmIsAbstractClass(declaringClass)) { dvmThrowInstantiationException(declaringClass, NULL); RETURN_VOID(); } /* initialize the class if it hasn't been already */ if (!dvmIsClassInitialized(declaringClass)) { if (!dvmInitClass(declaringClass)) { ALOGW("Class init failed in Constructor.constructNative (%s)", declaringClass->descriptor); assert(dvmCheckException(dvmThreadSelf())); RETURN_VOID(); } } newObj = dvmAllocObject(declaringClass, ALLOC_DEFAULT); if (newObj == NULL) RETURN_PTR(NULL); meth = dvmSlotToMethod(declaringClass, slot); assert(meth != NULL); (void) dvmInvokeMethod(newObj, meth, argList, params, NULL, noAccessCheck); dvmReleaseTrackedAlloc(newObj, NULL); RETURN_PTR(newObj); }
// simplified copy of Method.invokeNative, but calls the original (non-hooked) method and has no access checks // used when a method has been hooked static jobject miui_dexspy_DexspyInstaller_invokeOriginalMethodNative(JNIEnv* env, jclass clazz, jobject reflectedMethod, jobjectArray params1, jclass returnType1, jobject thisObject1, jobjectArray args1) { // try to find the original method Method* method = (Method*)env->FromReflectedMethod(reflectedMethod); OriginalMethodsIt original = findOriginalMethod(method); if (original != dexspyOriginalMethods.end()) { method = &(*original); } // dereference parameters ::Thread* self = dvmThreadSelf(); Object* thisObject = dvmDecodeIndirectRef(self, thisObject1); ArrayObject* args = (ArrayObject*)dvmDecodeIndirectRef(self, args1); ArrayObject* params = (ArrayObject*)dvmDecodeIndirectRef(self, params1); ClassObject* returnType = (ClassObject*)dvmDecodeIndirectRef(self, returnType1); // invoke the method dvmChangeStatus(self, THREAD_RUNNING); Object* result = dvmInvokeMethod(thisObject, method, args, params, returnType, true); dvmChangeStatus(self, THREAD_NATIVE); return dexspyAddLocalReference(self, result); }
/* * public int constructNative(Object[] args, Class declaringClass, * Class[] parameterTypes, int slot, boolean noAccessCheck) */ static void Dalvik_java_lang_reflect_Constructor_constructNative( const u4* args, JValue* pResult) { // ignore thisPtr in args[0] ArrayObject* argList = (ArrayObject*) args[1]; ClassObject* declaringClass = (ClassObject*) args[2]; ArrayObject* params = (ArrayObject*) args[3]; int slot = args[4]; bool noAccessCheck = (args[5] != 0); Object* newObj; Method* meth; newObj = dvmAllocObject(declaringClass, ALLOC_DEFAULT); if (newObj == NULL) RETURN_PTR(NULL); meth = dvmSlotToMethod(declaringClass, slot); assert(meth != NULL); (void) dvmInvokeMethod(newObj, meth, argList, params, NULL, noAccessCheck); dvmReleaseTrackedAlloc(newObj, NULL); RETURN_PTR(newObj); }
/* * 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(); }