static void de_robv_android_xposed_XposedBridge_hookMethodNative(JNIEnv* env, jclass clazz, jobject declaredClassIndirect, jint slot) { // Usage errors? if (declaredClassIndirect == NULL) { dvmThrowIllegalArgumentException("declaredClass must not be null"); return; } // Find the internal representation of the method ClassObject* declaredClass = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), declaredClassIndirect); Method* method = dvmSlotToMethod(declaredClass, slot); if (method == NULL) { dvmThrowNoSuchMethodError("could not get internal representation for method"); return; } if (findXposedOriginalMethod(method) != xposedOriginalMethods.end()) { // already hooked return; } // Save a copy of the original method xposedOriginalMethods.push_front(*((MethodXposedExt*)method)); // Replace method with our own code SET_METHOD_FLAG(method, ACC_NATIVE); method->nativeFunc = &xposedCallHandler; method->registersSize = method->insSize; method->outsSize = 0; if (PTR_gDvmJit != NULL) { // reset JIT cache MEMBER_VAL(PTR_gDvmJit, DvmJitGlobals, codeCacheFull) = true; } }
static void miui_dexspy_DexspyInstaller_hookMethodNative(JNIEnv* env, jclass clazz, jobject declaredClassIndirect, jint slot) { // Usage errors? if (declaredClassIndirect == NULL) { dvmThrowIllegalArgumentException("declaredClass must not be null"); return; } // Find the internal representation of the method ClassObject* declaredClass = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), declaredClassIndirect); Method* method = dvmSlotToMethod(declaredClass, slot); if (method == NULL) { dvmThrowNoSuchMethodError("could not get internal representation for method"); return; } if (findOriginalMethod(method) != dexspyOriginalMethods.end()) { ALOGD("why this method already hooked: %s:%s(%s)", method->clazz->descriptor, method->name, method->shorty); // already hooked return; } // Save a copy of the original method dexspyOriginalMethods.push_front(*method); // Replace method with our own code SET_METHOD_FLAG(method, ACC_NATIVE); method->nativeFunc = &dexspyCallHandler; method->registersSize = method->insSize; method->outsSize = 0; #ifdef WITH_JIT // reset JIT cache gDvmJit.codeCacheFull = true; #endif }
jlonglong fastiva_Dalvik_dalvik_system_VMRuntime_addressOf(dalvik_system_VMRuntime_p self, java_lang_Object_p arg1) { ArrayObject* array = (ArrayObject*) arg1; #endif if (!dvmIsArray(array)) { dvmThrowIllegalArgumentException(NULL); THROW_V(); } // TODO: we should also check that this is a non-movable array. s8 result = (uintptr_t) array->contents; RETURN_LONG(result); }
static void Dalvik_dalvik_system_VMRuntime_addressOf(const u4* args, JValue* pResult) { ArrayObject* array = (ArrayObject*) args[1]; if (!dvmIsArray(array)) { dvmThrowIllegalArgumentException(NULL); RETURN_VOID(); } // TODO: we should also check that this is a non-movable array. s8 result = (uintptr_t) array->contents; RETURN_LONG(result); }
static void de_robv_android_xposed_XposedBridge_hookMethodNative(JNIEnv* env, jclass clazz, jobject reflectedMethodIndirect, jobject declaredClassIndirect, jint slot, jobject additionalInfoIndirect) { // Usage errors? if (declaredClassIndirect == NULL || reflectedMethodIndirect == NULL) { dvmThrowIllegalArgumentException( "method and declaredClass must not be null"); return; } // Find the internal representation of the method ClassObject* declaredClass = (ClassObject*) dvmDecodeIndirectRef( dvmThreadSelf(), declaredClassIndirect); Method* method = dvmSlotToMethod(declaredClass, slot); if (method == NULL) { dvmThrowNoSuchMethodError( "could not get internal representation for method"); return; } if (xposedIsHooked(method)) { ALOGD("Hook: Ignored! [%s] [%s]\n", declaredClass->descriptor, method->name); // already hooked return; } else { ALOGD("Hook: [%s] [%s]\n", declaredClass->descriptor, method->name); } // Save a copy of the original method and other hook info XposedHookInfo* hookInfo = (XposedHookInfo*) calloc(1, sizeof(XposedHookInfo)); memcpy(hookInfo, method, sizeof(hookInfo->originalMethodStruct)); hookInfo->reflectedMethod = dvmDecodeIndirectRef(dvmThreadSelf(), env->NewGlobalRef(reflectedMethodIndirect)); hookInfo->additionalInfo = dvmDecodeIndirectRef(dvmThreadSelf(), env->NewGlobalRef(additionalInfoIndirect)); // Replace method with our own code SET_METHOD_FLAG(method, ACC_NATIVE); method->nativeFunc = &xposedCallHandler; method->insns = (const u2*) hookInfo; method->registersSize = method->insSize; method->outsSize = 0; if (PTR_gDvmJit != NULL) { // reset JIT cache MEMBER_VAL(PTR_gDvmJit, DvmJitGlobals, codeCacheFull) = true; } }
/* * static void startMethodTracingNative(String traceFileName, * FileDescriptor fd, int bufferSize, int flags) * * Start method trace profiling. * * If both "traceFileName" and "fd" are null, the result will be sent * directly to DDMS. (The non-DDMS versions of the calls are expected * to enforce non-NULL filenames.) */ static void Dalvik_dalvik_system_VMDebug_startMethodTracingNative(const u4* args, JValue* pResult) { StringObject* traceFileStr = (StringObject*) args[0]; Object* traceFd = (Object*) args[1]; int bufferSize = args[2]; int flags = args[3]; if (bufferSize == 0) { // Default to 8MB per the documentation. bufferSize = 8 * 1024 * 1024; } if (bufferSize < 1024) { dvmThrowIllegalArgumentException(NULL); RETURN_VOID(); } char* traceFileName = NULL; if (traceFileStr != NULL) traceFileName = dvmCreateCstrFromString(traceFileStr); int fd = -1; if (traceFd != NULL) { int origFd = getFileDescriptor(traceFd); if (origFd < 0) RETURN_VOID(); fd = dup(origFd); if (fd < 0) { dvmThrowExceptionFmt(gDvm.exRuntimeException, "dup(%d) failed: %s", origFd, strerror(errno)); RETURN_VOID(); } } dvmMethodTraceStart(traceFileName != NULL ? traceFileName : "[DDMS]", fd, bufferSize, flags, (traceFileName == NULL && fd == -1)); free(traceFileName); RETURN_VOID(); }
/* * Wait on a monitor until timeout, interrupt, or notification. Used for * Object.wait() and (somewhat indirectly) Thread.sleep() and Thread.join(). * * If another thread calls Thread.interrupt(), we throw InterruptedException * and return immediately if one of the following are true: * - blocked in wait(), wait(long), or wait(long, int) methods of Object * - blocked in join(), join(long), or join(long, int) methods of Thread * - blocked in sleep(long), or sleep(long, int) methods of Thread * Otherwise, we set the "interrupted" flag. * * Checks to make sure that "nsec" is in the range 0-999999 * (i.e. fractions of a millisecond) and throws the appropriate * exception if it isn't. * * The spec allows "spurious wakeups", and recommends that all code using * Object.wait() do so in a loop. This appears to derive from concerns * about pthread_cond_wait() on multiprocessor systems. Some commentary * on the web casts doubt on whether these can/should occur. * * Since we're allowed to wake up "early", we clamp extremely long durations * to return at the end of the 32-bit time epoch. */ static void waitMonitor(Thread* self, Monitor* mon, s8 msec, s4 nsec, bool interruptShouldThrow) { struct timespec ts; bool wasInterrupted = false; bool timed; int ret; assert(self != NULL); assert(mon != NULL); /* Make sure that we hold the lock. */ if (mon->owner != self) { dvmThrowIllegalMonitorStateException( "object not locked by thread before wait()"); return; } /* * Enforce the timeout range. */ if (msec < 0 || nsec < 0 || nsec > 999999) { dvmThrowIllegalArgumentException("timeout arguments out of range"); return; } /* * Compute absolute wakeup time, if necessary. */ if (msec == 0 && nsec == 0) { timed = false; } else { absoluteTime(msec, nsec, &ts); timed = true; } /* * Add ourselves to the set of threads waiting on this monitor, and * release our hold. We need to let it go even if we're a few levels * deep in a recursive lock, and we need to restore that later. * * We append to the wait set ahead of clearing the count and owner * fields so the subroutine can check that the calling thread owns * the monitor. Aside from that, the order of member updates is * not order sensitive as we hold the pthread mutex. */ waitSetAppend(mon, self); int prevLockCount = mon->lockCount; mon->lockCount = 0; mon->owner = NULL; const Method* savedMethod = mon->ownerMethod; u4 savedPc = mon->ownerPc; mon->ownerMethod = NULL; mon->ownerPc = 0; /* * Update thread status. If the GC wakes up, it'll ignore us, knowing * that we won't touch any references in this state, and we'll check * our suspend mode before we transition out. */ if (timed) dvmChangeStatus(self, THREAD_TIMED_WAIT); else dvmChangeStatus(self, THREAD_WAIT); dvmLockMutex(&self->waitMutex); /* * Set waitMonitor to the monitor object we will be waiting on. * When waitMonitor is non-NULL a notifying or interrupting thread * must signal the thread's waitCond to wake it up. */ assert(self->waitMonitor == NULL); self->waitMonitor = mon; /* * Handle the case where the thread was interrupted before we called * wait(). */ if (self->interrupted) { wasInterrupted = true; self->waitMonitor = NULL; dvmUnlockMutex(&self->waitMutex); goto done; } /* * Release the monitor lock and wait for a notification or * a timeout to occur. */ dvmUnlockMutex(&mon->lock); if (!timed) { ret = pthread_cond_wait(&self->waitCond, &self->waitMutex); assert(ret == 0); } else { #ifdef HAVE_TIMEDWAIT_MONOTONIC ret = pthread_cond_timedwait_monotonic(&self->waitCond, &self->waitMutex, &ts); #else ret = pthread_cond_timedwait(&self->waitCond, &self->waitMutex, &ts); #endif assert(ret == 0 || ret == ETIMEDOUT); } if (self->interrupted) { wasInterrupted = true; } self->interrupted = false; self->waitMonitor = NULL; dvmUnlockMutex(&self->waitMutex); /* Reacquire the monitor lock. */ lockMonitor(self, mon); done: /* * We remove our thread from wait set after restoring the count * and owner fields so the subroutine can check that the calling * thread owns the monitor. Aside from that, the order of member * updates is not order sensitive as we hold the pthread mutex. */ mon->owner = self; mon->lockCount = prevLockCount; mon->ownerMethod = savedMethod; mon->ownerPc = savedPc; waitSetRemove(mon, self); /* set self->status back to THREAD_RUNNING, and self-suspend if needed */ dvmChangeStatus(self, THREAD_RUNNING); if (wasInterrupted) { /* * We were interrupted while waiting, or somebody interrupted an * un-interruptible thread earlier and we're bailing out immediately. * * The doc sayeth: "The interrupted status of the current thread is * cleared when this exception is thrown." */ self->interrupted = false; if (interruptShouldThrow) { dvmThrowInterruptedException(NULL); } } }