diff --git a/core/src/main/cpp/external/yahfa/src/HookMain.cpp b/core/src/main/cpp/external/yahfa/src/HookMain.cpp index eae67387..6f1a1781 100644 --- a/core/src/main/cpp/external/yahfa/src/HookMain.cpp +++ b/core/src/main/cpp/external/yahfa/src/HookMain.cpp @@ -122,6 +122,7 @@ namespace yahfa { SDKVersion = sdkVersion; jclass classExecutable = env->FindClass("java/lang/reflect/Executable"); fieldArtMethod = env->GetFieldID(classExecutable, "artMethod", "J"); + env->DeleteLocalRef(classExecutable); LOGI("init to SDK %d", sdkVersion); switch (sdkVersion) { case __ANDROID_API_S__: diff --git a/core/src/main/cpp/main/include/base/object.h b/core/src/main/cpp/main/include/base/object.h index 59bea9a7..80ab47e1 100644 --- a/core/src/main/cpp/main/include/base/object.h +++ b/core/src/main/cpp/main/include/base/object.h @@ -25,6 +25,7 @@ #include #include "config.h" #include "native_hook.h" +#include #define _uintval(p) reinterpret_cast(p) #define _ptr(p) reinterpret_cast(p) @@ -140,9 +141,8 @@ namespace lspd { }; template + requires (std::is_same_v || std::is_same_v) inline static auto memfun_cast(Return (*func)(T *, Args...)) { - static_assert(std::is_same_v || std::is_same_v, - "Not viable cast"); union { Return (Class::*f)(Args...); @@ -155,8 +155,7 @@ namespace lspd { return u.f; } - template>> + template T, typename Return, typename... Args> inline auto memfun_cast(Return (*func)(T *, Args...)) { return memfun_cast(func); } @@ -203,7 +202,7 @@ namespace lspd { struct Hooker> { inline static Ret (*backup)(Args...) = nullptr; - inline static constexpr const char sym[sizeof...(cs) + 1] = {cs..., '\0'}; + inline static constexpr const char *sym = tstring::c_str(); }; template @@ -211,10 +210,16 @@ namespace lspd { template struct MemHooker> { inline static MemberFunction backup; - inline static constexpr const char sym[sizeof...(cs) + 1] = {cs..., '\0'}; + inline static constexpr const char *sym = tstring::c_str(); }; template + concept HookerType = requires(T a) { + a.backup; + a.replace; + }; + + template inline static bool HookSymNoHandle(void *original, T &arg) { if (original) { if constexpr(is_instance::value) { @@ -231,13 +236,13 @@ namespace lspd { } } - template + template inline static bool HookSym(void *handle, T &arg) { auto original = Dlsym(handle, arg.sym); return HookSymNoHandle(original, arg); } - template + template inline static bool HookSyms(void *handle, T &first, Args &...rest) { if (!(HookSym(handle, first) || ... || HookSym(handle, rest))) { LOGW("Hook Fails: %s", first.sym); diff --git a/core/src/main/cpp/main/include/jni_helper.h b/core/src/main/cpp/main/include/jni_helper.h index 567958e7..bf9135dc 100644 --- a/core/src/main/cpp/main/include/jni_helper.h +++ b/core/src/main/cpp/main/include/jni_helper.h @@ -24,6 +24,7 @@ #include "macros.h" #include #include "logging.h" +#include "base/object.h" #define JNI_START JNIEnv *env, [[maybe_unused]] jclass clazz @@ -78,6 +79,9 @@ private: }; template +concept JObject = std::is_base_of_v, std::remove_pointer_t>; + +template class ScopedLocalRef { public: ScopedLocalRef(JNIEnv *env, T localRef) : mEnv(env), mLocalRef(localRef) { @@ -86,6 +90,10 @@ public: ScopedLocalRef(ScopedLocalRef &&s) noexcept: mEnv(s.mEnv), mLocalRef(s.release()) { } + template + ScopedLocalRef(ScopedLocalRef &&s) noexcept: mEnv(s.mEnv), mLocalRef((T) s.release()) { + } + explicit ScopedLocalRef(JNIEnv *env) : mEnv(env), mLocalRef(nullptr) { } @@ -93,18 +101,18 @@ public: reset(); } - void reset(T ptr = NULL) { + void reset(T ptr = nullptr) { if (ptr != mLocalRef) { - if (mLocalRef != NULL) { + if (mLocalRef != nullptr) { mEnv->DeleteLocalRef(mLocalRef); } mLocalRef = ptr; } } - T release() __attribute__((warn_unused_result)) { + [[nodiscard]] T release() { T localRef = mLocalRef; - mLocalRef = NULL; + mLocalRef = nullptr; return localRef; } @@ -123,26 +131,28 @@ public: return *this; } - // Allows "if (scoped_ref == nullptr)" - bool operator==(std::nullptr_t) const { - return mLocalRef == nullptr; - } - - // Allows "if (scoped_ref != nullptr)" - bool operator!=(std::nullptr_t) const { - return mLocalRef != nullptr; - } - operator bool() const { return mLocalRef; } + template + friend + class ScopedLocalRef; + private: JNIEnv *mEnv; T mLocalRef; DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef); }; + +template +concept ScopeOrRaw = std::is_same_v || std::is_same_v, U>; +template +concept ScopeOrClass = ScopeOrRaw; +template +concept ScopeOrObject = ScopeOrRaw; + inline ScopedLocalRef ClearException(JNIEnv *env) { if (auto exception = env->ExceptionOccurred()) { env->ExceptionClear(); @@ -157,15 +167,24 @@ inline ScopedLocalRef ClearException(JNIEnv *env) { template [[maybe_unused]] -inline auto unwrap_sv(T &&x) { +inline auto unwrap_scope(T &&x) { if constexpr (std::is_same_v, std::string_view>) return x.data(); + else if constexpr (lspd::is_instance, ScopedLocalRef>::value) return x.get(); else return std::forward(x); } -template +template [[maybe_unused]] -inline auto JNI_SafeInvoke(JNIEnv *env, Func f, Args &&... args) { - static_assert(std::is_member_function_pointer_v); +inline auto wrap_scope(JNIEnv *env, T &&x) { + if constexpr (std::is_convertible_v) { + return ScopedLocalRef(env, std::forward(x)); + } else return x; +} + +template +requires(std::is_function_v) +[[maybe_unused]] +inline auto JNI_SafeInvoke(JNIEnv *env, Func JNIEnv::*f, Args &&... args) { struct finally { finally(JNIEnv *env) : env_(env) {} @@ -178,7 +197,10 @@ inline auto JNI_SafeInvoke(JNIEnv *env, Func f, Args &&... args) { JNIEnv *env_; } _(env); - return (env->*f)(unwrap_sv(std::forward(args))...); + if constexpr (!std::is_same_v(args)))...>>) + return wrap_scope(env, (env->*f)(unwrap_scope(std::forward(args))...)); + else (env->*f)(unwrap_scope(std::forward(args))...); } [[maybe_unused]] @@ -186,93 +208,118 @@ inline auto JNI_FindClass(JNIEnv *env, std::string_view name) { return JNI_SafeInvoke(env, &JNIEnv::FindClass, name); } +template [[maybe_unused]] -inline auto JNI_GetObjectClass(JNIEnv *env, jobject obj) { +inline auto JNI_GetObjectClass(JNIEnv *env, const Object &obj) { return JNI_SafeInvoke(env, &JNIEnv::GetObjectClass, obj); } +template [[maybe_unused]] -inline auto JNI_GetFieldID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) { +inline auto +JNI_GetFieldID(JNIEnv *env, const Class &clazz, std::string_view name, std::string_view sig) { return JNI_SafeInvoke(env, &JNIEnv::GetFieldID, clazz, name, sig); } +template [[maybe_unused]] -inline auto JNI_GetObjectField(JNIEnv *env, jclass clazz, jfieldID fieldId) { +inline auto JNI_GetObjectField(JNIEnv *env, const Class &clazz, jfieldID fieldId) { return JNI_SafeInvoke(env, &JNIEnv::GetObjectField, clazz, fieldId); } +template [[maybe_unused]] inline auto -JNI_GetMethodID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) { +JNI_GetMethodID(JNIEnv *env, const Class &clazz, std::string_view name, std::string_view sig) { return JNI_SafeInvoke(env, &JNIEnv::GetMethodID, clazz, name, sig); } -template +template [[maybe_unused]] -inline auto JNI_CallObjectMethod(JNIEnv *env, jobject obj, Args &&... args) { +inline auto JNI_CallObjectMethod(JNIEnv *env, const Object &obj, Args &&... args) { return JNI_SafeInvoke(env, &JNIEnv::CallObjectMethod, obj, std::forward(args)...); } -template +template [[maybe_unused]] -inline auto JNI_CallVoidMethod(JNIEnv *env, jobject obj, Args &&...args) { +inline auto JNI_CallVoidMethod(JNIEnv *env, const Object &obj, Args &&...args) { return JNI_SafeInvoke(env, &JNIEnv::CallVoidMethod, obj, std::forward(args)...); } -template +template [[maybe_unused]] -inline auto JNI_CallBooleanMethod(JNIEnv *env, jobject obj, Args &&...args) { +inline auto JNI_CallBooleanMethod(JNIEnv *env, const Object &obj, Args &&...args) { return JNI_SafeInvoke(env, &JNIEnv::CallBooleanMethod, obj, std::forward(args)...); } +template [[maybe_unused]] inline auto -JNI_GetStaticFieldID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) { +JNI_GetStaticFieldID(JNIEnv *env, const Class &clazz, std::string_view name, std::string_view sig) { return JNI_SafeInvoke(env, &JNIEnv::GetStaticFieldID, clazz, name, sig); } +template [[maybe_unused]] -inline auto JNI_GetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldId) { +inline auto JNI_GetStaticObjectField(JNIEnv *env, const Class &clazz, jfieldID fieldId) { return JNI_SafeInvoke(env, &JNIEnv::GetStaticObjectField, clazz, fieldId); } +template [[maybe_unused]] inline auto -JNI_GetStaticMethodID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) { +JNI_GetStaticMethodID(JNIEnv *env, const Class &clazz, std::string_view name, + std::string_view sig) { return JNI_SafeInvoke(env, &JNIEnv::GetStaticMethodID, clazz, name, sig); } -template +template [[maybe_unused]] -inline auto JNI_CallStaticVoidMethod(JNIEnv *env, jclass clazz, Args &&...args) { +inline auto JNI_CallStaticVoidMethod(JNIEnv *env, const Class &clazz, Args &&...args) { return JNI_SafeInvoke(env, &JNIEnv::CallStaticVoidMethod, clazz, std::forward(args)...); } -template +template [[maybe_unused]] -inline auto JNI_CallStaticObjectMethod(JNIEnv *env, jclass clazz, Args &&...args) { +inline auto JNI_CallStaticObjectMethod(JNIEnv *env, const Class &clazz, Args &&...args) { return JNI_SafeInvoke(env, &JNIEnv::CallStaticObjectMethod, clazz, std::forward(args)...); } -template +template [[maybe_unused]] -inline auto JNI_CallStaticIntMethod(JNIEnv *env, jclass clazz, Args &&...args) { +inline auto JNI_CallStaticIntMethod(JNIEnv *env, const Class &clazz, Args &&...args) { return JNI_SafeInvoke(env, &JNIEnv::CallStaticIntMethod, clazz, std::forward(args)...); } +template Array> [[maybe_unused]] -inline auto JNI_GetArrayLength(JNIEnv *env, jarray array) { +inline auto JNI_GetArrayLength(JNIEnv *env, const Array &array) { return JNI_SafeInvoke(env, &JNIEnv::GetArrayLength, array); } -template +template [[maybe_unused]] -inline auto JNI_NewObject(JNIEnv *env, jclass clazz, Args &&...args) { +inline auto JNI_NewObject(JNIEnv *env, const Class &clazz, Args &&...args) { return JNI_SafeInvoke(env, &JNIEnv::NewObject, clazz, std::forward(args)...); } +template [[maybe_unused]] inline auto -JNI_RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint size) { +JNI_RegisterNatives(JNIEnv *env, const Class &clazz, const JNINativeMethod *methods, jint size) { return JNI_SafeInvoke(env, &JNIEnv::RegisterNatives, clazz, methods, size); } + +template +[[maybe_unused]] +inline auto JNI_NewGlobalRef(JNIEnv *env, T &&x) requires(std::is_convertible_v){ + return (T) env->NewGlobalRef(std::forward(x)); +} + +template +[[maybe_unused]] +inline auto +JNI_NewGlobalRef(JNIEnv *env, const ScopedLocalRef &x) requires( + std::is_convertible_v){ + return (T) env->NewGlobalRef(x.get()); +} diff --git a/core/src/main/cpp/main/include/native_util.h b/core/src/main/cpp/main/include/native_util.h index 759dc1e5..b5ca1219 100644 --- a/core/src/main/cpp/main/include/native_util.h +++ b/core/src/main/cpp/main/include/native_util.h @@ -35,13 +35,12 @@ namespace lspd { const JNINativeMethod *methods, jint method_count) { - ScopedLocalRef clazz(env, - Context::GetInstance()->FindClassFromCurrentLoader(env, class_name)); + auto clazz = Context::GetInstance()->FindClassFromCurrentLoader(env, class_name); if (clazz.get() == nullptr) { LOGF("Couldn't find class: %s", class_name); return false; } - return JNI_RegisterNatives(env, clazz.get(), methods, method_count); + return JNI_RegisterNatives(env, clazz, methods, method_count); } #if defined(__cplusplus) diff --git a/core/src/main/cpp/main/include/utils.h b/core/src/main/cpp/main/include/utils.h index 4f4958f1..d83ef186 100644 --- a/core/src/main/cpp/main/include/utils.h +++ b/core/src/main/cpp/main/include/utils.h @@ -42,11 +42,11 @@ namespace lspd { template struct tstring : public std::integer_sequence { - constexpr const char *c_str() const { + inline constexpr static const char *c_str() { return str_; } - constexpr operator std::string_view() const { + inline constexpr operator std::string_view() const { return c_str(); } diff --git a/core/src/main/cpp/main/src/context.cpp b/core/src/main/cpp/main/src/context.cpp index 7bb23254..76437814 100644 --- a/core/src/main/cpp/main/src/context.cpp +++ b/core/src/main/cpp/main/src/context.cpp @@ -52,7 +52,7 @@ namespace lspd { vm_->GetEnv((void **) (&env), JNI_VERSION_1_4); art::JNIEnvExt env_ext(env); ScopedLocalRef clazz(env, env_ext.NewLocalRefer(class_ptr)); - if (clazz != nullptr) { + if (clazz) { JNI_CallStaticVoidMethod(env, class_linker_class_, post_fixup_static_mid_, clazz.get()); } } @@ -74,48 +74,44 @@ namespace lspd { } void Context::LoadDex(JNIEnv *env) { - jclass classloader = JNI_FindClass(env, "java/lang/ClassLoader"); - jmethodID getsyscl_mid = JNI_GetStaticMethodID( + auto classloader = JNI_FindClass(env, "java/lang/ClassLoader"); + auto getsyscl_mid = JNI_GetStaticMethodID( env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); - jobject sys_classloader = JNI_CallStaticObjectMethod(env, classloader, getsyscl_mid); + auto sys_classloader = JNI_CallStaticObjectMethod(env, classloader, getsyscl_mid); if (UNLIKELY(!sys_classloader)) { LOGE("getSystemClassLoader failed!!!"); return; } - jclass in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader"); - jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "", - "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); - jclass byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer"); + auto in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader"); + auto initMid = JNI_GetMethodID(env, in_memory_classloader, "", + "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); + auto byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer"); auto dex_buffer = env->NewDirectByteBuffer(reinterpret_cast(dex.data()), dex.size()); - jobject my_cl = JNI_NewObject(env, in_memory_classloader, initMid, - dex_buffer, sys_classloader); - env->DeleteLocalRef(classloader); - env->DeleteLocalRef(sys_classloader); - env->DeleteLocalRef(in_memory_classloader); - env->DeleteLocalRef(byte_buffer_class); - - if (UNLIKELY(my_cl == nullptr)) { + if (auto my_cl = JNI_NewObject(env, in_memory_classloader, initMid, + dex_buffer, sys_classloader)) { + inject_class_loader_ = JNI_NewGlobalRef(env, my_cl); + } else { LOGE("InMemoryDexClassLoader creation failed!!!"); return; } - inject_class_loader_ = env->NewGlobalRef(my_cl); - - env->DeleteLocalRef(my_cl); + env->DeleteLocalRef(dex_buffer); env->GetJavaVM(&vm_); } void Context::Init(JNIEnv *env) { - class_linker_class_ = (jclass) env->NewGlobalRef( - FindClassFromCurrentLoader(env, kClassLinkerClassName)); + if (auto class_linker_class = FindClassFromCurrentLoader(env, kClassLinkerClassName)) { + class_linker_class_ = JNI_NewGlobalRef(env, class_linker_class); + } post_fixup_static_mid_ = JNI_GetStaticMethodID(env, class_linker_class_, "onPostFixupStaticTrampolines", "(Ljava/lang/Class;)V"); - entry_class_ = (jclass) (env->NewGlobalRef( - FindClassFromLoader(env, GetCurrentClassLoader(), kEntryClassName))); + if (auto entry_class = FindClassFromLoader(env, GetCurrentClassLoader(), kEntryClassName)) { + entry_class_ = JNI_NewGlobalRef(env, entry_class); + } RegisterLogger(env); RegisterResourcesHook(env); @@ -125,44 +121,41 @@ namespace lspd { RegisterNativeAPI(env); } - jclass + ScopedLocalRef Context::FindClassFromLoader(JNIEnv *env, jobject class_loader, std::string_view class_name) { - if (class_loader == nullptr) return nullptr; - static auto clz = (jclass) env->NewGlobalRef( - env->FindClass("dalvik/system/DexClassLoader")); + if (class_loader == nullptr) return {env, nullptr}; + static auto clz = JNI_NewGlobalRef(env, JNI_FindClass(env, "dalvik/system/DexClassLoader")); static jmethodID mid = JNI_GetMethodID(env, clz, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); - jclass ret = nullptr; if (!mid) { mid = JNI_GetMethodID(env, clz, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;"); } if (LIKELY(mid)) { - jobject target = JNI_CallObjectMethod(env, class_loader, mid, - env->NewStringUTF(class_name.data())); + auto target = JNI_CallObjectMethod(env, class_loader, mid, + env->NewStringUTF(class_name.data())); if (target) { - return (jclass) target; + return target; } } else { LOGE("No loadClass/findClass method found"); } LOGE("Class %s not found", class_name.data()); - return ret; + return {env, nullptr}; } - inline void Context::FindAndCall(JNIEnv *env, const char *method_name, - const char *method_sig, ...) const { + template + void + Context::FindAndCall(JNIEnv *env, std::string_view method_name, std::string_view method_sig, + Args &&... args) const { if (UNLIKELY(!entry_class_)) { - LOGE("cannot call method %s, entry class is null", method_name); + LOGE("cannot call method %s, entry class is null", method_name.data()); return; } jmethodID mid = JNI_GetStaticMethodID(env, entry_class_, method_name, method_sig); if (LIKELY(mid)) { - va_list args; - va_start(args, method_sig); - env->CallStaticVoidMethodV(entry_class_, mid, args); - va_end(args); + JNI_CallStaticVoidMethod(env, entry_class_, mid, std::forward(args)...); } else { - LOGE("method %s id is null", method_name); + LOGE("method %s id is null", method_name.data()); } } @@ -184,7 +177,7 @@ namespace lspd { InstallInlineHooks(); Init(env); FindAndCall(env, "forkSystemServerPost", "(Landroid/os/IBinder;)V", binder); - } + } else skip_ = true; } setAllowUnload(skip_); } @@ -221,7 +214,8 @@ namespace lspd { void Context::OnNativeForkAndSpecializePost(JNIEnv *env) { const JUTFString process_name(env, nice_name_); - auto binder = skip_ ? nullptr : Service::instance()->RequestBinder(env, nice_name_); + auto binder = skip_ ? ScopedLocalRef{env, nullptr} + : Service::instance()->RequestBinder(env, nice_name_); if (binder) { LoadDex(env); InstallInlineHooks(); diff --git a/core/src/main/cpp/main/src/context.h b/core/src/main/cpp/main/src/context.h index 5ab9b744..695ce540 100644 --- a/core/src/main/cpp/main/src/context.h +++ b/core/src/main/cpp/main/src/context.h @@ -27,6 +27,7 @@ #include #include #include "utils.h" +#include "jni_helper.h" namespace lspd { class Context { @@ -44,9 +45,7 @@ namespace lspd { void CallOnPostFixupStaticTrampolines(void *class_ptr); - void FindAndCall(JNIEnv *env, const char *method_name, const char *method_sig, ...) const; - - inline jclass FindClassFromCurrentLoader(JNIEnv *env, std::string_view className) const { + inline ScopedLocalRef FindClassFromCurrentLoader(JNIEnv *env, std::string_view className) const { return FindClassFromLoader(env, GetCurrentClassLoader(), className); }; @@ -78,10 +77,13 @@ namespace lspd { void Init(JNIEnv *env); - static jclass FindClassFromLoader(JNIEnv *env, jobject class_loader, + static ScopedLocalRef FindClassFromLoader(JNIEnv *env, jobject class_loader, std::string_view class_name); static void setAllowUnload(bool unload); + template + void FindAndCall(JNIEnv *env, std::string_view method_name, std::string_view method_sig, Args&&... args) const; + friend std::unique_ptr std::make_unique(); }; diff --git a/core/src/main/cpp/main/src/jni/resources_hook.cpp b/core/src/main/cpp/main/src/jni/resources_hook.cpp index 75a95e41..828cbe8c 100644 --- a/core/src/main/cpp/main/src/jni/resources_hook.cpp +++ b/core/src/main/cpp/main/src/jni/resources_hook.cpp @@ -69,9 +69,10 @@ namespace lspd { } LSP_DEF_NATIVE_METHOD(jboolean, ResourcesHook, initXResourcesNative) { - classXResources = Context::GetInstance()->FindClassFromCurrentLoader(env, - kXResourcesClassName); - if (!classXResources) { + if (auto classXResources_ = Context::GetInstance()->FindClassFromCurrentLoader(env, + kXResourcesClassName)) { + classXResources = JNI_NewGlobalRef(env, classXResources_); + } else { LOGE("Error while loading XResources class '%s':", kXResourcesClassName); return JNI_FALSE; } @@ -90,14 +91,13 @@ namespace lspd { if (!PrepareSymbols()) { return JNI_FALSE; } - classXResources = reinterpret_cast(env->NewGlobalRef(classXResources)); return JNI_TRUE; } // @ApiSensitive(Level.MIDDLE) LSP_DEF_NATIVE_METHOD(jboolean, ResourcesHook, removeFinalFlagNative, jclass target_class) { if (target_class) { - jclass class_clazz = JNI_FindClass(env, "java/lang/Class"); + auto class_clazz = JNI_FindClass(env, "java/lang/Class"); jfieldID java_lang_Class_accessFlags = JNI_GetFieldID( env, class_clazz, "accessFlags", "I"); jint access_flags = env->GetIntField(target_class, java_lang_Class_accessFlags); @@ -110,8 +110,8 @@ namespace lspd { LSP_DEF_NATIVE_METHOD(jobject, ResourcesHook, buildDummyClassLoader, jobject parent, jobject resource_super_class, jobject typed_array_super_class) { using namespace startop::dex; - static auto in_memory_classloader = (jclass) env->NewGlobalRef( - env->FindClass("dalvik/system/InMemoryDexClassLoader")); + static auto in_memory_classloader = JNI_NewGlobalRef(env, JNI_FindClass(env, + "dalvik/system/InMemoryDexClassLoader")); static jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "", "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); DexBuilder dex_file; @@ -132,7 +132,7 @@ namespace lspd { auto dex_buffer = env->NewDirectByteBuffer(const_cast(image.ptr()), image.size()); return JNI_NewObject(env, in_memory_classloader, initMid, - dex_buffer, parent); + dex_buffer, parent).release(); } LSP_DEF_NATIVE_METHOD(void, ResourcesHook, rewriteXmlReferencesNative, diff --git a/core/src/main/cpp/main/src/jni/yahfa.cpp b/core/src/main/cpp/main/src/jni/yahfa.cpp index 36f352f4..0bdecb9b 100644 --- a/core/src/main/cpp/main/src/jni/yahfa.cpp +++ b/core/src/main/cpp/main/src/jni/yahfa.cpp @@ -38,7 +38,7 @@ namespace lspd { LSP_DEF_NATIVE_METHOD(jobject, Yahfa, findMethodNative, jclass targetClass, jstring methodName, jstring methodSig) { return yahfa::findMethodNative(env, clazz, targetClass, methodName, - methodSig); + methodSig); } LSP_DEF_NATIVE_METHOD(jboolean, Yahfa, backupAndHookNative, jobject target, @@ -60,8 +60,8 @@ namespace lspd { LSP_DEF_NATIVE_METHOD(jclass, Yahfa, buildHooker, jobject app_class_loader, jclass return_class, jobjectArray classes, jstring method_name) { - static auto in_memory_classloader = (jclass) env->NewGlobalRef( - env->FindClass("dalvik/system/InMemoryDexClassLoader")); + static auto in_memory_classloader = JNI_NewGlobalRef(env, JNI_FindClass(env, + "dalvik/system/InMemoryDexClassLoader")); static jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "", "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); DexBuilder dex_file; @@ -158,8 +158,9 @@ namespace lspd { slicer::MemView image{dex_file.CreateImage()}; auto dex_buffer = env->NewDirectByteBuffer(const_cast(image.ptr()), image.size()); - jobject my_cl = JNI_NewObject(env, in_memory_classloader, initMid, - dex_buffer, app_class_loader); + auto my_cl = JNI_NewObject(env, in_memory_classloader, initMid, + dex_buffer, app_class_loader); + env->DeleteLocalRef(dex_buffer); static jmethodID mid = JNI_GetMethodID(env, in_memory_classloader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); @@ -167,10 +168,10 @@ namespace lspd { mid = JNI_GetMethodID(env, in_memory_classloader, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;"); } - jobject target = env->CallObjectMethod(my_cl, mid, env->NewStringUTF("LspHooker_")); + auto target = JNI_CallObjectMethod(env, my_cl, mid, env->NewStringUTF("LspHooker_")); // LOGD("Created %zd", image.size()); if (target) { - return (jclass) target; + return (jclass) target.release(); } return nullptr; } diff --git a/core/src/main/cpp/main/src/service.cpp b/core/src/main/cpp/main/src/service.cpp index 872e88d0..00148f13 100644 --- a/core/src/main/cpp/main/src/service.cpp +++ b/core/src/main/cpp/main/src/service.cpp @@ -62,66 +62,64 @@ namespace lspd { void Service::InitService(JNIEnv *env) { if (LIKELY(initialized_)) return; - initialized_ = true; // ServiceManager - service_manager_class_ = env->FindClass("android/os/ServiceManager"); - if (service_manager_class_) { - service_manager_class_ = (jclass) env->NewGlobalRef(service_manager_class_); - } else { - env->ExceptionClear(); - return; - } - get_service_method_ = env->GetStaticMethodID(service_manager_class_, "getService", - "(Ljava/lang/String;)Landroid/os/IBinder;"); - if (!get_service_method_) { - env->ExceptionClear(); - return; - } + if (auto service_manager_class = JNI_FindClass(env, "android/os/ServiceManager")) + service_manager_class_ = JNI_NewGlobalRef(env, service_manager_class); + else return; + get_service_method_ = JNI_GetStaticMethodID(env, service_manager_class_, "getService", + "(Ljava/lang/String;)Landroid/os/IBinder;"); + if (!get_service_method_) return; // IBinder - jclass ibinder_class = env->FindClass("android/os/IBinder"); - transact_method_ = env->GetMethodID(ibinder_class, "transact", - "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z"); + if (auto ibinder_class = JNI_FindClass(env, "android/os/IBinder")) + transact_method_ = JNI_GetMethodID(env, ibinder_class, "transact", + "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z"); + else return; - binder_class_ = env->FindClass("android/os/Binder"); - if (binder_class_) binder_class_ = (jclass) env->NewGlobalRef(binder_class_); - binder_ctor_ = env->GetMethodID(binder_class_, "", "()V"); + if (auto binder_class = JNI_FindClass(env, "android/os/Binder")) + binder_class_ = JNI_NewGlobalRef(env, binder_class); + else return; + binder_ctor_ = JNI_GetMethodID(env, binder_class_, "", "()V"); // Parcel - parcel_class_ = env->FindClass("android/os/Parcel"); - if (parcel_class_) parcel_class_ = (jclass) env->NewGlobalRef(parcel_class_); - obtain_method_ = env->GetStaticMethodID(parcel_class_, "obtain", "()Landroid/os/Parcel;"); - recycleMethod_ = env->GetMethodID(parcel_class_, "recycle", "()V"); - write_interface_token_method_ = env->GetMethodID(parcel_class_, "writeInterfaceToken", - "(Ljava/lang/String;)V"); - write_int_method_ = env->GetMethodID(parcel_class_, "writeInt", "(I)V"); - write_string_method_ = env->GetMethodID(parcel_class_, "writeString", - "(Ljava/lang/String;)V"); - write_strong_binder_method_ = env->GetMethodID(parcel_class_, "writeStrongBinder", - "(Landroid/os/IBinder;)V"); - read_exception_method_ = env->GetMethodID(parcel_class_, "readException", "()V"); - read_strong_binder_method_ = env->GetMethodID(parcel_class_, "readStrongBinder", - "()Landroid/os/IBinder;"); + if (auto parcel_class = JNI_FindClass(env, "android/os/Parcel")) + parcel_class_ = JNI_NewGlobalRef(env, parcel_class); + else return; + obtain_method_ = JNI_GetStaticMethodID(env, parcel_class_, "obtain", + "()Landroid/os/Parcel;"); + recycleMethod_ = JNI_GetMethodID(env, parcel_class_, "recycle", "()V"); + write_interface_token_method_ = JNI_GetMethodID(env, parcel_class_, "writeInterfaceToken", + "(Ljava/lang/String;)V"); + write_int_method_ = JNI_GetMethodID(env, parcel_class_, "writeInt", "(I)V"); + write_string_method_ = JNI_GetMethodID(env, parcel_class_, "writeString", + "(Ljava/lang/String;)V"); + write_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "writeStrongBinder", + "(Landroid/os/IBinder;)V"); + read_exception_method_ = JNI_GetMethodID(env, parcel_class_, "readException", "()V"); + read_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "readStrongBinder", + "()Landroid/os/IBinder;"); // createStringArray_ = env->GetMethodID(parcel_class_, "createStringArray", // "()[Ljava/lang/String;"); - deadObjectExceptionClass_ = env->FindClass("android/os/DeadObjectException"); - if (deadObjectExceptionClass_) - deadObjectExceptionClass_ = (jclass) env->NewGlobalRef(deadObjectExceptionClass_); + if (auto deadObjectExceptionClass = JNI_FindClass(env, "android/os/DeadObjectException")) + deadObjectExceptionClass_ = JNI_NewGlobalRef(env, deadObjectExceptionClass); + initialized_ = true; } void Service::HookBridge(const Context &context, JNIEnv *env) { static bool hooked = false; // This should only be ran once, so unlikely if (UNLIKELY(hooked)) return; + if (UNLIKELY(!initialized_)) return; hooked = true; - bridge_service_class_ = context.FindClassFromCurrentLoader(env, kBridgeServiceClassName); - if (!bridge_service_class_) { + if (auto bridge_service_class = context.FindClassFromCurrentLoader(env, + kBridgeServiceClassName)) + bridge_service_class_ = JNI_NewGlobalRef(env, bridge_service_class); + else { LOGE("server class not found"); return; } - bridge_service_class_ = (jclass) env->NewGlobalRef(bridge_service_class_); exec_transact_replace_methodID_ = JNI_GetStaticMethodID(env, bridge_service_class_, "execTransact", "(IJJI)Z"); @@ -130,8 +128,8 @@ namespace lspd { return; } - ScopedLocalRef binderClass(env, env->FindClass("android/os/Binder")); - exec_transact_backup_methodID_ = JNI_GetMethodID(env, binderClass.get(), "execTransact", + auto binderClass = JNI_FindClass(env, "android/os/Binder"); + exec_transact_backup_methodID_ = JNI_GetMethodID(env, binderClass, "execTransact", "(IJJI)Z"); auto set_table_override = reinterpret_cast(Dlsym(handle_libart, @@ -151,10 +149,10 @@ namespace lspd { LOGD("Done InitService"); } - jobject Service::RequestBinder(JNIEnv *env, jstring nice_name) { + ScopedLocalRef Service::RequestBinder(JNIEnv *env, jstring nice_name) { if (UNLIKELY(!initialized_)) { LOGE("Service not initialized"); - return nullptr; + return {env, nullptr}; } auto bridgeServiceName = env->NewStringUTF(BRIDGE_SERVICE_NAME.data()); @@ -162,7 +160,7 @@ namespace lspd { get_service_method_, bridgeServiceName); if (!bridgeService) { LOGD("can't get %s", BRIDGE_SERVICE_NAME.data()); - return nullptr; + return {env, nullptr}; } auto heart_beat_binder = JNI_NewObject(env, binder_class_, binder_ctor_); @@ -181,7 +179,7 @@ namespace lspd { data, reply, 0); - jobject service = nullptr; + ScopedLocalRef service = {env, nullptr}; if (res) { JNI_CallVoidMethod(env, reply, read_exception_method_); service = JNI_CallObjectMethod(env, reply, read_strong_binder_method_); @@ -189,25 +187,23 @@ namespace lspd { JNI_CallVoidMethod(env, data, recycleMethod_); JNI_CallVoidMethod(env, reply, recycleMethod_); if (service) { - env->NewGlobalRef(heart_beat_binder); - } else { - env->DeleteLocalRef(heart_beat_binder); + JNI_NewGlobalRef(env, heart_beat_binder); } return service; } - jobject Service::RequestBinderForSystemServer(JNIEnv *env) { + ScopedLocalRef Service::RequestBinderForSystemServer(JNIEnv *env) { if (UNLIKELY(!initialized_ || !bridge_service_class_)) { LOGE("Service not initialized"); - return nullptr; + return {env, nullptr}; } auto bridgeServiceName = env->NewStringUTF(SYSTEM_SERVER_BRIDGE_SERVICE_NAME.data()); auto binder = JNI_CallStaticObjectMethod(env, service_manager_class_, get_service_method_, bridgeServiceName); if (!binder) { LOGD("Fail to get binder for system server"); - return nullptr; + return {env, nullptr}; } auto method = JNI_GetStaticMethodID(env, bridge_service_class_, "getApplicationServiceForSystemServer", @@ -216,9 +212,7 @@ namespace lspd { auto app_binder = JNI_CallStaticObjectMethod(env, bridge_service_class_, method, binder, heart_beat_binder); if (app_binder) { - env->NewGlobalRef(heart_beat_binder); - } else { - env->DeleteLocalRef(heart_beat_binder); + JNI_NewGlobalRef(env, heart_beat_binder); } return app_binder; } diff --git a/core/src/main/cpp/main/src/service.h b/core/src/main/cpp/main/src/service.h index b9a810d9..0bd66af7 100644 --- a/core/src/main/cpp/main/src/service.h +++ b/core/src/main/cpp/main/src/service.h @@ -49,10 +49,9 @@ namespace lspd { void InitService(JNIEnv *env); void HookBridge(const Context& context, JNIEnv *env); + ScopedLocalRef RequestBinder(JNIEnv *env, jstring nice_name); - jobject RequestBinder(JNIEnv *env, jstring nice_name); - - jobject RequestBinderForSystemServer(JNIEnv *env); + ScopedLocalRef RequestBinderForSystemServer(JNIEnv *env); private: inline static std::unique_ptr instance_ = std::make_unique();