From c24cb0ae00fa590d6f883e738b894d69167d38be Mon Sep 17 00:00:00 2001 From: canyie Date: Tue, 1 Mar 2022 23:27:01 +0800 Subject: [PATCH] Support Zygisk --- app/build.gradle | 4 +- app/src/main/cpp/CMakeLists.txt | 1 + app/src/main/cpp/dreamland/zygisk_flavor.cpp | 50 +++ app/src/main/cpp/pine.h | 2 +- app/src/main/cpp/utils/scoped_elf.h | 4 +- app/src/main/cpp/zygisk.hpp | 326 +++++++++++++++++++ template/customize.sh | 95 +++--- template/languages.sh | 34 +- 8 files changed, 460 insertions(+), 56 deletions(-) create mode 100644 app/src/main/cpp/dreamland/zygisk_flavor.cpp create mode 100644 app/src/main/cpp/zygisk.hpp diff --git a/app/build.gradle b/app/build.gradle index 521bb66..ff02371 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -75,11 +75,11 @@ dependencies { def moduleProp = [ id: 'riru_dreamland', - name: 'Riru - Dreamland', + name: 'Dreamland', author: 'canyie', version: rootProject.ext.versionName + "_" + rootProject.ext.versionCode, versionCode: rootProject.ext.versionCode, - description: 'A third-party Xposed framework implementation, supports Android 7.0 ~ 11. Requires module \'Riru\' is installed. Telegram group: @DreamlandFramework, QQ group: 949888394.', + description: 'A third-party Xposed framework implementation, supports Android 7.0 ~ 12. Requires module \'Riru\' is installed or Zygisk is enabled. Telegram group: @DreamlandFramework, QQ group: 949888394.', minMagisk: rootProject.ext.minMagiskVersion, api: rootProject.ext.riruApiVersion ] diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index db11052..30d4317 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -23,6 +23,7 @@ add_library(riru_dreamland utils/well_known_classes.cpp dreamland/flavor.cpp dreamland/riru_flavor.cpp + dreamland/zygisk_flavor.cpp dreamland/dreamland.cpp dreamland/android.cpp dreamland/resources_hook.cpp diff --git a/app/src/main/cpp/dreamland/zygisk_flavor.cpp b/app/src/main/cpp/dreamland/zygisk_flavor.cpp new file mode 100644 index 0000000..716b8a0 --- /dev/null +++ b/app/src/main/cpp/dreamland/zygisk_flavor.cpp @@ -0,0 +1,50 @@ +// +// Created by canyie on 2022/2/28. +// + +#include "flavor.h" +#include "../zygisk.hpp" +#include "../utils/macros.h" + +using namespace dreamland; + +using zygisk::Api; +using zygisk::AppSpecializeArgs; +using zygisk::ServerSpecializeArgs; + +class DreamlandZygiskFlavor : public zygisk::ModuleBase { +public: + void onLoad(Api* api, JNIEnv* env) override { + this->api_ = api; + this->env_ = env; + skip_ = true; + Flavor::OnModuleLoaded(false); + } + + void preAppSpecialize(AppSpecializeArgs* args) override { + skip_ = Flavor::ShouldSkip(args->is_child_zygote && *args->is_child_zygote, args->uid); + if (!skip_) + Flavor::PreFork(env_, false); + } + + void postAppSpecialize(const AppSpecializeArgs* args) override { + /** FIXME: check if the zygote that created the child process is main zygote */ + if (skip_ || !Flavor::PostForkApp(env_, false)) + api_->setOption(zygisk::Option::DLCLOSE_MODULE_LIBRARY); + } + + void preServerSpecialize(ServerSpecializeArgs* args) override { + if (LIKELY(!Flavor::IsDisabled())) Flavor::PreFork(env_, true); + } + + void postServerSpecialize(const ServerSpecializeArgs* args) override { + if (!Flavor::IsDisabled()) Flavor::PostForkSystemServer(env_); + } + +private: + Api *api_; + JNIEnv *env_; + bool skip_; +}; + +REGISTER_ZYGISK_MODULE(DreamlandZygiskFlavor) diff --git a/app/src/main/cpp/pine.h b/app/src/main/cpp/pine.h index 2e97955..fd951f4 100644 --- a/app/src/main/cpp/pine.h +++ b/app/src/main/cpp/pine.h @@ -14,7 +14,7 @@ extern "C" { void PineSetAndroidVersion(int version); void* PineOpenElf(const char* elf); void PineCloseElf(void* handle); - void* PineGetElfSymbolAddress(void* handle, const char* symbol); + void* PineGetElfSymbolAddress(void* handle, const char* symbol, bool warn_if_missing); bool PineNativeInlineHookSymbolNoBackup(const char* elf, const char* symbol, void* replace); void PineNativeInlineHookFuncNoBackup(void* target, void* replace); }; diff --git a/app/src/main/cpp/utils/scoped_elf.h b/app/src/main/cpp/utils/scoped_elf.h index 7866ec3..55b9e9c 100644 --- a/app/src/main/cpp/utils/scoped_elf.h +++ b/app/src/main/cpp/utils/scoped_elf.h @@ -18,8 +18,8 @@ namespace dreamland { PineCloseElf(handle_); } - bool GetSymbolAddress(const char* symbol, void** out) { - *out = PineGetElfSymbolAddress(handle_, symbol); + bool GetSymbolAddress(const char* symbol, void** out, bool warn_if_missing = true) { + *out = PineGetElfSymbolAddress(handle_, symbol, warn_if_missing); return *out != nullptr; } diff --git a/app/src/main/cpp/zygisk.hpp b/app/src/main/cpp/zygisk.hpp new file mode 100644 index 0000000..a7383e5 --- /dev/null +++ b/app/src/main/cpp/zygisk.hpp @@ -0,0 +1,326 @@ +// This is the public API for Zygisk modules. +// DO NOT MODIFY ANY CODE IN THIS HEADER. + +#pragma once + +#include + +#define ZYGISK_API_VERSION 2 + +/* + +Define a class and inherit zygisk::ModuleBase to implement the functionality of your module. +Use the macro REGISTER_ZYGISK_MODULE(className) to register that class to Zygisk. + +Please note that modules will only be loaded after zygote has forked the child process. +THIS MEANS ALL OF YOUR CODE RUNS IN THE APP/SYSTEM SERVER PROCESS, NOT THE ZYGOTE DAEMON! + +Example code: + +static jint (*orig_logger_entry_max)(JNIEnv *env); +static jint my_logger_entry_max(JNIEnv *env) { return orig_logger_entry_max(env); } + +static void example_handler(int socket) { ... } + +class ExampleModule : public zygisk::ModuleBase { +public: + void onLoad(zygisk::Api *api, JNIEnv *env) override { + this->api = api; + this->env = env; + } + void preAppSpecialize(zygisk::AppSpecializeArgs *args) override { + JNINativeMethod methods[] = { + { "logger_entry_max_payload_native", "()I", (void*) my_logger_entry_max }, + }; + api->hookJniNativeMethods(env, "android/util/Log", methods, 1); + *(void **) &orig_logger_entry_max = methods[0].fnPtr; + } +private: + zygisk::Api *api; + JNIEnv *env; +}; + +REGISTER_ZYGISK_MODULE(ExampleModule) + +REGISTER_ZYGISK_COMPANION(example_handler) + +*/ + +namespace zygisk { + +struct Api; +struct AppSpecializeArgs; +struct ServerSpecializeArgs; + +class ModuleBase { +public: + + // This function is called when the module is loaded into the target process. + // A Zygisk API handle will be sent as an argument; call utility functions or interface + // with Zygisk through this handle. + virtual void onLoad([[maybe_unused]] Api *api, [[maybe_unused]] JNIEnv *env) {} + + // This function is called before the app process is specialized. + // At this point, the process just got forked from zygote, but no app specific specialization + // is applied. This means that the process does not have any sandbox restrictions and + // still runs with the same privilege of zygote. + // + // All the arguments that will be sent and used for app specialization is passed as a single + // AppSpecializeArgs object. You can read and overwrite these arguments to change how the app + // process will be specialized. + // + // If you need to run some operations as superuser, you can call Api::connectCompanion() to + // get a socket to do IPC calls with a root companion process. + // See Api::connectCompanion() for more info. + virtual void preAppSpecialize([[maybe_unused]] AppSpecializeArgs *args) {} + + // This function is called after the app process is specialized. + // At this point, the process has all sandbox restrictions enabled for this application. + // This means that this function runs as the same privilege of the app's own code. + virtual void postAppSpecialize([[maybe_unused]] const AppSpecializeArgs *args) {} + + // This function is called before the system server process is specialized. + // See preAppSpecialize(args) for more info. + virtual void preServerSpecialize([[maybe_unused]] ServerSpecializeArgs *args) {} + + // This function is called after the system server process is specialized. + // At this point, the process runs with the privilege of system_server. + virtual void postServerSpecialize([[maybe_unused]] const ServerSpecializeArgs *args) {} +}; + +struct AppSpecializeArgs { + // Required arguments. These arguments are guaranteed to exist on all Android versions. + jint &uid; + jint &gid; + jintArray &gids; + jint &runtime_flags; + jint &mount_external; + jstring &se_info; + jstring &nice_name; + jstring &instruction_set; + jstring &app_data_dir; + + // Optional arguments. Please check whether the pointer is null before de-referencing + jboolean *const is_child_zygote; + jboolean *const is_top_app; + jobjectArray *const pkg_data_info_list; + jobjectArray *const whitelisted_data_info_list; + jboolean *const mount_data_dirs; + jboolean *const mount_storage_dirs; + + AppSpecializeArgs() = delete; +}; + +struct ServerSpecializeArgs { + jint &uid; + jint &gid; + jintArray &gids; + jint &runtime_flags; + jlong &permitted_capabilities; + jlong &effective_capabilities; + + ServerSpecializeArgs() = delete; +}; + +namespace internal { +struct api_table; +template void entry_impl(api_table *, JNIEnv *); +} + +// These values are used in Api::setOption(Option) +enum Option : int { + // Force Magisk's denylist unmount routines to run on this process. + // + // Setting this option only makes sense in preAppSpecialize. + // The actual unmounting happens during app process specialization. + // + // Set this option to force all Magisk and modules' files to be unmounted from the + // mount namespace of the process, regardless of the denylist enforcement status. + FORCE_DENYLIST_UNMOUNT = 0, + + // When this option is set, your module's library will be dlclose-ed after post[XXX]Specialize. + // Be aware that after dlclose-ing your module, all of your code will be unmapped from memory. + // YOU MUST NOT ENABLE THIS OPTION AFTER HOOKING ANY FUNCTIONS IN THE PROCESS. + DLCLOSE_MODULE_LIBRARY = 1, +}; + +// Bit masks of the return value of Api::getFlags() +enum StateFlag : uint32_t { + // The user has granted root access to the current process + PROCESS_GRANTED_ROOT = (1u << 0), + + // The current process was added on the denylist + PROCESS_ON_DENYLIST = (1u << 1), +}; + +// All API functions will stop working after post[XXX]Specialize as Zygisk will be unloaded +// from the specialized process afterwards. +struct Api { + + // Connect to a root companion process and get a Unix domain socket for IPC. + // + // This API only works in the pre[XXX]Specialize functions due to SELinux restrictions. + // + // The pre[XXX]Specialize functions run with the same privilege of zygote. + // If you would like to do some operations with superuser permissions, register a handler + // function that would be called in the root process with REGISTER_ZYGISK_COMPANION(func). + // Another good use case for a companion process is that if you want to share some resources + // across multiple processes, hold the resources in the companion process and pass it over. + // + // The root companion process is ABI aware; that is, when calling this function from a 32-bit + // process, you will be connected to a 32-bit companion process, and vice versa for 64-bit. + // + // Returns a file descriptor to a socket that is connected to the socket passed to your + // module's companion request handler. Returns -1 if the connection attempt failed. + int connectCompanion(); + + // Get the file descriptor of the root folder of the current module. + // + // This API only works in the pre[XXX]Specialize functions. + // Accessing the directory returned is only possible in the pre[XXX]Specialize functions + // or in the root companion process (assuming that you sent the fd over the socket). + // Both restrictions are due to SELinux and UID. + // + // Returns -1 if errors occurred. + int getModuleDir(); + + // Set various options for your module. + // Please note that this function accepts one single option at a time. + // Check zygisk::Option for the full list of options available. + void setOption(Option opt); + + // Get information about the current process. + // Returns bitwise-or'd zygisk::StateFlag values. + uint32_t getFlags(); + + // Hook JNI native methods for a class + // + // Lookup all registered JNI native methods and replace it with your own functions. + // The original function pointer will be saved in each JNINativeMethod's fnPtr. + // If no matching class, method name, or signature is found, that specific JNINativeMethod.fnPtr + // will be set to nullptr. + void hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods); + + // For ELFs loaded in memory matching `regex`, replace function `symbol` with `newFunc`. + // If `oldFunc` is not nullptr, the original function pointer will be saved to `oldFunc`. + void pltHookRegister(const char *regex, const char *symbol, void *newFunc, void **oldFunc); + + // For ELFs loaded in memory matching `regex`, exclude hooks registered for `symbol`. + // If `symbol` is nullptr, then all symbols will be excluded. + void pltHookExclude(const char *regex, const char *symbol); + + // Commit all the hooks that was previously registered. + // Returns false if an error occurred. + bool pltHookCommit(); + +private: + internal::api_table *impl; + template friend void internal::entry_impl(internal::api_table *, JNIEnv *); +}; + +// Register a class as a Zygisk module + +#define REGISTER_ZYGISK_MODULE(clazz) \ +void zygisk_module_entry(zygisk::internal::api_table *table, JNIEnv *env) { \ + zygisk::internal::entry_impl(table, env); \ +} + +// Register a root companion request handler function for your module +// +// The function runs in a superuser daemon process and handles a root companion request from +// your module running in a target process. The function has to accept an integer value, +// which is a socket that is connected to the target process. +// See Api::connectCompanion() for more info. +// +// NOTE: the function can run concurrently on multiple threads. +// Be aware of race conditions if you have a globally shared resource. + +#define REGISTER_ZYGISK_COMPANION(func) \ +void zygisk_companion_entry(int client) { func(client); } + +/************************************************************************************ + * All the code after this point is internal code used to interface with Zygisk + * and guarantee ABI stability. You do not have to understand what it is doing. + ************************************************************************************/ + +namespace internal { + +struct module_abi { + long api_version; + ModuleBase *_this; + + void (*preAppSpecialize)(ModuleBase *, AppSpecializeArgs *); + void (*postAppSpecialize)(ModuleBase *, const AppSpecializeArgs *); + void (*preServerSpecialize)(ModuleBase *, ServerSpecializeArgs *); + void (*postServerSpecialize)(ModuleBase *, const ServerSpecializeArgs *); + + module_abi(ModuleBase *module) : api_version(ZYGISK_API_VERSION), _this(module) { + preAppSpecialize = [](auto self, auto args) { self->preAppSpecialize(args); }; + postAppSpecialize = [](auto self, auto args) { self->postAppSpecialize(args); }; + preServerSpecialize = [](auto self, auto args) { self->preServerSpecialize(args); }; + postServerSpecialize = [](auto self, auto args) { self->postServerSpecialize(args); }; + } +}; + +struct api_table { + // These first 2 entries are permanent, shall never change + void *_this; + bool (*registerModule)(api_table *, module_abi *); + + // Utility functions + void (*hookJniNativeMethods)(JNIEnv *, const char *, JNINativeMethod *, int); + void (*pltHookRegister)(const char *, const char *, void *, void **); + void (*pltHookExclude)(const char *, const char *); + bool (*pltHookCommit)(); + + // Zygisk functions + int (*connectCompanion)(void * /* _this */); + void (*setOption)(void * /* _this */, Option); + int (*getModuleDir)(void * /* _this */); + uint32_t (*getFlags)(void * /* _this */); +}; + +template +void entry_impl(api_table *table, JNIEnv *env) { + ModuleBase *module = new T(); + if (!table->registerModule(table, new module_abi(module))) + return; + auto api = new Api(); + api->impl = table; + module->onLoad(api, env); +} + +} // namespace internal + +inline int Api::connectCompanion() { + return impl->connectCompanion ? impl->connectCompanion(impl->_this) : -1; +} +inline int Api::getModuleDir() { + return impl->getModuleDir ? impl->getModuleDir(impl->_this) : -1; +} +inline void Api::setOption(Option opt) { + if (impl->setOption) impl->setOption(impl->_this, opt); +} +inline uint32_t Api::getFlags() { + return impl->getFlags ? impl->getFlags(impl->_this) : 0; +} +inline void Api::hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods) { + if (impl->hookJniNativeMethods) impl->hookJniNativeMethods(env, className, methods, numMethods); +} +inline void Api::pltHookRegister(const char *regex, const char *symbol, void *newFunc, void **oldFunc) { + if (impl->pltHookRegister) impl->pltHookRegister(regex, symbol, newFunc, oldFunc); +} +inline void Api::pltHookExclude(const char *regex, const char *symbol) { + if (impl->pltHookExclude) impl->pltHookExclude(regex, symbol); +} +inline bool Api::pltHookCommit() { + return impl->pltHookCommit != nullptr && impl->pltHookCommit(); +} + +} // namespace zygisk + +[[gnu::visibility("default")]] [[gnu::used]] +extern "C" void zygisk_module_entry(zygisk::internal::api_table *, JNIEnv *); + +[[gnu::visibility("default")]] [[gnu::used]] +extern "C" void zygisk_companion_entry(int); diff --git a/template/customize.sh b/template/customize.sh index 8969391..30b8dfd 100644 --- a/template/customize.sh +++ b/template/customize.sh @@ -24,35 +24,45 @@ else fi MAGISK_TMP=$(magisk --path) || MAGISK_TMP="/sbin" -MAGISK_CURRENT_RIRU_MODULE_PATH=$MAGISK_TMP/.magisk/modules/riru-core -if [ -f $MAGISK_CURRENT_RIRU_MODULE_PATH/util_functions.sh ]; then - # Riru V24+, api version is provided in util_functions.sh - # I don't like this, but I can only follow this change - RIRU_PATH=$MAGISK_CURRENT_RIRU_MODULE_PATH - ui_print "- Load $MAGISK_CURRENT_RIRU_MODULE_PATH/util_functions.sh" - # shellcheck disable=SC1090 - . $MAGISK_CURRENT_RIRU_MODULE_PATH/util_functions.sh - - # Pre Riru 25, as a old module - if [ "$RIRU_API" -lt 25 ]; then - ui_print "- Riru API version $RIRU_API is lower than v25" - RIRU_PATH=$RIRU_NEW_PATH - fi -elif [ -f "$RIRU_OLD_PATH/api_version.new" ] || [ -f "$RIRU_OLD_PATH/api_version" ]; then - RIRU_PATH="$RIRU_OLD_PATH" -elif [ -f "$RIRU_NEW_PATH/api_version.new" ] || [ -f "$RIRU_NEW_PATH/api_version" ]; then - RIRU_PATH="$RIRU_NEW_PATH" +if [ "$ZYGISK_ENABLED" = "1" ]; then + [ "$MAGISK_VER_CODE" -lt 24000 ] && abort "! $ERR_ZYGISK_REQUIRES_24" + FLAVOR="zygisk" + ui_print "- $ALERT_ZYGISK_FLAVOR" else - abort "! $ERR_RIRU_NOT_INSTALLED" -fi -RIRU_MODULE_PATH="$RIRU_PATH/modules/$RIRU_MODULE_ID" + ui_print "- $ALERT_RIRU_FLAVOR" + MAGISK_CURRENT_RIRU_MODULE_PATH=$MAGISK_TMP/.magisk/modules/riru-core + + if [ -f $MAGISK_CURRENT_RIRU_MODULE_PATH/util_functions.sh ]; then + # Riru V24+, api version is provided in util_functions.sh + # I don't like this, but I can only follow this change + RIRU_PATH=$MAGISK_CURRENT_RIRU_MODULE_PATH + ui_print "- Load $MAGISK_CURRENT_RIRU_MODULE_PATH/util_functions.sh" + # shellcheck disable=SC1090 + . $MAGISK_CURRENT_RIRU_MODULE_PATH/util_functions.sh + + # Pre Riru 25, as a old module + if [ "$RIRU_API" -lt 25 ]; then + ui_print "- Riru API version $RIRU_API is lower than v25" + RIRU_PATH=$RIRU_NEW_PATH + fi + elif [ -f "$RIRU_OLD_PATH/api_version.new" ] || [ -f "$RIRU_OLD_PATH/api_version" ]; then + RIRU_PATH="$RIRU_OLD_PATH" + elif [ -f "$RIRU_NEW_PATH/api_version.new" ] || [ -f "$RIRU_NEW_PATH/api_version" ]; then + RIRU_PATH="$RIRU_NEW_PATH" + else + abort "! $ERR_NO_FLAVOR" + fi + RIRU_MODULE_PATH="$RIRU_PATH/modules/$RIRU_MODULE_ID" -[ "$RIRU_API" -ne 0 ] || RIRU_API=$(cat "$RIRU_PATH/api_version.new") || RIRU_API=$(cat "$RIRU_PATH/api_version") -ui_print "- $ALERT_RIRU_API $RIRU_API" + [ "$RIRU_API" -ne 0 ] || RIRU_API=$(cat "$RIRU_PATH/api_version.new") || RIRU_API=$(cat "$RIRU_PATH/api_version") + ui_print "- $ALERT_RIRU_API $RIRU_API" -RIRU_MIN_API=$(grep_prop api "$TMPDIR/module.prop") -[ "$RIRU_API" -ge "$RIRU_MIN_API" ] || abort "! $ERR_UNSUPPORTED_RIRU_API $RIRU_API" + RIRU_MIN_API=$(grep_prop api "$TMPDIR/module.prop") + [ "$RIRU_API" -ge "$RIRU_MIN_API" ] || abort "! $ERR_UNSUPPORTED_RIRU_API $RIRU_API" + + FLAVOR="riru" +fi if [ "${BOOTMODE}" = "true" ]; then if [ "$(pm path 'top.canyie.dreamland.manager')" = "" ]; then @@ -76,20 +86,29 @@ if [ "$IS64BIT" = "false" ]; then rm -rf "$MODPATH/riru/lib64" fi -ui_print "- $ALERT_EXTRACT_RIRU_FILES" -if [ "$RIRU_API" -lt 25 ]; then - ui_print "- $ALERT_OLD_RIRU $RIRU_API" - mv -f "$MODPATH/riru/lib" "$MODPATH/system/" - [ -d "$MODPATH/riru/lib64" ] && mv -f "$MODPATH/riru/lib64" "$MODPATH/system/" 2>&1 - rm -rf "$MODPATH/riru" - [ -d $RIRU_MODULE_PATH ] || mkdir -p $RIRU_MODULE_PATH || abort "! Can't create $RIRU_MODULE_PATH: $?" - cp -f "$MODPATH/module.prop" "$RIRU_MODULE_PATH/module.prop" +ui_print "- $ALERT_FLAVOR_SPECIFC" +if [ "$FLAVOR" = "riru" ]; then + if [ "$RIRU_API" -lt 25 ]; then + ui_print "- $ALERT_OLD_RIRU $RIRU_API" + mv -f "$MODPATH/riru/lib" "$MODPATH/system/" + [ -d "$MODPATH/riru/lib64" ] && mv -f "$MODPATH/riru/lib64" "$MODPATH/system/" 2>&1 + rm -rf "$MODPATH/riru" + [ -d $RIRU_MODULE_PATH ] || mkdir -p $RIRU_MODULE_PATH || abort "! Can't create $RIRU_MODULE_PATH: $?" + cp -f "$MODPATH/module.prop" "$RIRU_MODULE_PATH/module.prop" + else + # Riru v25+, user may upgrade from old module without uninstall + # Remove the Riru v22's module path to make sure riru knews we're a new module + RIRU_22_MODULE_PATH="$RIRU_NEW_PATH/modules/$RIRU_MODULE_ID" + ui_print "- $ALERT_REMOVE_OLD_FOR_NEW_RIRU" + rm -rf "$RIRU_22_MODULE_PATH" + fi else - # Riru v25+, maybe the user upgrade from old module without uninstall - # Remove the Riru v22's module path to make sure riru knews we're a new module - RIRU_22_MODULE_PATH="$RIRU_NEW_PATH/modules/$RIRU_MODULE_ID" - ui_print "- $ALERT_REMOVE_OLD_FOR_NEW_RIRU" - rm -rf "$RIRU_22_MODULE_PATH" + mkdir -p "$MODPATH/zygisk" + mv -f "$MODPATH/riru/lib/libriru_dreamland.so" "$MODPATH/zygisk/armeabi-v7a.so" || abort "! $ERR_FLAVOR_SPECIFC" + [ -f "$MODPATH/riru/lib64/libriru_dreamland.so" ] && (mv -f "$MODPATH/riru/lib64/libriru_dreamland.so" "$MODPATH/zygisk/arm64-v8a.so" || abort "! $ERR_FLAVOR_SPECIFC") + + # Magisk won't load Riru modules if Zygisk enabled + rm -rf "$MODPATH/riru" || abort "! $ERR_FLAVOR_SPECIFC" fi ui_print "- $ALERT_PREPARE_LOCAL_DIR" diff --git a/template/languages.sh b/template/languages.sh index 6c68617..b5e69fe 100644 --- a/template/languages.sh +++ b/template/languages.sh @@ -7,27 +7,31 @@ fi if [ "$SIMPLIFIED_CHINESE" = "true" ]; then ALERT_ARCH="设备架构:" - ALERT_ANDROID_API="Android API级别:" - ALERT_RIRU_API="Riru API版本:" + ALERT_ANDROID_API="Android API 级别:" + ALERT_RIRU_API="Riru API 版本:" + ALERT_DETECTING_FLAVOR="正在检测安装环境" + ALERT_ZYGISK_FLAVOR="Zygisk 已启用,将安装为 Zygisk 版本" + ALERT_RIRU_FLAVOR="Zygisk 未启用,将安装为 Riru 版本" ALERT_EXTRACT_MODULE_FILES="正在解压模块文件" - ALERT_REMOVE_LIB64="正在移除64位支持库" - ALERT_EXTRACT_RIRU_FILES="正在初始化Riru模块文件" + ALERT_REMOVE_LIB64="正在移除 64 位支持库" + ALERT_FLAVOR_SPECIFC="开始 flavor 特定安装" ALERT_PREPARE_LOCAL_DIR="正在准备配置目录" - ALRET_REMOVE_SEPOLICY_1="Magisk版本低于20.2,正在移除sepolicy.rule" - ALRET_REMOVE_SEPOLICY_2="我们建议您升级Magisk" - ALERT_REBOOT_TWICE_1="Magisk版本低于21006" + ALRET_REMOVE_SEPOLICY_1="Magisk 版本低于 20.2,正在移除 sepolicy.rule" + ALRET_REMOVE_SEPOLICY_2="我们建议您升级 Magisk" + ALERT_REBOOT_TWICE_1="Magisk 版本低于 21006" ALERT_REBOOT_TWICE_2="您可能需要重启设备两次才能工作" ALERT_SETTING_PERMISSIONS="正在设置文件权限" - ALERT_OLD_RIRU="较旧的Riru API版本:" + ALERT_OLD_RIRU="较旧的 Riru API 版本:" ALERT_REMOVE_OLD_FOR_NEW_RIRU="Riru v25+,正在移除旧的模块路径" ERR_UNSUPPORTED_ARCH="不支持的设备架构:" ERR_UNSUPPORTED_ANDROID_API="不支持的Android API级别:" - ERR_RIRU_NOT_INSTALLED="请先安装模块 'Riru'" + ERR_ZYGISK_REQUIRES_24="Zygisk 版本只支持 Magisk v24+" + ERR_NO_FLAVOR="请在 Magisk app 中打开 Zygisk 并重启或安装模块 'Riru'" ERR_UNSUPPORTED_RIRU_API="不支持的 Riru API版本:" ERR_EXTRACT_MODULE_FILES="解压模块文件失败:" ERR_EXTRACT_SYSTEM_FOLDER="解压system目录失败:" - ERR_CREATE_RIRU_MODULE_PATH="创建riru模块路径失败:" + ERR_FLAVOR_SPECIFC="无法进行 flavor 特定安装:" ERR_COPY_PROP_TO_RIRU_MODULE_PATH="复制module.prop失败:" ERR_PREPARE_LOCAL_DIR="无法创建配置目录:" @@ -40,9 +44,12 @@ else ALERT_ARCH="Device architecture:" ALERT_ANDROID_API="Android API level:" ALERT_RIRU_API="Riru API version:" + ALERT_DETECTING_FLAVOR="Detecting installation flavor" + ALERT_ZYGISK_FLAVOR="Zygisk is enabled, installing as Zygisk flavor" + ALERT_RIRU_FLAVOR="Zygisk not enabled, installing as Riru flavor" ALERT_EXTRACT_MODULE_FILES="Extracting module files" ALERT_REMOVE_LIB64="Removing 64-bit libraries" - ALERT_EXTRACT_RIRU_FILES="Extracting riru files" + ALERT_FLAVOR_SPECIFC="Starting flavor specific installations" ALERT_PREPARE_LOCAL_DIR="Preparing local directory" ALRET_REMOVE_SEPOLICY_1="Removing sepolicy because of your Magisk version is lower than 20.2" ALRET_REMOVE_SEPOLICY_2="We recommend that you upgrade Magisk to the latest version" @@ -54,11 +61,12 @@ else ERR_UNSUPPORTED_ARCH="Unsupported architecture:" ERR_UNSUPPORTED_ANDROID_API="Unsupported Android API level" - ERR_RIRU_NOT_INSTALLED="Requirement module 'Riru' is not installed" + ERR_ZYGISK_REQUIRES_24="Zygisk flavor requires Magisk v24+" + ERR_NO_FLAVOR="Please turn on Zygisk from Magisk app and reboot, or install module 'Riru'" ERR_UNSUPPORTED_RIRU_API="Unsupported Riru API version" ERR_EXTRACT_MODULE_FILES="Can't extract module files:" ERR_EXTRACT_SYSTEM_FOLDER="Can't extract the system folder:" - ERR_CREATE_RIRU_MODULE_PATH="Can't create riru module path:" + ERR_FLAVOR_SPECIFC="Unable to do flavor specific installation" ERR_COPY_PROP_TO_RIRU_MODULE_PATH="Can't copy module.prop to the riru module path:" ERR_PREPARE_LOCAL_DIR="Can't create the local directory:"