diff --git a/native/src/zygisk/api.hpp b/native/src/zygisk/api.hpp index f1c9f68c2..65cdf9001 100644 --- a/native/src/zygisk/api.hpp +++ b/native/src/zygisk/api.hpp @@ -220,7 +220,7 @@ struct Api { bool pltHookCommit(); private: - internal::api_table *impl; + internal::api_table *tbl; template friend void internal::entry_impl(internal::api_table *, JNIEnv *); }; @@ -244,46 +244,43 @@ void zygisk_module_entry(zygisk::internal::api_table *table, JNIEnv *env) { \ #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. - ************************************************************************************/ +/********************************************************* + * The following is internal ABI implementation detail. + * You do not have to understand what it is doing. + *********************************************************/ namespace internal { struct module_abi { long api_version; - ModuleBase *_this; + ModuleBase *impl; 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); }; + module_abi(ModuleBase *module) : api_version(ZYGISK_API_VERSION), impl(module) { + preAppSpecialize = [](auto m, auto args) { m->preAppSpecialize(args); }; + postAppSpecialize = [](auto m, auto args) { m->postAppSpecialize(args); }; + preServerSpecialize = [](auto m, auto args) { m->preServerSpecialize(args); }; + postServerSpecialize = [](auto m, auto args) { m->postServerSpecialize(args); }; } }; struct api_table { - // These first 2 entries are permanent, shall never change - void *_this; + // Base + void *impl; 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 */); + int (*connectCompanion)(void * /* impl */); + void (*setOption)(void * /* impl */, Option); + int (*getModuleDir)(void * /* impl */); + uint32_t (*getFlags)(void * /* impl */); }; template @@ -292,35 +289,35 @@ void entry_impl(api_table *table, JNIEnv *env) { if (!table->registerModule(table, new module_abi(module))) return; auto api = new Api(); - api->impl = table; + api->tbl = table; module->onLoad(api, env); } } // namespace internal inline int Api::connectCompanion() { - return impl->connectCompanion ? impl->connectCompanion(impl->_this) : -1; + return tbl->connectCompanion ? tbl->connectCompanion(tbl->impl) : -1; } inline int Api::getModuleDir() { - return impl->getModuleDir ? impl->getModuleDir(impl->_this) : -1; + return tbl->getModuleDir ? tbl->getModuleDir(tbl->impl) : -1; } inline void Api::setOption(Option opt) { - if (impl->setOption) impl->setOption(impl->_this, opt); + if (tbl->setOption) tbl->setOption(tbl->impl, opt); } inline uint32_t Api::getFlags() { - return impl->getFlags ? impl->getFlags(impl->_this) : 0; + return tbl->getFlags ? tbl->getFlags(tbl->impl) : 0; } inline void Api::hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods) { - if (impl->hookJniNativeMethods) impl->hookJniNativeMethods(env, className, methods, numMethods); + if (tbl->hookJniNativeMethods) tbl->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); + if (tbl->pltHookRegister) tbl->pltHookRegister(regex, symbol, newFunc, oldFunc); } inline void Api::pltHookExclude(const char *regex, const char *symbol) { - if (impl->pltHookExclude) impl->pltHookExclude(regex, symbol); + if (tbl->pltHookExclude) tbl->pltHookExclude(regex, symbol); } inline bool Api::pltHookCommit() { - return impl->pltHookCommit != nullptr && impl->pltHookCommit(); + return tbl->pltHookCommit != nullptr && tbl->pltHookCommit(); } } // namespace zygisk diff --git a/native/src/zygisk/gen_jni_hooks.py b/native/src/zygisk/gen_jni_hooks.py index 8a5b70d19..d6ce38875 100755 --- a/native/src/zygisk/gen_jni_hooks.py +++ b/native/src/zygisk/gen_jni_hooks.py @@ -97,7 +97,7 @@ class ForkAndSpec(JNIHook): decl += ind(1) + f'args.{a.name} = &{a.name};' decl += ind(1) + 'HookContext ctx;' decl += ind(1) + 'ctx.env = env;' - decl += ind(1) + 'ctx.raw_args = &args;' + decl += ind(1) + 'ctx.args = { &args };' decl += ind(1) + f'ctx.{self.base_name()}_pre();' decl += ind(1) + self.orig_method() + '(' decl += ind(2) + f'env, clazz, {self.name_list()}' diff --git a/native/src/zygisk/hook.cpp b/native/src/zygisk/hook.cpp index 1d237eed6..a1dcbf3c8 100644 --- a/native/src/zygisk/hook.cpp +++ b/native/src/zygisk/hook.cpp @@ -43,10 +43,10 @@ void name##_post(); struct HookContext { JNIEnv *env; union { - AppSpecializeArgs_v3 *args; - ServerSpecializeArgs_v1 *server_args; - void *raw_args; - }; + void *ptr; + AppSpecializeArgs_v3 *app; + ServerSpecializeArgs_v1 *server; + } args; const char *process; vector modules; bitset state; @@ -54,7 +54,7 @@ struct HookContext { int pid; uint32_t flags; - HookContext() : pid(-1), flags(0) {} + HookContext() : env(nullptr), args{nullptr}, process(nullptr), pid(-1), flags(0) {} static void close_fds(); void unload_zygisk(); @@ -280,39 +280,49 @@ void hookJniNativeMethods(JNIEnv *env, const char *clz, JNINativeMethod *methods } ZygiskModule::ZygiskModule(int id, void *handle, void *entry) -: raw_entry(entry), api(this), id(id), handle(handle) {} +: id(id), handle(handle), entry{entry}, api{}, mod{nullptr} { + // Make sure all pointers are null + memset(&api, 0, sizeof(api)); + api.base.impl = this; + api.base.registerModule = &ZygiskModule::RegisterModule; +} -ApiTable::ApiTable(ZygiskModule *m) -: module(m), registerModule(&ZygiskModule::RegisterModule) {} - -bool ZygiskModule::RegisterModule(ApiTable *table, long *module) { - long ver = *module; +bool ZygiskModule::RegisterModule(api_abi_base *api, long *module) { + long api_version = *module; // Unsupported version - if (ver > ZYGISK_API_VERSION) + if (api_version > ZYGISK_API_VERSION) return false; // Set the actual module_abi* - table->module->ver = module; + api->impl->mod = { module }; // Fill in API accordingly with module API version - switch (ver) { + switch (api_version) { case 3: - case 2: - table->v2.getModuleDir = [](ZygiskModule *m) { return m->getModuleDir(); }; - table->v2.getFlags = [](auto) { return ZygiskModule::getFlags(); }; + case 2: { + auto v2 = static_cast(api); + v2->getModuleDir = [](ZygiskModule *m) { return m->getModuleDir(); }; + v2->getFlags = [](auto) { return ZygiskModule::getFlags(); }; + } // fallthrough - case 1: - table->v1.hookJniNativeMethods = &hookJniNativeMethods; - table->v1.pltHookRegister = [](const char *p, const char *s, void *n, void **o) { + case 1: { + auto v1 = static_cast(api); + v1->hookJniNativeMethods = &hookJniNativeMethods; + v1->pltHookRegister = [](const char *p, const char *s, void *n, void **o) { xhook_register(p, s, n, o); }; - table->v1.pltHookExclude = [](const char *p, const char *s) { + v1->pltHookExclude = [](const char *p, const char *s) { xhook_ignore(p, s); }; - table->v1.pltHookCommit = []{ bool r = xhook_refresh(0) == 0; xhook_clear(); return r; }; - table->v1.connectCompanion = [](ZygiskModule *m) { return m->connectCompanion(); }; - table->v1.setOption = [](ZygiskModule *m, auto opt) { m->setOption(opt); }; + v1->pltHookCommit = [] { + bool r = xhook_refresh(0) == 0; + xhook_clear(); + return r; + }; + v1->connectCompanion = [](ZygiskModule *m) { return m->connectCompanion(); }; + v1->setOption = [](ZygiskModule *m, auto opt) { m->setOption(opt); }; break; + } default: // Unknown version number return false; @@ -395,17 +405,17 @@ void HookContext::run_modules_pre(const vector &fds) { } for (auto &m : modules) { - m.entry(&m.api, env); + m.onLoad(env); if (state[APP_SPECIALIZE]) { - m.preAppSpecialize(args); + m.preAppSpecialize(args.app); } else if (state[SERVER_SPECIALIZE]) { - m.preServerSpecialize(server_args); + m.preServerSpecialize(args.server); } } // Add all ignored fd onto whitelist - if (state[APP_SPECIALIZE] && args->fds_to_ignore) { - if (jintArray fdsToIgnore = *args->fds_to_ignore) { + if (state[APP_SPECIALIZE] && args.app->fds_to_ignore) { + if (jintArray fdsToIgnore = *args.app->fds_to_ignore) { int len = env->GetArrayLength(fdsToIgnore); int *arr = env->GetIntArrayElements(fdsToIgnore, nullptr); for (int i = 0; i < len; ++i) { @@ -431,11 +441,11 @@ void HookContext::run_modules_pre(const vector &fds) { void HookContext::run_modules_post() { for (const auto &m : modules) { if (state[APP_SPECIALIZE]) { - m.postAppSpecialize(args); + m.postAppSpecialize(args.app); } else if (state[SERVER_SPECIALIZE]) { - m.postServerSpecialize(server_args); + m.postServerSpecialize(args.server); } - m.doUnload(); + m.tryUnload(); } } @@ -452,7 +462,7 @@ void HookContext::unload_zygisk() { // Strip out all API function pointers for (auto &m : modules) { - memset(&m.api, 0, sizeof(m.api)); + m.clearApi(); } new_daemon_thread(reinterpret_cast(&dlclose), self_handle); @@ -464,7 +474,7 @@ void HookContext::unload_zygisk() { void HookContext::nativeSpecializeAppProcess_pre() { g_ctx = this; state[APP_SPECIALIZE] = true; - process = env->GetStringUTFChars(args->nice_name, nullptr); + process = env->GetStringUTFChars(args.app->nice_name, nullptr); if (state[FORK_AND_SPECIALIZE]) { ZLOGV("pre forkAndSpecialize [%s]\n", process); } else { @@ -472,7 +482,7 @@ void HookContext::nativeSpecializeAppProcess_pre() { } vector module_fds; - int fd = remote_get_info(args->uid, process, &flags, module_fds); + int fd = remote_get_info(args.app->uid, process, &flags, module_fds); if ((flags & UNMOUNT_MASK) == UNMOUNT_MASK) { ZLOGI("[%s] is on the denylist\n", process); state[DO_UNMOUNT] = true; @@ -492,7 +502,7 @@ void HookContext::nativeSpecializeAppProcess_post() { ZLOGV("post specialize [%s]\n", process); } - env->ReleaseStringUTFChars(args->nice_name, process); + env->ReleaseStringUTFChars(args.app->nice_name, process); run_modules_post(); if (flags & PROCESS_IS_MAGISK_APP) { setenv("ZYGISK_ENABLED", "1", 1); diff --git a/native/src/zygisk/jni_hooks.hpp b/native/src/zygisk/jni_hooks.hpp index 6d25a1b26..bb5266ebf 100644 --- a/native/src/zygisk/jni_hooks.hpp +++ b/native/src/zygisk/jni_hooks.hpp @@ -7,7 +7,7 @@ jint nativeForkAndSpecialize_l(JNIEnv *env, jclass clazz, jint uid, jint gid, ji AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir); HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, instruction_set, app_data_dir @@ -20,7 +20,7 @@ jint nativeForkAndSpecialize_o(JNIEnv *env, jclass clazz, jint uid, jint gid, ji args.fds_to_ignore = &fds_to_ignore; HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, instruction_set, app_data_dir @@ -34,7 +34,7 @@ jint nativeForkAndSpecialize_p(JNIEnv *env, jclass clazz, jint uid, jint gid, ji args.is_child_zygote = &is_child_zygote; HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir @@ -49,7 +49,7 @@ jint nativeForkAndSpecialize_q_alt(JNIEnv *env, jclass clazz, jint uid, jint gid args.is_top_app = &is_top_app; HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app @@ -68,7 +68,7 @@ jint nativeForkAndSpecialize_r(JNIEnv *env, jclass clazz, jint uid, jint gid, ji args.mount_storage_dirs = &mount_storage_dirs; HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs @@ -80,7 +80,7 @@ jint nativeForkAndSpecialize_samsung_m(JNIEnv *env, jclass clazz, jint uid, jint AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir); HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _0, _1, nice_name, fds_to_close, instruction_set, app_data_dir @@ -92,7 +92,7 @@ jint nativeForkAndSpecialize_samsung_n(JNIEnv *env, jclass clazz, jint uid, jint AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir); HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _2, _3, nice_name, fds_to_close, instruction_set, app_data_dir, _4 @@ -105,7 +105,7 @@ jint nativeForkAndSpecialize_samsung_o(JNIEnv *env, jclass clazz, jint uid, jint args.fds_to_ignore = &fds_to_ignore; HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _5, _6, nice_name, fds_to_close, fds_to_ignore, instruction_set, app_data_dir @@ -119,7 +119,7 @@ jint nativeForkAndSpecialize_samsung_p(JNIEnv *env, jclass clazz, jint uid, jint args.is_child_zygote = &is_child_zygote; HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _7, _8, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir @@ -182,7 +182,7 @@ void nativeSpecializeAppProcess_q(JNIEnv *env, jclass clazz, jint uid, jint gid, args.is_child_zygote = &is_child_zygote; HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeSpecializeAppProcess_pre(); reinterpret_cast(nativeSpecializeAppProcess_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, is_child_zygote, instruction_set, app_data_dir @@ -195,7 +195,7 @@ void nativeSpecializeAppProcess_q_alt(JNIEnv *env, jclass clazz, jint uid, jint args.is_top_app = &is_top_app; HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeSpecializeAppProcess_pre(); reinterpret_cast(nativeSpecializeAppProcess_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, is_child_zygote, instruction_set, app_data_dir, is_top_app @@ -212,7 +212,7 @@ void nativeSpecializeAppProcess_r(JNIEnv *env, jclass clazz, jint uid, jint gid, args.mount_storage_dirs = &mount_storage_dirs; HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeSpecializeAppProcess_pre(); reinterpret_cast(nativeSpecializeAppProcess_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs @@ -224,7 +224,7 @@ void nativeSpecializeAppProcess_samsung_q(JNIEnv *env, jclass clazz, jint uid, j args.is_child_zygote = &is_child_zygote; HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeSpecializeAppProcess_pre(); reinterpret_cast(nativeSpecializeAppProcess_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _9, _10, nice_name, is_child_zygote, instruction_set, app_data_dir @@ -260,7 +260,7 @@ jint nativeForkSystemServer_l(JNIEnv *env, jclass clazz, jint uid, jint gid, jin ServerSpecializeArgs_v1 args(uid, gid, gids, runtime_flags, permitted_capabilities, effective_capabilities); HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeForkSystemServer_pre(); reinterpret_cast(nativeForkSystemServer_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, effective_capabilities @@ -272,7 +272,7 @@ jint nativeForkSystemServer_samsung_q(JNIEnv *env, jclass clazz, jint uid, jint ServerSpecializeArgs_v1 args(uid, gid, gids, runtime_flags, permitted_capabilities, effective_capabilities); HookContext ctx; ctx.env = env; - ctx.raw_args = &args; + ctx.args = { &args }; ctx.nativeForkSystemServer_pre(); reinterpret_cast(nativeForkSystemServer_orig)( env, clazz, uid, gid, gids, runtime_flags, _11, _12, rlimits, permitted_capabilities, effective_capabilities diff --git a/native/src/zygisk/module.hpp b/native/src/zygisk/module.hpp index edb58c75d..b2df2a646 100644 --- a/native/src/zygisk/module.hpp +++ b/native/src/zygisk/module.hpp @@ -7,6 +7,18 @@ namespace { struct HookContext; struct ZygiskModule; +struct AppSpecializeArgs_v1; +using AppSpecializeArgs_v2 = AppSpecializeArgs_v1; +struct AppSpecializeArgs_v3; + +struct module_abi_v1; +using module_abi_v2 = module_abi_v1; +using module_abi_v3 = module_abi_v1; + +struct api_abi_v1; +struct api_abi_v2; +using api_abi_v3 = api_abi_v2; + struct AppSpecializeArgs_v3 { jint &uid; jint &gid; @@ -64,17 +76,6 @@ struct AppSpecializeArgs_v1 { mount_data_dirs(v3->mount_data_dirs), mount_storage_dirs(v3->mount_storage_dirs) {} }; -struct module_abi_raw { - long api_version; - void *_this; - void (*preAppSpecialize)(void *, void *); - void (*postAppSpecialize)(void *, const void *); - void (*preServerSpecialize)(void *, void *); - void (*postServerSpecialize)(void *, const void *); -}; - -using module_abi_v1 = module_abi_raw; - struct ServerSpecializeArgs_v1 { jint &uid; jint &gid; @@ -91,6 +92,15 @@ struct ServerSpecializeArgs_v1 { effective_capabilities(effective_capabilities) {} }; +struct module_abi_v1 { + long api_version; + void *impl; + void (*preAppSpecialize)(void *, void *); + void (*postAppSpecialize)(void *, const void *); + void (*preServerSpecialize)(void *, void *); + void (*postServerSpecialize)(void *, const void *); +}; + enum : uint32_t { PROCESS_GRANTED_ROOT = zygisk::StateFlag::PROCESS_GRANTED_ROOT, PROCESS_ON_DENYLIST = zygisk::StateFlag::PROCESS_ON_DENYLIST, @@ -99,46 +109,47 @@ enum : uint32_t { PROCESS_IS_MAGISK_APP = (1u << 31), UNMOUNT_MASK = (PROCESS_ON_DENYLIST | DENYLIST_ENFORCING), - PRIVATE_MASK = (0x3u << 30) + PRIVATE_MASK = (DENYLIST_ENFORCING | PROCESS_IS_MAGISK_APP) }; -struct ApiTable { - // These first 2 entries are permanent - ZygiskModule *module; - bool (*registerModule)(ApiTable *, long *); - - struct { - void (*hookJniNativeMethods)(JNIEnv *, const char *, JNINativeMethod *, int); - void (*pltHookRegister)(const char *, const char *, void *, void **); - void (*pltHookExclude)(const char *, const char *); - bool (*pltHookCommit)(); - - int (*connectCompanion)(ZygiskModule *); - void (*setOption)(ZygiskModule *, zygisk::Option); - } v1{}; - struct { - int (*getModuleDir)(ZygiskModule *); - uint32_t (*getFlags)(ZygiskModule *); - } v2{}; - - ApiTable(ZygiskModule *m); +struct api_abi_base { + ZygiskModule *impl; + bool (*registerModule)(api_abi_base *, long *); }; -#define call_app(method) \ -switch (*ver) { \ -case 1: \ -case 2: { \ - AppSpecializeArgs_v1 a(args); \ - v1->method(v1->_this, &a); \ - break; \ -} \ -case 3: \ - v1->method(v1->_this, args); \ - break; \ +struct api_abi_v1 : public api_abi_base { + void (*hookJniNativeMethods)(JNIEnv *, const char *, JNINativeMethod *, int); + void (*pltHookRegister)(const char *, const char *, void *, void **); + void (*pltHookExclude)(const char *, const char *); + bool (*pltHookCommit)(); + + int (*connectCompanion)(ZygiskModule *); + void (*setOption)(ZygiskModule *, zygisk::Option); +}; + +struct api_abi_v2 : public api_abi_v1 { + int (*getModuleDir)(ZygiskModule *); + uint32_t (*getFlags)(ZygiskModule *); +}; + +#define call_app(method) \ +switch (*mod.api_version) { \ +case 1: \ +case 2: { \ + AppSpecializeArgs_v1 a(args); \ + mod.v1->method(mod.v1->impl, &a); \ + break; \ +} \ +case 3: \ + mod.v1->method(mod.v1->impl, args);\ + break; \ } struct ZygiskModule { + void onLoad(void *env) { + entry.fn(&api, env); + } void preAppSpecialize(AppSpecializeArgs_v3 *args) const { call_app(preAppSpecialize) } @@ -146,37 +157,44 @@ struct ZygiskModule { call_app(postAppSpecialize) } void preServerSpecialize(ServerSpecializeArgs_v1 *args) const { - v1->preServerSpecialize(v1->_this, args); + mod.v1->preServerSpecialize(mod.v1->impl, args); } void postServerSpecialize(const ServerSpecializeArgs_v1 *args) const { - v1->postServerSpecialize(v1->_this, args); + mod.v1->postServerSpecialize(mod.v1->impl, args); } int connectCompanion() const; int getModuleDir() const; void setOption(zygisk::Option opt); static uint32_t getFlags(); - void doUnload() const { if (unload) dlclose(handle); } + void tryUnload() const { if (unload) dlclose(handle); } + void clearApi() { memset(&api, 0, sizeof(api)); } int getId() const { return id; } ZygiskModule(int id, void *handle, void *entry); - static bool RegisterModule(ApiTable *table, long *module); - - union { - void (* const entry)(void *, void *); - void * const raw_entry; - }; - ApiTable api; + static bool RegisterModule(api_abi_base *api, long *module); private: const int id; bool unload = false; + void * const handle; union { - long *ver = nullptr; + void * const ptr; + void (* const fn)(void *, void *); + } entry; + + union { + api_abi_base base; + api_abi_v1 v1; + api_abi_v2 v2; + } api; + + union { + long *api_version; module_abi_v1 *v1; - }; + } mod; }; } // namespace