diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4ca44d7..894f559 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -58,17 +58,6 @@ jobs: with: gradle-home-cache-cleanup: true - - name: Setup ccache - uses: hendrikmuhs/ccache-action@v1 - with: - max-size: 2G - key: lsp - restore-keys: lsp - save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - - - name: Setup Android SDK - uses: android-actions/setup-android@v3 - - name: Setup ninja uses: seanmiddleditch/gha-setup-ninja@master with: diff --git a/core b/core index bdba029..db9b97e 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit bdba029fe9ebde961a4e7f9047226d4d7258c233 +Subproject commit db9b97e53d39bb06d8ba706b74ccf01a80f2221c diff --git a/patch-loader/src/main/jni/include/art/runtime/jit/profile_saver.h b/patch-loader/src/main/jni/include/art/runtime/jit/profile_saver.h index ca54350..c6bcec9 100644 --- a/patch-loader/src/main/jni/include/art/runtime/jit/profile_saver.h +++ b/patch-loader/src/main/jni/include/art/runtime/jit/profile_saver.h @@ -10,47 +10,49 @@ using namespace lsplant; namespace art { - CREATE_MEM_HOOK_STUB_ENTRY( - "_ZN3art12ProfileSaver20ProcessProfilingInfoEbPt", - bool, ProcessProfilingInfo, (void * thiz, bool, uint16_t *), { - LOGD("skipped profile saving"); - return true; - }); +class ProfileSaver { +private: + inline static MemberHooker<"_ZN3art12ProfileSaver20ProcessProfilingInfoEbPt", ProfileSaver, + bool(bool, uint16_t *)> + ProcessProfilingInfo_ = +[](ProfileSaver *thiz, bool a, uint16_t *b) { + LOGD("skipped profile saving"); + return true; + }; - CREATE_MEM_HOOK_STUB_ENTRY( - "_ZN3art12ProfileSaver20ProcessProfilingInfoEbbPt", - bool, ProcessProfilingInfoWithBool, (void * thiz, bool, bool, uint16_t *), { - LOGD("skipped profile saving"); - return true; - }); + inline static MemberHooker<"_ZN3art12ProfileSaver20ProcessProfilingInfoEbbPt", ProfileSaver, + bool(bool, bool, uint16_t *)> + ProcessProfilingInfoWithBool_ = +[](ProfileSaver *thiz, bool, bool, uint16_t *) { + LOGD("skipped profile saving"); + return true; + }; - CREATE_HOOK_STUB_ENTRY( - "execve", - int, execve, (const char *pathname, const char *argv[], char *const envp[]), { - if (strstr(pathname, "dex2oat")) { - size_t count = 0; - while (argv[count++] != nullptr); - std::unique_ptr new_args = std::make_unique( - count + 1); - for (size_t i = 0; i < count - 1; ++i) - new_args[i] = argv[i]; - new_args[count - 1] = "--inline-max-code-units=0"; - new_args[count] = nullptr; + inline static Hooker<"execve", + int(const char *pathname, const char *argv[], char *const envp[])> + execve_ = +[](const char *pathname, const char *argv[], char *const envp[]) { + if (strstr(pathname, "dex2oat")) { + size_t count = 0; + while (argv[count++] != nullptr); + std::unique_ptr new_args = + std::make_unique(count + 1); + for (size_t i = 0; i < count - 1; ++i) new_args[i] = argv[i]; + new_args[count - 1] = "--inline-max-code-units=0"; + new_args[count] = nullptr; - LOGD("dex2oat by disable inline!"); - int ret = backup(pathname, new_args.get(), envp); - return ret; - } - int ret = backup(pathname, argv, envp); + LOGD("dex2oat by disable inline!"); + int ret = execve_(pathname, new_args.get(), envp); return ret; - }); - + } + int ret = execve_(pathname, argv, envp); + return ret; + }; +public: static void DisableInline(const HookHandler &handler) { - HookSyms(handler, ProcessProfilingInfo, ProcessProfilingInfoWithBool); - HookSymNoHandle(handler, reinterpret_cast(&::execve), execve); + handler.hook(ProcessProfilingInfo_); + handler.hook(ProcessProfilingInfoWithBool_); + handler.hook(execve_); } -} +}; +} // namespace art - -#endif //LSPATCH_PROFILE_SAVER_H +#endif // LSPATCH_PROFILE_SAVER_H diff --git a/patch-loader/src/main/jni/include/art/runtime/oat_file_manager.h b/patch-loader/src/main/jni/include/art/runtime/oat_file_manager.h index d72be48..2f904d5 100644 --- a/patch-loader/src/main/jni/include/art/runtime/oat_file_manager.h +++ b/patch-loader/src/main/jni/include/art/runtime/oat_file_manager.h @@ -26,39 +26,46 @@ using namespace lsplant; namespace art { - CREATE_MEM_HOOK_STUB_ENTRY( - "_ZN3art14OatFileManager25RunBackgroundVerificationERKNSt3__16vectorIPKNS_7DexFileENS1_9allocatorIS5_EEEEP8_jobjectPKc", - void, RunBackgroundVerificationWithContext, - (void * thiz, const std::vector &dex_files, - jobject class_loader, - const char *class_loader_context), { +class FileManager { +public: + inline static MemberHooker< + "_ZN3art14OatFileManager25RunBackgroundVerificationERKNSt3__" + "16vectorIPKNS_7DexFileENS1_9allocatorIS5_EEEEP8_jobjectPKc", + FileManager, void(const std::vector &, jobject, const char *)> + RunBackgroundVerificationWithContext_ = + +[](FileManager *thiz, const std::vector &dex_files, jobject class_loader, + const char *class_loader_context) { if (lspd::Context::GetInstance()->GetCurrentClassLoader() == nullptr) { LOGD("Disabled background verification"); return; } - backup(thiz, dex_files, class_loader, class_loader_context); - }); + RunBackgroundVerificationWithContext_(thiz, dex_files, class_loader, + class_loader_context); + }; - CREATE_MEM_HOOK_STUB_ENTRY( - "_ZN3art14OatFileManager25RunBackgroundVerificationERKNSt3__16vectorIPKNS_7DexFileENS1_9allocatorIS5_EEEEP8_jobject", - void, RunBackgroundVerification, - (void * thiz, const std::vector &dex_files, - jobject class_loader), { + inline static MemberHooker< + "_ZN3art14OatFileManager25RunBackgroundVerificationERKNSt3__" + "16vectorIPKNS_7DexFileENS1_9allocatorIS5_EEEEP8_jobject", + FileManager, void(const std::vector &, jobject)> + RunBackgroundVerification_ = + +[](FileManager *thiz, const std::vector &dex_files, + jobject class_loader) { if (lspd::Context::GetInstance()->GetCurrentClassLoader() == nullptr) { LOGD("Disabled background verification"); return; } - backup(thiz, dex_files, class_loader); - }); - + RunBackgroundVerification_(thiz, dex_files, class_loader); + }; +public: static void DisableBackgroundVerification(const lsplant::HookHandler &handler) { const int api_level = lspd::GetAndroidApiLevel(); if (api_level >= __ANDROID_API_Q__) { - HookSyms(handler, RunBackgroundVerificationWithContext, RunBackgroundVerification); + handler.hook(RunBackgroundVerificationWithContext_); + handler.hook(RunBackgroundVerification_); } } -} +}; +} // namespace art - -#endif //LSPATCH_OAT_FILE_MANAGER_H +#endif // LSPATCH_OAT_FILE_MANAGER_H diff --git a/patch-loader/src/main/jni/src/jni/bypass_sig.cpp b/patch-loader/src/main/jni/src/jni/bypass_sig.cpp index c546fbc..8b371c9 100644 --- a/patch-loader/src/main/jni/src/jni/bypass_sig.cpp +++ b/patch-loader/src/main/jni/src/jni/bypass_sig.cpp @@ -2,6 +2,7 @@ // Created by VIP on 2021/4/25. // +#include "../src/native_api.h" #include "bypass_sig.h" #include "elf_util.h" #include "logging.h" @@ -12,40 +13,46 @@ namespace lspd { - std::string apkPath; - std::string redirectPath; +std::string apkPath; +std::string redirectPath; - CREATE_HOOK_STUB_ENTRY( - "__openat", - int, __openat, - (int fd, const char* pathname, int flag, int mode), { - if (pathname == apkPath) { - LOGD("redirect openat"); - return backup(fd, redirectPath.c_str(), flag, mode); - } - return backup(fd, pathname, flag, mode); - }); - - LSP_DEF_NATIVE_METHOD(void, SigBypass, enableOpenatHook, jstring origApkPath, jstring cacheApkPath) { - auto sym_openat = SandHook::ElfImg("libc.so").getSymbAddress("__openat"); - auto r = HookSymNoHandle(handler, sym_openat, __openat); - if (!r) { - LOGE("Hook __openat fail"); - return; +inline static lsplant::Hooker<"__openat", int(int, const char*, int flag, int)> __openat_ = + +[](int fd, const char* pathname, int flag, int mode) { + if (pathname == apkPath) { + LOGD("redirect openat"); + return __openat_(fd, redirectPath.c_str(), flag, mode); } - lsplant::JUTFString str1(env, origApkPath); - lsplant::JUTFString str2(env, cacheApkPath); - apkPath = str1.get(); - redirectPath = str2.get(); - LOGD("apkPath %s", apkPath.c_str()); - LOGD("redirectPath %s", redirectPath.c_str()); - } - - static JNINativeMethod gMethods[] = { - LSP_NATIVE_METHOD(SigBypass, enableOpenatHook, "(Ljava/lang/String;Ljava/lang/String;)V") + return __openat_(fd, pathname, flag, mode); }; - void RegisterBypass(JNIEnv* env) { - REGISTER_LSP_NATIVE_METHODS(SigBypass); +bool HookOpenat(const lsplant::HookHandler& handler) { return handler.hook(__openat_); } + +LSP_DEF_NATIVE_METHOD(void, SigBypass, enableOpenatHook, jstring origApkPath, + jstring cacheApkPath) { + auto r = HookOpenat(lsplant::InitInfo{ + .inline_hooker = + [](auto t, auto r) { + void* bk = nullptr; + return HookInline(t, r, &bk) == 0 ? bk : nullptr; + }, + .art_symbol_resolver = + [](auto symbol) { return SandHook::ElfImg("libc.so").getSymbAddress(symbol); }, + }); + if (!r) { + LOGE("Hook __openat fail"); + return; } + lsplant::JUTFString str1(env, origApkPath); + lsplant::JUTFString str2(env, cacheApkPath); + apkPath = str1.get(); + redirectPath = str2.get(); + LOGD("apkPath %s", apkPath.c_str()); + LOGD("redirectPath %s", redirectPath.c_str()); } + +static JNINativeMethod gMethods[] = { + LSP_NATIVE_METHOD(SigBypass, enableOpenatHook, "(Ljava/lang/String;Ljava/lang/String;)V")}; + +void RegisterBypass(JNIEnv* env) { REGISTER_LSP_NATIVE_METHODS(SigBypass); } + +} // namespace lspd diff --git a/patch-loader/src/main/jni/src/patch_loader.cpp b/patch-loader/src/main/jni/src/patch_loader.cpp index fd96281..97a3053 100644 --- a/patch-loader/src/main/jni/src/patch_loader.cpp +++ b/patch-loader/src/main/jni/src/patch_loader.cpp @@ -21,12 +21,13 @@ // Created by Nullptr on 2022/3/17. // -#include "art/runtime/oat_file_manager.h" +#include "patch_loader.h" + #include "art/runtime/jit/profile_saver.h" +#include "art/runtime/oat_file_manager.h" #include "elf_util.h" #include "jni/bypass_sig.h" #include "native_util.h" -#include "patch_loader.h" #include "symbol_cache.h" #include "utils/jni_helper.hpp" @@ -34,93 +35,95 @@ using namespace lsplant; namespace lspd { - void PatchLoader::LoadDex(JNIEnv* env, Context::PreloadedDex&& dex) { - auto class_activity_thread = JNI_FindClass(env, "android/app/ActivityThread"); - auto class_activity_thread_app_bind_data = JNI_FindClass(env, "android/app/ActivityThread$AppBindData"); - auto class_loaded_apk = JNI_FindClass(env, "android/app/LoadedApk"); +void PatchLoader::LoadDex(JNIEnv* env, Context::PreloadedDex&& dex) { + auto class_activity_thread = JNI_FindClass(env, "android/app/ActivityThread"); + auto class_activity_thread_app_bind_data = + JNI_FindClass(env, "android/app/ActivityThread$AppBindData"); + auto class_loaded_apk = JNI_FindClass(env, "android/app/LoadedApk"); - auto mid_current_activity_thread = JNI_GetStaticMethodID(env, class_activity_thread, "currentActivityThread", - "()Landroid/app/ActivityThread;"); - auto mid_get_classloader = JNI_GetMethodID(env, class_loaded_apk, "getClassLoader", "()Ljava/lang/ClassLoader;"); - auto fid_m_bound_application = JNI_GetFieldID(env, class_activity_thread, "mBoundApplication", - "Landroid/app/ActivityThread$AppBindData;"); - auto fid_info = JNI_GetFieldID(env, class_activity_thread_app_bind_data, "info", "Landroid/app/LoadedApk;"); + auto mid_current_activity_thread = JNI_GetStaticMethodID( + env, class_activity_thread, "currentActivityThread", "()Landroid/app/ActivityThread;"); + auto mid_get_classloader = + JNI_GetMethodID(env, class_loaded_apk, "getClassLoader", "()Ljava/lang/ClassLoader;"); + auto fid_m_bound_application = JNI_GetFieldID(env, class_activity_thread, "mBoundApplication", + "Landroid/app/ActivityThread$AppBindData;"); + auto fid_info = + JNI_GetFieldID(env, class_activity_thread_app_bind_data, "info", "Landroid/app/LoadedApk;"); - auto activity_thread = JNI_CallStaticObjectMethod(env, class_activity_thread, mid_current_activity_thread); - auto m_bound_application = JNI_GetObjectField(env, activity_thread, fid_m_bound_application); - auto info = JNI_GetObjectField(env, m_bound_application, fid_info); - auto stub_classloader = JNI_CallObjectMethod(env, info, mid_get_classloader); + auto activity_thread = + JNI_CallStaticObjectMethod(env, class_activity_thread, mid_current_activity_thread); + auto m_bound_application = JNI_GetObjectField(env, activity_thread, fid_m_bound_application); + auto info = JNI_GetObjectField(env, m_bound_application, fid_info); + auto stub_classloader = JNI_CallObjectMethod(env, info, mid_get_classloader); - if (!stub_classloader) [[unlikely]] { - LOGE("getStubClassLoader failed!!!"); - return; - } - - auto in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader"); - auto mid_init = 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(dex.data(), dex.size()); - if (auto my_cl = JNI_NewObject(env, in_memory_classloader, mid_init, dex_buffer, stub_classloader)) { - inject_class_loader_ = JNI_NewGlobalRef(env, my_cl); - } else { - LOGE("InMemoryDexClassLoader creation failed!!!"); - return; - } - - env->DeleteLocalRef(dex_buffer); + if (!stub_classloader) [[unlikely]] { + LOGE("getStubClassLoader failed!!!"); + return; } - void PatchLoader::InitArtHooker(JNIEnv* env, const InitInfo& initInfo) { - Context::InitArtHooker(env, initInfo); - handler = initInfo; - art::DisableInline(initInfo); - art::DisableBackgroundVerification(initInfo); + auto in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader"); + auto mid_init = 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(dex.data(), dex.size()); + if (auto my_cl = + JNI_NewObject(env, in_memory_classloader, mid_init, dex_buffer, stub_classloader)) { + inject_class_loader_ = JNI_NewGlobalRef(env, my_cl); + } else { + LOGE("InMemoryDexClassLoader creation failed!!!"); + return; } - void PatchLoader::InitHooks(JNIEnv* env) { - Context::InitHooks(env); - RegisterBypass(env); + env->DeleteLocalRef(dex_buffer); +} + +void PatchLoader::InitArtHooker(JNIEnv* env, const InitInfo& initInfo) { + Context::InitArtHooker(env, initInfo); + handler = initInfo; + art::ProfileSaver::DisableInline(initInfo); + art::FileManager::DisableBackgroundVerification(initInfo); +} + +void PatchLoader::InitHooks(JNIEnv* env) { + Context::InitHooks(env); + RegisterBypass(env); +} + +void PatchLoader::SetupEntryClass(JNIEnv* env) { + if (auto entry_class = FindClassFromLoader(env, GetCurrentClassLoader(), + "org.lsposed.lspatch.loader.LSPApplication")) { + entry_class_ = JNI_NewGlobalRef(env, entry_class); } +} - void PatchLoader::SetupEntryClass(JNIEnv* env) { - if (auto entry_class = FindClassFromLoader(env, GetCurrentClassLoader(), - "org.lsposed.lspatch.loader.LSPApplication")) { - entry_class_ = JNI_NewGlobalRef(env, entry_class); - } - } +void PatchLoader::Load(JNIEnv* env) { + /* InitSymbolCache(nullptr); */ + lsplant::InitInfo initInfo{ + .inline_hooker = + [](auto t, auto r) { + void* bk = nullptr; + return HookInline(t, r, &bk) == 0 ? bk : nullptr; + }, + .inline_unhooker = [](auto t) { return UnhookInline(t) == 0; }, + .art_symbol_resolver = [](auto symbol) { return GetArt()->getSymbAddress(symbol); }, + .art_symbol_prefix_resolver = + [](auto symbol) { return GetArt()->getSymbPrefixFirstAddress(symbol); }, + }; - void PatchLoader::Load(JNIEnv* env) { - /* InitSymbolCache(nullptr); */ - lsplant::InitInfo initInfo { - .inline_hooker = [](auto t, auto r) { - void* bk = nullptr; - return HookFunction(t, r, &bk) == RS_SUCCESS ? bk : nullptr; - }, - .inline_unhooker = [](auto t) { - return UnhookFunction(t) == RT_SUCCESS; - }, - .art_symbol_resolver = [](auto symbol) { - return GetArt()->getSymbAddress(symbol); - }, - .art_symbol_prefix_resolver = [](auto symbol) { - return GetArt()->getSymbPrefixFirstAddress(symbol); - }, - }; + auto stub = JNI_FindClass(env, "org/lsposed/lspatch/metaloader/LSPAppComponentFactoryStub"); + auto dex_field = JNI_GetStaticFieldID(env, stub, "dex", "[B"); - auto stub = JNI_FindClass(env, "org/lsposed/lspatch/metaloader/LSPAppComponentFactoryStub"); - auto dex_field = JNI_GetStaticFieldID(env, stub, "dex", "[B"); + ScopedLocalRef array = JNI_GetStaticObjectField(env, stub, dex_field); + auto dex = PreloadedDex{env->GetByteArrayElements(array.get(), nullptr), + static_cast(JNI_GetArrayLength(env, array))}; - ScopedLocalRef array = JNI_GetStaticObjectField(env, stub, dex_field); - auto dex = PreloadedDex {env->GetByteArrayElements(array.get(), nullptr), static_cast(JNI_GetArrayLength(env, array))}; + InitArtHooker(env, initInfo); + LoadDex(env, std::move(dex)); + InitHooks(env); - InitArtHooker(env, initInfo); - LoadDex(env, std::move(dex)); - InitHooks(env); + GetArt(true); - GetArt(true); - - SetupEntryClass(env); - FindAndCall(env, "onLoad", "()V"); - } -} // namespace lspd + SetupEntryClass(env); + FindAndCall(env, "onLoad", "()V"); +} +} // namespace lspd diff --git a/settings.gradle.kts b/settings.gradle.kts index 3657cd5..9364f78 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -31,9 +31,10 @@ dependencyResolutionManagement { rootProject.name = "LSPatch" include( + ":apache", ":apkzlib", - ":core", ":axml", + ":core", ":hiddenapi:bridge", ":hiddenapi:stubs", ":jar", @@ -48,8 +49,9 @@ include( ":share:java", ) -project(":core").projectDir = file("core/core") +project(":apache").projectDir = file("core/apache") project(":axml").projectDir = file("core/axml") +project(":core").projectDir = file("core/core") project(":hiddenapi:bridge").projectDir = file("core/hiddenapi/bridge") project(":hiddenapi:stubs").projectDir = file("core/hiddenapi/stubs") project(":services:daemon-service").projectDir = file("core/services/daemon-service")