diff --git a/core/src/main/cpp/main/include/art/runtime/art_method.h b/core/src/main/cpp/main/include/art/runtime/art_method.h index 00f8b19d..a6720330 100644 --- a/core/src/main/cpp/main/include/art/runtime/art_method.h +++ b/core/src/main/cpp/main/include/art/runtime/art_method.h @@ -22,7 +22,7 @@ namespace art { return PrettyMethod(thiz, true); } - static void Setup(void *handle, HookFunType hook_func) { + static void Setup(void *handle) { LOGD("art_method hook setup, handle=%p", handle); RETRIEVE_MEM_FUNC_SYMBOL(PrettyMethod, "_ZN3art9ArtMethod12PrettyMethodEb"); } diff --git a/core/src/main/cpp/main/include/art/runtime/class_linker.h b/core/src/main/cpp/main/include/art/runtime/class_linker.h index e06eb49b..dcabef25 100644 --- a/core/src/main/cpp/main/include/art/runtime/class_linker.h +++ b/core/src/main/cpp/main/include/art/runtime/class_linker.h @@ -79,7 +79,7 @@ namespace art { } // @ApiSensitive(Level.MIDDLE) - static void Setup(void *handle, HookFunType hook_func) { + static void Setup(void *handle) { LOGD("Classlinker hook setup, handle=%p", handle); int api_level = lspd::GetAndroidApiLevel(); size_t OFFSET_classlinker; // Get offset from art::Runtime::RunRootClinits() call in IDA @@ -128,7 +128,7 @@ namespace art { RETRIEVE_MEM_FUNC_SYMBOL(SetEntryPointsToInterpreter, "_ZNK3art11ClassLinker27SetEntryPointsToInterpreterEPNS_9ArtMethodE"); - lspd::HookSyms(handle, hook_func, ShouldUseInterpreterEntrypoint); + lspd::HookSyms(handle, ShouldUseInterpreterEntrypoint); if (api_level >= __ANDROID_API_R__) { // In android R, FixupStaticTrampolines won't be called unless it's marking it as @@ -136,9 +136,9 @@ namespace art { // So we miss some calls between initialized and visiblyInitialized. // Therefore we hook the new introduced MarkClassInitialized instead // This only happens on non-x86 devices - lspd::HookSyms(handle, hook_func, MarkClassInitialized); + lspd::HookSyms(handle, MarkClassInitialized); } else { - lspd::HookSyms(handle, hook_func, FixupStaticTrampolines); + lspd::HookSyms(handle, FixupStaticTrampolines); } // MakeInitializedClassesVisiblyInitialized will cause deadlock diff --git a/core/src/main/cpp/main/include/art/runtime/gc/heap.h b/core/src/main/cpp/main/include/art/runtime/gc/heap.h index 0d6ff447..daeaec5d 100644 --- a/core/src/main/cpp/main/include/art/runtime/gc/heap.h +++ b/core/src/main/cpp/main/include/art/runtime/gc/heap.h @@ -31,7 +31,7 @@ namespace art { } // @ApiSensitive(Level.MIDDLE) - static void Setup(void *handle, HookFunType hook_func) { + static void Setup(void *handle) { int api_level = lspd::GetAndroidApiLevel(); size_t OFFSET_heap; // Get offset from art::Runtime::RunRootClinits() call in IDA switch (api_level) { diff --git a/core/src/main/cpp/main/include/art/runtime/hidden_api.h b/core/src/main/cpp/main/include/art/runtime/hidden_api.h index 63fe7671..6e735769 100644 --- a/core/src/main/cpp/main/include/art/runtime/hidden_api.h +++ b/core/src/main/cpp/main/include/art/runtime/hidden_api.h @@ -39,17 +39,17 @@ namespace art { }); // @ApiSensitive(Level.HIGH) - static void DisableHiddenApi(void *handle, HookFunType hook_func) { + static void DisableHiddenApi(void *handle) { const int api_level = lspd::GetAndroidApiLevel(); if (api_level < __ANDROID_API_P__) { return; } if (api_level == __ANDROID_API_P__) { - lspd::HookSyms(handle, hook_func, GetMethodActionImpl); - lspd::HookSyms(handle, hook_func, GetFieldActionImpl); + lspd::HookSyms(handle, GetMethodActionImpl); + lspd::HookSyms(handle, GetFieldActionImpl); } else { - lspd::HookSyms(handle, hook_func, ShouldDenyAccessToMethodImpl); - lspd::HookSyms(handle, hook_func, ShouldDenyAccessToFieldImpl); + lspd::HookSyms(handle, ShouldDenyAccessToMethodImpl); + lspd::HookSyms(handle, ShouldDenyAccessToFieldImpl); } }; diff --git a/core/src/main/cpp/main/include/art/runtime/instrumentation.h b/core/src/main/cpp/main/include/art/runtime/instrumentation.h index 4c180289..e3ad3b3f 100644 --- a/core/src/main/cpp/main/include/art/runtime/instrumentation.h +++ b/core/src/main/cpp/main/include/art/runtime/instrumentation.h @@ -22,8 +22,8 @@ namespace art { } }); - static void DisableUpdateHookedMethodsCode(void *handle, HookFunType hook_func) { - lspd::HookSym(handle, hook_func, UpdateMethodsCode); + static void DisableUpdateHookedMethodsCode(void *handle) { + lspd::HookSym(handle, UpdateMethodsCode); } } } diff --git a/core/src/main/cpp/main/include/art/runtime/jni_env_ext.h b/core/src/main/cpp/main/include/art/runtime/jni_env_ext.h index b6bddf6f..7d102c88 100644 --- a/core/src/main/cpp/main/include/art/runtime/jni_env_ext.h +++ b/core/src/main/cpp/main/include/art/runtime/jni_env_ext.h @@ -21,7 +21,7 @@ namespace art { JNIEnvExt(void *thiz) : HookedObject(thiz) {} // @ApiSensitive(Level.MIDDLE) - static void Setup(void *handle, HookFunType hook_func) { + static void Setup(void *handle) { RETRIEVE_MEM_FUNC_SYMBOL(NewLocalRef, "_ZN3art9JNIEnvExt11NewLocalRefEPNS_6mirror6ObjectE"); RETRIEVE_MEM_FUNC_SYMBOL(DeleteLocalRef, "_ZN3art9JNIEnvExt14DeleteLocalRefEP8_jobject"); } diff --git a/core/src/main/cpp/main/include/art/runtime/mirror/class.h b/core/src/main/cpp/main/include/art/runtime/mirror/class.h index 2f9692a8..c55ebb17 100644 --- a/core/src/main/cpp/main/include/art/runtime/mirror/class.h +++ b/core/src/main/cpp/main/include/art/runtime/mirror/class.h @@ -55,13 +55,13 @@ namespace art { Class(void *thiz) : HookedObject(thiz) {} // @ApiSensitive(Level.MIDDLE) - static void Setup(void *handle, HookFunType hook_func) { + static void Setup(void *handle) { RETRIEVE_MEM_FUNC_SYMBOL(GetDescriptor, "_ZN3art6mirror5Class13GetDescriptorEPNSt3__112" "basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE"); RETRIEVE_MEM_FUNC_SYMBOL(GetClassDef, "_ZN3art6mirror5Class11GetClassDefEv"); - lspd::HookSyms(handle, hook_func, IsInSamePackage); + lspd::HookSyms(handle, IsInSamePackage); } const char *GetDescriptor(std::string *storage) { diff --git a/core/src/main/cpp/main/include/art/runtime/reflection.h b/core/src/main/cpp/main/include/art/runtime/reflection.h index e63a7412..2f47f3bb 100644 --- a/core/src/main/cpp/main/include/art/runtime/reflection.h +++ b/core/src/main/cpp/main/include/art/runtime/reflection.h @@ -21,8 +21,8 @@ namespace art { return backup(obj, declaring_class, access_flags, calling_class); }); - static void PermissiveAccessByReflection(void *handle, HookFunType hook_func) { - lspd::HookSym(handle, hook_func, VerifyAccess); + static void PermissiveAccessByReflection(void *handle) { + lspd::HookSym(handle, VerifyAccess); } } #endif //LSPOSED_REFLECTION_H diff --git a/core/src/main/cpp/main/include/art/runtime/runtime.h b/core/src/main/cpp/main/include/art/runtime/runtime.h index 378fa9a7..36bc6b56 100644 --- a/core/src/main/cpp/main/include/art/runtime/runtime.h +++ b/core/src/main/cpp/main/include/art/runtime/runtime.h @@ -18,7 +18,7 @@ namespace art { } // @ApiSensitive(Level.LOW) - static void Setup(void *handle, HookFunType hook_func) { + static void Setup(void *handle) { RETRIEVE_FIELD_SYMBOL(instance, "_ZN3art7Runtime9instance_E"); void * thiz = *reinterpret_cast(instance); LOGD("_ZN3art7Runtime9instance_E = %p", thiz); diff --git a/core/src/main/cpp/main/include/art/runtime/thread.h b/core/src/main/cpp/main/include/art/runtime/thread.h index 0573f4d3..7d7393f9 100644 --- a/core/src/main/cpp/main/include/art/runtime/thread.h +++ b/core/src/main/cpp/main/include/art/runtime/thread.h @@ -26,7 +26,7 @@ namespace art { return Thread(CurrentFromGdb()); } - static void Setup(void *handle, [[maybe_unused]] HookFunType hook_func) { + static void Setup(void *handle) { RETRIEVE_MEM_FUNC_SYMBOL(DecodeJObject, "_ZNK3art6Thread13DecodeJObjectEP8_jobject"); RETRIEVE_FUNC_SYMBOL(CurrentFromGdb, diff --git a/core/src/main/cpp/main/include/base/object.h b/core/src/main/cpp/main/include/base/object.h index 8c57112a..cfb14e60 100644 --- a/core/src/main/cpp/main/include/base/object.h +++ b/core/src/main/cpp/main/include/base/object.h @@ -7,6 +7,7 @@ #include #include #include "config.h" +#include "native_hook.h" #define _uintval(p) reinterpret_cast(p) #define _ptr(p) reinterpret_cast(p) @@ -19,8 +20,6 @@ _page_align(_uintval(p) + n) != _page_align(_uintval(p)) ? _page_align(n) + _page_size : _page_align(n), \ PROT_READ | PROT_WRITE | PROT_EXEC) -typedef void (*HookFunType)(void *, void *, void **); - #define CONCATENATE(a, b) a##b #define CREATE_HOOK_STUB_ENTRIES(SYM, RET, FUNC, PARAMS, DEF) \ @@ -110,10 +109,9 @@ namespace lspd { return Dlsym(handle, last...); } - ALWAYS_INLINE inline static void HookFunction(HookFunType hook_fun, void *original, - void *replace, void **backup) { + ALWAYS_INLINE inline static void HookFunction(void *original, void *replace, void **backup) { _make_rwx(original, _page_size); - hook_fun(original, replace, backup); + hook_func(original, replace, backup); } template class> @@ -207,15 +205,14 @@ namespace lspd { }; template - inline static bool HookSym(void *handle, HookFunType hook_fun, T &arg) { - auto original = Dlsym(handle, arg.sym); + inline static bool HookSymNoHandle(void *original, T &arg) { if (original) { if constexpr(is_instance::value) { void *backup; - HookFunction(hook_fun, original, reinterpret_cast(arg.replace), &backup); + HookFunction(original, reinterpret_cast(arg.replace), &backup); arg.backup = reinterpret_cast(backup); } else { - HookFunction(hook_fun, original, reinterpret_cast(arg.replace), + HookFunction(original, reinterpret_cast(arg.replace), reinterpret_cast(&arg.backup)); } return true; @@ -224,9 +221,15 @@ namespace lspd { } } + template + inline static bool HookSym(void *handle, T &arg) { + auto original = Dlsym(handle, arg.sym); + return HookSymNoHandle(original, arg); + } + template - inline static bool HookSyms(void *handle, HookFunType hook_fun, T &first, Args &...rest) { - if (!(HookSym(handle, hook_fun, first) || ... || HookSym(handle, hook_fun, rest))) { + inline static bool HookSyms(void *handle, T &first, Args &...rest) { + if (!(HookSym(handle, first) || ... || HookSym(handle, rest))) { LOGW("Hook Fails: %s", first.sym); return false; } diff --git a/core/src/main/cpp/main/src/context.cpp b/core/src/main/cpp/main/src/context.cpp index 75ae277f..3132a804 100644 --- a/core/src/main/cpp/main/src/context.cpp +++ b/core/src/main/cpp/main/src/context.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include "jni/config_manager.h" #include "jni/art_class_linker.h" #include "jni/art_heap.h" @@ -9,19 +8,16 @@ #include "jni/resources_hook.h" #include #include -#include #include -#include #include "jni/pending_hooks.h" #include #include #include #include "context.h" #include "config_manager.h" -#include "art/runtime/runtime.h" -#include "art/runtime/gc/heap.h" #include "native_hook.h" #include "jni/logger.h" +#include "jni/native_api.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-value" @@ -121,6 +117,7 @@ namespace lspd { RegisterArtHeap(env); RegisterEdxpYahfa(env); RegisterPendingHooks(env); + RegisterNativeAPI(env); variant_ = Variant(ConfigManager::GetInstance()->GetVariant()); LOGI("LSP Variant: %d", variant_); diff --git a/core/src/main/cpp/main/src/jni/native_api.cpp b/core/src/main/cpp/main/src/jni/native_api.cpp new file mode 100644 index 00000000..fe44561c --- /dev/null +++ b/core/src/main/cpp/main/src/jni/native_api.cpp @@ -0,0 +1,23 @@ +// +// Created by 双草酸酯 on 2/7/21. +// +#include "native_api.h" +#include "nativehelper/jni_macros.h" +#include "native_util.h" +#include "JNIHelper.h" +#include "../native_api.h" + +namespace lspd { + LSP_DEF_NATIVE_METHOD(void, NativeAPI, recordNativeEntrypoint, jstring jstr) { + JUTFString str(env, jstr); + RegisterNativeLib(str); + } + + static JNINativeMethod gMethods[] = { + LSP_NATIVE_METHOD(NativeAPI, recordNativeEntrypoint, "(Ljava/lang/String;)V") + }; + + void RegisterNativeAPI(JNIEnv *env) { + REGISTER_LSP_NATIVE_METHODS(NativeAPI); + } +} diff --git a/core/src/main/cpp/main/src/jni/native_api.h b/core/src/main/cpp/main/src/jni/native_api.h new file mode 100644 index 00000000..28bbc321 --- /dev/null +++ b/core/src/main/cpp/main/src/jni/native_api.h @@ -0,0 +1,15 @@ +// +// Created by 双草酸酯 on 2/7/21. +// + +#ifndef LSPOSED_JNI_NATIVE_API_H +#define LSPOSED_JNI_NATIVE_API_H + +#include + +namespace lspd { + void RegisterNativeAPI(JNIEnv*); +} + + +#endif //LSPOSED_JNI_NATIVE_API_H diff --git a/core/src/main/cpp/main/src/main.cpp b/core/src/main/cpp/main/src/main.cpp index 266238ed..628c33cd 100644 --- a/core/src/main/cpp/main/src/main.cpp +++ b/core/src/main/cpp/main/src/main.cpp @@ -1,22 +1,13 @@ -#include -#include -#include #include #include #include -#include #include -#include -#include -#include -#include -#include #include "logging.h" #include "config.h" #include "context.h" #include #include "config_manager.h" -#include "native_hook.h" +#include "symbol_cache.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-value" @@ -25,6 +16,7 @@ namespace lspd { static void onModuleLoaded() { LOGI("onModuleLoaded: welcome to LSPosed!"); // rirud must be used in onModuleLoaded + InitSymbolCache(); ConfigManager::Init(); } diff --git a/core/src/main/cpp/main/src/native_api.cpp b/core/src/main/cpp/main/src/native_api.cpp new file mode 100644 index 00000000..8ce2b51e --- /dev/null +++ b/core/src/main/cpp/main/src/native_api.cpp @@ -0,0 +1,89 @@ +// +// Created by kotori on 2/4/21. +// + +#include "native_api.h" +#include "symbol_cache.h" +#include +#include +#include + +/* + * Module: define xposed_native file in /assets, each line is a .so file name + * LSP: Hook do_dlopen, if any .so file matches the name above, try to call + * "native_init(void*)" function in target so with function pointer of "init" below. + * Module: Call init function with the pointer of callback function. + * LSP: Store the callback function pointer (multiple callback allowed) and return + * LsposedNativeAPIEntries struct. + * Module: Since JNI is not yet available at that time, module can store the struct to somewhere else, + * and handle them in JNI_Onload or later. + * Module: Do some MAGIC provided by LSPosed framework. + * LSP: If any so loaded by target app, we will send a callback to the specific module callback function. + * But an exception is, if the target skipped dlopen and handle linker stuffs on their own, the + * callback will not work. + */ + +namespace lspd { + std::vector moduleLoadedCallbacks; + std::vector moduleNativeLibs; + + LsposedNativeAPIEntriesV1 init(LsposedNativeOnModuleLoaded onModuleLoaded) { + if (onModuleLoaded != nullptr) moduleLoadedCallbacks.push_back(onModuleLoaded); + + LsposedNativeAPIEntriesV1 ret{ + .version = 1, + .inlineHookFunc = HookFunction + }; + return ret; + } + + void RegisterNativeLib(const std::string& library_name) { + LOGD("native_api: Registered %s", library_name.c_str()); + moduleNativeLibs.push_back(library_name); + } + + bool hasEnding(std::string_view fullString, std::string_view ending) { + if (fullString.length() >= ending.length()) { + return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); + } else { + return false; + } + } + + CREATE_HOOK_STUB_ENTRIES( + "__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv", + void*, do_dlopen, (const char* name, int flags, const void* extinfo, + const void* caller_addr), { + auto *handle = backup(name, flags, extinfo, caller_addr); + std::string ns(name); + LOGD("native_api: do_dlopen(%s)", name); + if (handle == nullptr) { + return nullptr; + } + for (std::string_view module_lib: moduleNativeLibs) { + // the so is a module so + if (UNLIKELY(hasEnding(ns, module_lib))) { + LOGI("Loading module native library %s", module_lib.data()); + void* native_init_sym = dlsym(handle, "native_init"); + if (UNLIKELY(native_init_sym == nullptr)) { + LOGE("Failed to get symbol \"native_init\" from library %s", module_lib.data()); + break; + } + auto native_init = reinterpret_cast(native_init_sym); + native_init(reinterpret_cast(init)); + } + } + + // Callbacks + for (LsposedNativeOnModuleLoaded callback: moduleLoadedCallbacks) { + callback(name, handle); + } + return handle; + }); + + void InstallNativeAPI() { + LOGD("InstallNativeAPI: %p", symbol_do_dlopen); + symbol_do_dlopen = DobbySymbolResolver(nullptr, "__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv"); + HookSymNoHandle(symbol_do_dlopen, do_dlopen); + } +} \ No newline at end of file diff --git a/core/src/main/cpp/main/src/native_api.h b/core/src/main/cpp/main/src/native_api.h new file mode 100644 index 00000000..afe9d21a --- /dev/null +++ b/core/src/main/cpp/main/src/native_api.h @@ -0,0 +1,25 @@ +// +// Created by kotori on 2/4/21. +// + +#ifndef LSPOSED_NATIVE_API_H +#define LSPOSED_NATIVE_API_H + +#include +#include +#include + +// typedef int (*HookFunType)(void *, void *, void **); // For portability +typedef void (*LsposedNativeOnModuleLoaded) (const char* name, void* handle); +typedef void (*NativeInit)(void * init_func); +struct LsposedNativeAPIEntriesV1 { + uint32_t version; + lspd::HookFunType inlineHookFunc; +}; + +namespace lspd { + void InstallNativeAPI(); + void RegisterNativeLib(const std::string& library_name); +} + +#endif //LSPOSED_NATIVE_API_H diff --git a/core/src/main/cpp/main/src/native_hook.cpp b/core/src/main/cpp/main/src/native_hook.cpp index 0ab036a2..5a2a71f2 100644 --- a/core/src/main/cpp/main/src/native_hook.cpp +++ b/core/src/main/cpp/main/src/native_hook.cpp @@ -10,6 +10,7 @@ #include "bionic_linker_restriction.h" #include "utils.h" #include "logging.h" +#include "native_api.h" #include "native_hook.h" #include "riru_hook.h" #include "art/runtime/mirror/class.h" @@ -17,7 +18,6 @@ #include "art/runtime/class_linker.h" #include "art/runtime/gc/heap.h" #include "art/runtime/hidden_api.h" -#include "art/runtime/art_method.h" #include "art/runtime/instrumentation.h" #include "art/runtime/reflection.h" @@ -27,7 +27,6 @@ namespace lspd { static volatile bool installed = false; static volatile bool art_hooks_installed = false; - static HookFunType hook_func = reinterpret_cast(DobbyHook); void InstallArtHooks(void *art_handle); @@ -44,7 +43,7 @@ namespace lspd { return; } LOGI("Using api level %d", api_level); - InstallRiruHooks(hook_func); + InstallRiruHooks(); // install ART hooks if (api_level >= __ANDROID_API_Q__) { // From Riru v22 we can't get ART handle by hooking dlopen, so we get libart.so from soinfo. @@ -68,22 +67,24 @@ namespace lspd { ScopedDlHandle art_handle(kLibArtLegacyPath.c_str()); InstallArtHooks(art_handle.Get()); } + + InstallNativeAPI(); } void InstallArtHooks(void *art_handle) { if (art_hooks_installed) { return; } - art::hidden_api::DisableHiddenApi(art_handle, hook_func); - art::Runtime::Setup(art_handle, hook_func); - art::gc::Heap::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); - art::instrumentation::DisableUpdateHookedMethodsCode(art_handle, hook_func); - art::PermissiveAccessByReflection(art_handle, hook_func); + art::hidden_api::DisableHiddenApi(art_handle); + art::Runtime::Setup(art_handle); + art::gc::Heap::Setup(art_handle); + art::art_method::Setup(art_handle); + art::Thread::Setup(art_handle); + art::ClassLinker::Setup(art_handle); + art::mirror::Class::Setup(art_handle); + art::JNIEnvExt::Setup(art_handle); + art::instrumentation::DisableUpdateHookedMethodsCode(art_handle); + art::PermissiveAccessByReflection(art_handle); art_hooks_installed = true; LOGI("ART hooks installed"); diff --git a/core/src/main/cpp/main/src/native_hook.h b/core/src/main/cpp/main/src/native_hook.h index 781b9ea2..1d777ba3 100644 --- a/core/src/main/cpp/main/src/native_hook.h +++ b/core/src/main/cpp/main/src/native_hook.h @@ -1,8 +1,10 @@ #pragma once +#include namespace lspd { - + typedef void (*HookFunType)(void *, void *, void **); + static HookFunType hook_func = reinterpret_cast(DobbyHook); void InstallInlineHooks(); } diff --git a/core/src/main/cpp/main/src/riru_hook.cpp b/core/src/main/cpp/main/src/riru_hook.cpp index 6ef32120..9a793661 100644 --- a/core/src/main/cpp/main/src/riru_hook.cpp +++ b/core/src/main/cpp/main/src/riru_hook.cpp @@ -101,7 +101,7 @@ namespace lspd { return res; }); - void InstallRiruHooks(HookFunType hook_func) { + void InstallRiruHooks() { LOGI("Start to install Riru hook"); @@ -112,8 +112,7 @@ namespace lspd { LOGE("Failed to get symbol of __system_property_get"); return; } - HookFunction(hook_func, sym, reinterpret_cast(decltype(__system_property_get)::replace), - reinterpret_cast(&decltype(__system_property_get)::backup)); + HookSymNoHandle(sym, __system_property_get); if (GetAndroidApiLevel() >= __ANDROID_API_P__) { sym = DobbySymbolResolver(nullptr, @@ -122,8 +121,7 @@ namespace lspd { LOGE("Failed to get symbol of _ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_"); return; } - HookFunction(hook_func, sym, reinterpret_cast(decltype(GetProperty)::replace), - reinterpret_cast(&decltype(GetProperty)::backup)); + HookSymNoHandle(sym, GetProperty); } LOGI("Riru hooks installed"); diff --git a/core/src/main/cpp/main/src/riru_hook.h b/core/src/main/cpp/main/src/riru_hook.h index 27ff885c..43cf668e 100644 --- a/core/src/main/cpp/main/src/riru_hook.h +++ b/core/src/main/cpp/main/src/riru_hook.h @@ -16,6 +16,6 @@ namespace lspd { static constexpr const char *kPropValueCompilerFlagsWS = " --inline-max-code-units=0"; - void InstallRiruHooks(HookFunType hook_func); + void InstallRiruHooks(); } diff --git a/core/src/main/cpp/main/src/symbol_cache.cpp b/core/src/main/cpp/main/src/symbol_cache.cpp new file mode 100644 index 00000000..cd433ea8 --- /dev/null +++ b/core/src/main/cpp/main/src/symbol_cache.cpp @@ -0,0 +1,18 @@ +// +// Created by kotori on 2/7/21. +// + +#include "symbol_cache.h" +#include +#include +#include + +namespace lspd { + void InitSymbolCache() { + if (LIKELY(initialized)) return; + LOGD("InitSymbolCache"); + // TODO: set image name + symbol_do_dlopen = DobbySymbolResolver(nullptr, "__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv"); + initialized = true; + } +} \ No newline at end of file diff --git a/core/src/main/cpp/main/src/symbol_cache.h b/core/src/main/cpp/main/src/symbol_cache.h new file mode 100644 index 00000000..f637e52c --- /dev/null +++ b/core/src/main/cpp/main/src/symbol_cache.h @@ -0,0 +1,16 @@ +// +// Created by kotori on 2/7/21. +// + +#ifndef LSPOSED_SYMBOL_CACHE_H +#define LSPOSED_SYMBOL_CACHE_H +#include + +namespace lspd { + static std::atomic_bool initialized; + static void* symbol_do_dlopen = nullptr; + + void InitSymbolCache(); +} + +#endif //LSPOSED_SYMBOL_CACHE_H diff --git a/core/src/main/java/de/robv/android/xposed/XposedInit.java b/core/src/main/java/de/robv/android/xposed/XposedInit.java index 3aead877..e2531259 100644 --- a/core/src/main/java/de/robv/android/xposed/XposedInit.java +++ b/core/src/main/java/de/robv/android/xposed/XposedInit.java @@ -41,6 +41,7 @@ import de.robv.android.xposed.callbacks.XC_InitPackageResources; import de.robv.android.xposed.callbacks.XC_InitZygote; import de.robv.android.xposed.callbacks.XC_LoadPackage; import de.robv.android.xposed.callbacks.XCallback; +import io.github.lsposed.lspd.nativebridge.NativeAPI; import static de.robv.android.xposed.XposedBridge.hookAllConstructors; import static de.robv.android.xposed.XposedBridge.hookAllMethods; @@ -345,6 +346,7 @@ public final class XposedInit { newLoadedApk.add(apk); } else { loadedModules.add(apk); // temporarily add it for XSharedPreference + loadNativeLibs(apk); boolean loadSuccess = loadModule(apk, topClassLoader, callInitZygote); if (loadSuccess) { newLoadedApk.add(apk); @@ -391,6 +393,45 @@ public final class XposedInit { } } + /** + * Load all so from an APK by reading assets/native_init. + * It will only store the so names but not doing anything. + */ + private static boolean loadNativeLibs(String apk) { + ZipFile zipFile = null; + InputStream is; + try { + zipFile = new ZipFile(apk); + ZipEntry zipEntry = zipFile.getEntry("assets/native_init"); + if (zipEntry == null) { + Log.e(TAG, " assets/native_init not found in the APK"); + closeSilently(zipFile); + return false; + } + is = zipFile.getInputStream(zipEntry); + } catch (IOException e) { + Log.w(TAG, " Cannot read assets/native_init in the APK. Maybe it doesn't support native API", e); + closeSilently(zipFile); + return false; + } + BufferedReader moduleLibraryReader = new BufferedReader(new InputStreamReader(is)); + String moduleLibraryName; + try { + while ((moduleLibraryName = moduleLibraryReader.readLine()) != null) { + if (!moduleLibraryName.startsWith("#") && moduleLibraryName.endsWith(".so")) { + NativeAPI.recordNativeEntrypoint(moduleLibraryName); + } + } + } catch (IOException e) { + Log.e(TAG, " Failed to load native library list from " + apk, e); + return false; + } finally { + closeSilently(is); + closeSilently(zipFile); + } + return true; + } + /** * Load a module from an APK by calling the init(String) method for all classes defined * in assets/xposed_init. @@ -403,7 +444,14 @@ public final class XposedInit { return false; } - ClassLoader mcl = new PathClassLoader(apk, topClassLoader); + // module can load it's own so + StringBuilder nativePath = new StringBuilder(); + for (String i: Build.SUPPORTED_ABIS) { + nativePath.append(apk).append("!/lib/").append(i).append(File.pathSeparator); + } + // Log.d(TAG, "Allowed native path" + nativePath.toString()); + ClassLoader mcl = new PathClassLoader(apk, nativePath.toString(), topClassLoader); + try { if (mcl.loadClass(INSTANT_RUN_CLASS) != null) { Log.e(TAG, " Cannot load module, please disable \"Instant Run\" in Android Studio."); diff --git a/core/src/main/java/io/github/lsposed/lspd/nativebridge/NativeAPI.java b/core/src/main/java/io/github/lsposed/lspd/nativebridge/NativeAPI.java new file mode 100644 index 00000000..63692959 --- /dev/null +++ b/core/src/main/java/io/github/lsposed/lspd/nativebridge/NativeAPI.java @@ -0,0 +1,5 @@ +package io.github.lsposed.lspd.nativebridge; + +public class NativeAPI { + public static native void recordNativeEntrypoint(String library_name); +}