diff --git a/edxp-core/src/main/cpp/main/include/art/runtime/art_method.h b/edxp-core/src/main/cpp/main/include/art/runtime/art_method.h index d91106bf..3389e8cb 100644 --- a/edxp-core/src/main/cpp/main/include/art/runtime/art_method.h +++ b/edxp-core/src/main/cpp/main/include/art/runtime/art_method.h @@ -9,21 +9,35 @@ #include namespace art { + namespace art_method { - class ArtMethod : public edxp::HookedObject { - - private: inline static size_t oat_header_length; inline static int32_t oat_header_code_length_offset; + + CREATE_FUNC_SYMBOL_ENTRY(std::string, PrettyMethod, void *thiz, bool with_signature) { + if (UNLIKELY(thiz == nullptr)) + return "null"; + if (LIKELY(PrettyMethodSym)) + return PrettyMethodSym(thiz, with_signature); + else return "null sym"; + } + + inline static std::string PrettyMethod(void *thiz) { + return PrettyMethod(thiz, true); + } + CREATE_HOOK_STUB_ENTRIES(void *, GetOatQuickMethodHeader, void *thiz, uintptr_t pc) { - // LOGD("GetOatQuickMethodHeader called, thiz=%p", thiz); // This is a partial copy from AOSP. We only touch them if they are hooked. - if (LIKELY(edxp::isHooked(thiz))) { - uintptr_t original_ep = reinterpret_cast(getOriginalEntryPointFromTargetMethod(thiz)); - if(original_ep) { - char* code_length_loc = reinterpret_cast(original_ep) + oat_header_code_length_offset; - uint32_t code_length = *reinterpret_cast(code_length_loc) & ~0x80000000; - LOGD("GetOatQuickMethodHeader: isHooked=true, original_ep=0x%x, code_length=0x%x, pc=0x%x", original_ep, code_length, pc); + if (UNLIKELY(edxp::isHooked(thiz))) { + uintptr_t original_ep = reinterpret_cast(getOriginalEntryPointFromTargetMethod( + thiz)); + if (original_ep) { + char *code_length_loc = + reinterpret_cast(original_ep) + oat_header_code_length_offset; + uint32_t code_length = + *reinterpret_cast(code_length_loc) & ~0x80000000; + LOGD("GetOatQuickMethodHeader: ArtMethod=%p (%s), isHooked=true, original_ep=0x%x, code_length=0x%x, pc=0x%x", + thiz, PrettyMethod(thiz).c_str(), original_ep, code_length, pc); if (original_ep <= pc && pc <= original_ep + code_length) return reinterpret_cast(original_ep - oat_header_length); // If PC is not in range, we mark it as not found. @@ -36,28 +50,38 @@ namespace art { return GetOatQuickMethodHeaderBackup(thiz, pc); } - public: - // @ApiSensitive(Level.MIDDLE) static void Setup(void *handle, HookFunType hook_func) { LOGD("Classlinker hook setup, handle=%p", handle); int api_level = edxp::GetAndroidApiLevel(); switch (api_level) { case __ANDROID_API_O__: + [[fallthrough]]; case __ANDROID_API_O_MR1__: + [[fallthrough]]; case __ANDROID_API_P__: oat_header_length = 24; oat_header_code_length_offset = -4; break; default: - LOGW("No valid offset in SDK %d for oatHeaderLen, using offset from Android R", api_level); + LOGW("No valid offset in SDK %d for oatHeaderLen, using offset from Android R", + api_level); + [[fallthrough]]; case __ANDROID_API_Q__: + [[fallthrough]]; case __ANDROID_API_R__: oat_header_length = 8; oat_header_code_length_offset = -4; break; } - HOOK_FUNC(GetOatQuickMethodHeader, "_ZN3art9ArtMethod23GetOatQuickMethodHeaderEj"); + if constexpr (edxp::is64) { + HOOK_FUNC(GetOatQuickMethodHeader, "_ZN3art9ArtMethod23GetOatQuickMethodHeaderEm"); + } else { + HOOK_FUNC(GetOatQuickMethodHeader, "_ZN3art9ArtMethod23GetOatQuickMethodHeaderEj"); + } + + RETRIEVE_FUNC_SYMBOL(PrettyMethod, + "_ZN3art9ArtMethod12PrettyMethodEb"); } - }; + } } #endif //EDXPOSED_ART_METHOD_H diff --git a/edxp-core/src/main/cpp/main/include/art/runtime/class_linker.h b/edxp-core/src/main/cpp/main/include/art/runtime/class_linker.h index 39ea2a96..53db6ad2 100644 --- a/edxp-core/src/main/cpp/main/include/art/runtime/class_linker.h +++ b/edxp-core/src/main/cpp/main/include/art/runtime/class_linker.h @@ -35,13 +35,10 @@ namespace art { } CREATE_HOOK_STUB_ENTRIES(void, FixupStaticTrampolines, void *thiz, void *clazz_ptr) { - art::mirror::Class clazz(clazz_ptr); - std::string storage; - const char *desc = clazz.GetDescriptor(&storage); - bool should_intercept = - edxp::IsClassPending(desc) || std::string(desc).rfind("LEdHooker_") == 0; + bool should_intercept = edxp::IsClassPending(clazz_ptr); FixupStaticTrampolinesBackup(thiz, clazz_ptr); if (UNLIKELY(should_intercept)) { + LOGD("Pending hook for %p (%s)", clazz_ptr, art::mirror::Class(clazz_ptr).GetDescriptor(nullptr)); edxp::Context::GetInstance()->CallOnPostFixupStaticTrampolines(clazz_ptr); } } diff --git a/edxp-core/src/main/cpp/main/include/art/runtime/jit/jit_code_cache.h b/edxp-core/src/main/cpp/main/include/art/runtime/jit/jit_code_cache.h index 6f35e78c..190d69fa 100644 --- a/edxp-core/src/main/cpp/main/include/art/runtime/jit/jit_code_cache.h +++ b/edxp-core/src/main/cpp/main/include/art/runtime/jit/jit_code_cache.h @@ -1,6 +1,7 @@ #pragma once #include "base/object.h" +#include "art/runtime/art_method.h" namespace art { @@ -9,7 +10,8 @@ namespace art { CREATE_HOOK_STUB_ENTRIES(const void*, GetSavedEntryPointOfPreCompiledMethod, void *thiz, void *art_method) { if (UNLIKELY(edxp::isHooked(art_method))) { - LOGD("Found hooked method %p, return entrypoint as jit entrypoint", art_method); + LOGD("Found hooked method %p (%s), return entrypoint as jit entrypoint", art_method, + art::art_method::PrettyMethod(art_method).c_str()); return getEntryPoint(art_method); } return GetSavedEntryPointOfPreCompiledMethodBackup(thiz, art_method); @@ -25,7 +27,7 @@ namespace art { HOOK_FUNC(GetSavedEntryPointOfPreCompiledMethod, "_ZN3art3jit12JitCodeCache37GetSavedEntryPointOfPreCompiledMethodEPNS_9ArtMethodE"); } - }; + } } diff --git a/edxp-core/src/main/cpp/main/include/art/runtime/mirror/class.h b/edxp-core/src/main/cpp/main/include/art/runtime/mirror/class.h index 55d05dae..0b3061fb 100644 --- a/edxp-core/src/main/cpp/main/include/art/runtime/mirror/class.h +++ b/edxp-core/src/main/cpp/main/include/art/runtime/mirror/class.h @@ -64,7 +64,12 @@ namespace art { const char *GetDescriptor(std::string *storage) { if (thiz_ && GetDescriptorSym) { - return GetDescriptor(thiz_, storage); + if (storage == nullptr) { + std::string str; + return GetDescriptor(thiz_, &str); + } else { + return GetDescriptor(thiz_, storage); + } } return ""; } diff --git a/edxp-core/src/main/cpp/main/include/art/runtime/thread.h b/edxp-core/src/main/cpp/main/include/art/runtime/thread.h index 136914f6..07931338 100644 --- a/edxp-core/src/main/cpp/main/include/art/runtime/thread.h +++ b/edxp-core/src/main/cpp/main/include/art/runtime/thread.h @@ -5,10 +5,29 @@ namespace art { -class Thread : public edxp::HookedObject { + class Thread : public edxp::HookedObject { + + CREATE_FUNC_SYMBOL_ENTRY(void *, DecodeJObject, void *thiz, + jobject obj) { + if (DecodeJObjectSym) + return DecodeJObjectSym(thiz, obj); + else + return nullptr; + } public: Thread(void *thiz) : HookedObject(thiz) {} + static void Setup(void *handle, HookFunType hook_func) { + RETRIEVE_FUNC_SYMBOL(DecodeJObject, + "_ZNK3art6Thread13DecodeJObjectEP8_jobject"); + } + + void *DecodeJObject(jobject obj) { + if (thiz_ && DecodeJObjectSym) { + return DecodeJObject(thiz_, obj); + } + return nullptr; + } }; } diff --git a/edxp-core/src/main/cpp/main/src/jni/edxp_pending_hooks.cpp b/edxp-core/src/main/cpp/main/src/jni/edxp_pending_hooks.cpp index 8e256cd1..2859ca38 100644 --- a/edxp-core/src/main/cpp/main/src/jni/edxp_pending_hooks.cpp +++ b/edxp-core/src/main/cpp/main/src/jni/edxp_pending_hooks.cpp @@ -1,40 +1,44 @@ #include -#include #include +#include #include "HookMain.h" #include "jni.h" #include "native_util.h" #include "edxp_pending_hooks.h" +#include "art/runtime/thread.h" +#include "art/runtime/mirror/class.h" namespace edxp { - static std::set class_descs_; + static std::unordered_set pending_classes_; - static std::set hooked_methods_; + static std::unordered_set hooked_methods_; - bool IsClassPending(const char *class_desc) { - return class_descs_.find(class_desc) != class_descs_.end(); + bool IsClassPending(void *clazz) { + return pending_classes_.count(clazz); } - static void PendingHooks_recordPendingMethodNative(JNI_START, jstring class_desc) { - const char *class_desc_chars = env->GetStringUTFChars(class_desc, JNI_FALSE); - class_descs_.insert(class_desc_chars); + static void PendingHooks_recordPendingMethodNative(JNI_START, jlong thread, jclass class_ref) { + art::Thread current_thread(reinterpret_cast(thread)); + auto *class_ptr = current_thread.DecodeJObject(class_ref); + LOGD("record pending: %p (%s)", class_ptr, art::mirror::Class(class_ptr).GetDescriptor(nullptr)); + pending_classes_.insert(class_ptr); } static JNINativeMethod gMethods[] = { - NATIVE_METHOD(PendingHooks, recordPendingMethodNative, "(Ljava/lang/String;)V"), + NATIVE_METHOD(PendingHooks, recordPendingMethodNative, "(JLjava/lang/Class;)V"), }; void RegisterPendingHooks(JNIEnv *env) { REGISTER_EDXP_NATIVE_METHODS("de.robv.android.xposed.PendingHooks"); } - bool isHooked(void* art_method) { + bool isHooked(void *art_method) { return hooked_methods_.count(art_method); } - void recordHooked(void * art_method) { + void recordHooked(void *art_method) { hooked_methods_.insert(art_method); } diff --git a/edxp-core/src/main/cpp/main/src/jni/edxp_pending_hooks.h b/edxp-core/src/main/cpp/main/src/jni/edxp_pending_hooks.h index b952a2c5..81420577 100644 --- a/edxp-core/src/main/cpp/main/src/jni/edxp_pending_hooks.h +++ b/edxp-core/src/main/cpp/main/src/jni/edxp_pending_hooks.h @@ -5,7 +5,7 @@ namespace edxp { - bool IsClassPending(const char *); + bool IsClassPending(void *); void RegisterPendingHooks(JNIEnv *); diff --git a/edxp-core/src/main/cpp/main/src/native_hook.cpp b/edxp-core/src/main/cpp/main/src/native_hook.cpp index 9c42a3cb..3d37cc8a 100644 --- a/edxp-core/src/main/cpp/main/src/native_hook.cpp +++ b/edxp-core/src/main/cpp/main/src/native_hook.cpp @@ -19,6 +19,7 @@ #include "art/runtime/hidden_api.h" #include "art/runtime/oat_file_manager.h" #include "art/runtime/jit/jit_code_cache.h" +#include "art/runtime/art_method.h" std::vector linker_get_solist(); // Dobby but not in .h @@ -76,7 +77,8 @@ namespace edxp { art::hidden_api::DisableHiddenApi(art_handle, hook_func); art::Runtime::Setup(art_handle, hook_func); art::gc::Heap::Setup(art_handle, hook_func); - art::ArtMethod::Setup(art_handle, hook_func); + art::art_method::Setup(art_handle, hook_func); + art::Thread::Setup(art_handle, hook_func); art::ClassLinker::Setup(art_handle, hook_func); art::mirror::Class::Setup(art_handle, hook_func); art::JNIEnvExt::Setup(art_handle, hook_func); diff --git a/edxp-core/template_override/post-fs-data.sh b/edxp-core/template_override/post-fs-data.sh index 607c539a..76c8f8f5 100644 --- a/edxp-core/template_override/post-fs-data.sh +++ b/edxp-core/template_override/post-fs-data.sh @@ -157,7 +157,7 @@ fi [[ -f "${MODDIR}/sepolicy.rule" ]] || livePatch # start_verbose_log_catcher -start_log_cather all "EdXposed:V XSharedPreferences:V EdXposed-Bridge:V EdXposedManager:V XposedInstaller:V" true ${LOG_VERBOSE} +start_log_cather all "EdXposed:V XSharedPreferences:V EdXposed-Bridge:V EdXposedManager:V XposedInstaller:V *:F" true ${LOG_VERBOSE} # start_bridge_log_catcher start_log_cather error "XSharedPreferences:V EdXposed-Bridge:V" true true diff --git a/xposed-bridge/src/main/java/de/robv/android/xposed/PendingHooks.java b/xposed-bridge/src/main/java/de/robv/android/xposed/PendingHooks.java index 20999bf7..fbd81ce4 100644 --- a/xposed-bridge/src/main/java/de/robv/android/xposed/PendingHooks.java +++ b/xposed-bridge/src/main/java/de/robv/android/xposed/PendingHooks.java @@ -1,48 +1,52 @@ package de.robv.android.xposed; import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal; +import com.jaredrummler.apkparser.utils.Utils; import java.lang.reflect.Member; import java.lang.reflect.Modifier; import java.util.HashSet; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; import static de.robv.android.xposed.XposedBridge.hookMethodNative; +import static de.robv.android.xposed.XposedBridge.log; public final class PendingHooks { // GuardedBy("PendingHooks.class") - private static final ConcurrentHashMap - sPendingHookMethods = new ConcurrentHashMap<>(); - // GuardedBy("PendingHooks.class") - private static final HashSet sNonNativeMethods = new HashSet<>(); + private static final ConcurrentHashMap, ConcurrentHashMap> + sPendingHooks = new ConcurrentHashMap<>(); - public synchronized static void hookPendingMethod(Class clazz) { - for (Member member : sPendingHookMethods.keySet()) { - if (member.getDeclaringClass().equals(clazz)) { - hookMethodNative(member, clazz, 0, sPendingHookMethods.get(member)); + public synchronized static void hookPendingMethod(Class clazz) { + if (sPendingHooks.containsKey(clazz)) { + for (Map.Entry hook : sPendingHooks.get(clazz).entrySet()) { + hookMethodNative(hook.getKey(), clazz, 0, hook.getValue()); } } } public synchronized static void recordPendingMethod(Member hookMethod, XposedBridge.AdditionalHookInfo additionalInfo) { - if (!Modifier.isNative(hookMethod.getModifiers())) { - // record non-native methods for later native flag temporary removing - sNonNativeMethods.add(hookMethod); - } - sPendingHookMethods.put(hookMethod, additionalInfo); - recordPendingMethodNative("L" + - hookMethod.getDeclaringClass().getName().replace(".", "/") + ";"); + ConcurrentHashMap pending = + sPendingHooks.computeIfAbsent(hookMethod.getDeclaringClass(), + new Function, ConcurrentHashMap>() { + @Override + public ConcurrentHashMap apply(Class aClass) { + return new ConcurrentHashMap<>(); + } + }); + + pending.put(hookMethod, additionalInfo); + Thread currentThread = Thread.currentThread(); + long nativePeer = XposedHelpers.getLongField(currentThread, "nativePeer"); + recordPendingMethodNative(nativePeer, hookMethod.getDeclaringClass()); } public synchronized void cleanUp() { - sPendingHookMethods.clear(); - // sNonNativeMethods should be cleared very carefully because their - // pre-set native flag have to be removed if its hooking is cancelled - // before its class is initialized -// sNonNativeMethods.clear(); + sPendingHooks.clear(); } - private static native void recordPendingMethodNative(String classDesc); + private static native void recordPendingMethodNative(long thread, Class clazz); }