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 }
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 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; } }
extern "C" JNIEXPORT void JNICALL Java_com_zhaoxiaodan_hookdemo_Demo1_hook(JNIEnv *env, jobject instance, jobject clazzToHook, jstring methodName_, jstring methodSig_) { const char *methodName = env->GetStringUTFChars(methodName_, 0); const char *methodSig = env->GetStringUTFChars(methodSig_, 0); jmethodID methodIDToHook = env->GetMethodID((jclass) clazzToHook,methodName,methodSig); // 找不到有可能是个static if(nullptr == methodIDToHook){ env->ExceptionClear(); methodIDToHook = env->GetStaticMethodID((jclass) clazzToHook,methodName,methodSig); } if(methodIDToHook != nullptr) { //主要在这里替换 //jmethodID 在dvm里实际上就是个Method 结构体 Method* method = (Method*) methodIDToHook; //看看method的各个属性都是啥: showMethodInfo(method); //设置Method 的 accessFlags 为 枚举型 // ACC_NATIVE 表示 这个method 切换成了一个native 方法 // 这个枚举 在 dalvik/libdex/DexFile.h // 类似: // ACC_PUBLIC = 0x00000001, // class, field, method, ic // ACC_PRIVATE = 0x00000002, // field, method, ic // ACC_PROTECTED = 0x00000004, // field, method, ic SET_METHOD_FLAG(method, ACC_NATIVE); //既然是一个native方法, 那就把 nativeFunc 指针指向我们的hook, 用来替换test的新方法 method->nativeFunc = &newTestMethod; // registersSize是函数栈大小, insSize是参数占用大小 // 如果是native方法, 就没有额外开销了 // 所有开销就是参数占用, 所以把它设置成跟参数占用空间 method->registersSize=method->insSize; //未知 method->outsSize=0; } env->ReleaseStringUTFChars(methodName_, methodName); env->ReleaseStringUTFChars(methodSig_, methodSig); }
bool HookDalvikMethod(jmethodID jmethod){ Method *method = (Method*)jmethod; //关键!!将目标方法修改为native方法 SET_METHOD_FLAG(method, ACC_NATIVE); int argsSize = dvmComputeMethodArgsSize(method); if (!dvmIsStaticMethod(method)) argsSize++; method->registersSize = method->insSize = argsSize; if (dvmIsNativeMethod(method)) { method->nativeFunc = dvmResolveNativeMethod; method->jniArgInfo = computeJniArgInfo(&method->prototype); } }
extern "C" int hook_dvm(JNIEnv *env, struct hook_java_args *args) { jclass clz, tmp; jmethodID jm; bool isStatic = false; struct hook_java_args *ha = NULL; Method *method; int argsSize; if (loadDVM()) { LOGE("hook_dvm: loadDVM() failed"); return -1; } if ((args->prev || args->post) && args->func) { LOGE("hook_dvm: invalid argument"); return -1; } tmp = hsdk_find_clz(env, args->clz); if (tmp == NULL) { LOGE("hook_dvm: class `%s\' not found", args->clz); return -1; } // XXX: find_clz3w // saying given clz is invalid //W/dalvikvm( 8493): Invalid indirect reference 0x41cd9338 in decodeIndirectRef //E/dalvikvm( 8493): VM aborting clz = (jclass) env->NewGlobalRef(tmp); env->DeleteLocalRef(tmp); if (clz == NULL) { LOGE("hook_dvm: unable to ref clz"); return -1; } jm = env->GetMethodID(clz, args->mtd, args->sig); if (jm == NULL) { if (env->ExceptionOccurred()) env->ExceptionClear(); jm = env->GetStaticMethodID(clz, args->mtd, args->sig); if (env->ExceptionOccurred()) env->ExceptionClear(); if (jm == NULL) { LOGE("hook_dvm: method `%s\' with sig `%s\' not found", args->mtd, args->sig); env->DeleteGlobalRef(clz); return -1; } isStatic = true; } // XXX: leak the global ref so GC won't recycle the class then Member will be always valid? env->DeleteGlobalRef(clz); method = (Method *) jm; if ((method->nativeFunc == hsdk_bridge_func) || (method->nativeFunc == dvmCallJNIMethod && method->insns == args->func)) { LOGD("hook_dvm: already hooked"); return 0; } // hook args->old = calloc(1, sizeof(*method)); if (args->old) memcpy(args->old, jm, sizeof(*method)); if (!args->func) { ha = (struct hook_java_args *) calloc(1, sizeof(*ha)); if (!ha) { LOGE("hook_dvm: calloc failed"); if (args->old) { free(args->old); args->old = 0; } return -1; } ha->clz = strdup(args->clz); ha->mtd = strdup(args->mtd); ha->sig = strdup(args->sig); ha->prev = args->prev; ha->post = args->post; } argsSize = dexProtoComputeArgsSize(&method->prototype); if (!isStatic) argsSize += 1; method->registersSize = argsSize; method->insSize = argsSize; method->outsSize = 0; method->insns = NULL; method->jniArgInfo = computeJniArgInfo(&method->prototype); if (!args->func) { method->insns = (const u2*) ha; method->nativeFunc = hsdk_bridge_func; } else { dvmUseJNIBridge(method, args->func); } SET_METHOD_FLAG(method, ACC_NATIVE); if (args->func) { LOGD("hook_dvm: %sL%s;%s->%s => %p", isStatic ? "static " : "", args->clz, args->mtd, args->sig, args->func); } return 0; }