Support setting more options

This commit is contained in:
topjohnwu 2021-10-21 03:20:04 -07:00
parent ffb5d9ea9c
commit 4194ac894c
3 changed files with 51 additions and 27 deletions

View File

@ -30,16 +30,18 @@ class ExampleModule : public zygisk::ModuleBase {
public: public:
void onLoad(zygisk::Api *api, JNIEnv *env) override { void onLoad(zygisk::Api *api, JNIEnv *env) override {
this->api = api; this->api = api;
this->env = env;
} }
void preAppSpecialize(zygisk::AppSpecializeArgs *args) override { void preAppSpecialize(zygisk::AppSpecializeArgs *args) override {
JNINativeMethod methods[] = { JNINativeMethod methods[] = {
{ "logger_entry_max_payload_native", "()I", (void*) my_logger_entry_max }, { "logger_entry_max_payload_native", "()I", (void*) my_logger_entry_max },
}; };
api->hookJniNativeMethods("android/util/Log", methods, 1); api->hookJniNativeMethods(env, "android/util/Log", methods, 1);
*(void **) &orig_logger_entry_max = methods[0].fnPtr; *(void **) &orig_logger_entry_max = methods[0].fnPtr;
} }
private: private:
zygisk::Api *api; zygisk::Api *api;
JNIEnv *env;
}; };
REGISTER_ZYGISK_MODULE(ExampleModule) REGISTER_ZYGISK_MODULE(ExampleModule)
@ -129,6 +131,27 @@ struct api_table;
template <class T> void entry_impl(api_table *, JNIEnv *); template <class T> 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.
//
// Processes added to Magisk's denylist will have all Magisk and its modules' files unmounted
// from its mount namespace. In addition, all Zygisk code will be unloaded from memory, which
// also implies that no Zygisk modules (including yours) are loaded.
//
// However, if for any reason your module still wants the unmount part of the denylist
// operation to be enabled EVEN IF THE PROCESS IS NOT ON THE DENYLIST, set this option.
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.
// YOU SHOULD NOT ENABLE THIS OPTION AFTER HOOKING ANY FUNCTION IN THE PROCESS.
DLCLOSE_MODULE_LIBRARY = 1,
};
struct Api { struct Api {
// Connect to a root companion process and get a Unix domain socket for IPC. // Connect to a root companion process and get a Unix domain socket for IPC.
@ -145,22 +168,10 @@ struct Api {
// module's companion request handler. Returns -1 if the connection attempt failed. // module's companion request handler. Returns -1 if the connection attempt failed.
int connectCompanion(); int connectCompanion();
// Force Magisk's denylist unmount routines to run on this process. // Set various options for your module.
// // Please note that this function accepts one single option at a time.
// This API only works in preAppSpecialize. // Check zygisk::Option for the full list of options available.
// void setOption(Option opt);
// Processes added to Magisk's denylist will have all Magisk and its modules' files unmounted
// from its mount namespace. In addition, all Zygisk code will be unloaded from memory, which
// also implies that no Zygisk modules (including yours) are loaded.
//
// However, if for any reason your module still wants the unmount part of the denylist
// operation to be enabled EVEN IF THE PROCESS IS NOT ON THE DENYLIST, call this function.
// No code will be unloaded from memory (including your module) because there is no way to
// guarantee no crashes will occur.
//
// The unmounting does not happen immediately after the function is called. It is actually
// done during app process specialization.
void forceDenyListUnmount();
// Hook JNI native methods for a class // Hook JNI native methods for a class
// //
@ -244,7 +255,7 @@ struct api_table {
// Zygisk functions // Zygisk functions
int (*connectCompanion)(void * /* _this */); int (*connectCompanion)(void * /* _this */);
void (*forceDenyListUnmount)(void * /* _this */); void (*setOption)(void * /* _this */, Option);
}; };
template <class T> template <class T>
@ -262,8 +273,8 @@ void entry_impl(api_table *table, JNIEnv *env) {
int Api::connectCompanion() { int Api::connectCompanion() {
return impl->connectCompanion(impl->_this); return impl->connectCompanion(impl->_this);
} }
void Api::forceDenyListUnmount() { void Api::setOption(Option opt) {
impl->forceDenyListUnmount(impl->_this); impl->setOption(impl->_this, opt);
} }
void Api::hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods) { void Api::hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods) {
impl->hookJniNativeMethods(env, className, methods, numMethods); impl->hookJniNativeMethods(env, className, methods, numMethods);

View File

@ -282,7 +282,7 @@ bool ZygiskModule::registerModule(ApiTable *table, long *module) {
}; };
table->v1.pltHookCommit = []() { return xhook_refresh(0) == 0; }; table->v1.pltHookCommit = []() { return xhook_refresh(0) == 0; };
table->v1.connectCompanion = [](ZygiskModule *m) { return m->connectCompanion(); }; table->v1.connectCompanion = [](ZygiskModule *m) { return m->connectCompanion(); };
table->v1.forceDenyListUnmount = [](auto) { ZygiskModule::forceDenyListUnmount(); }; table->v1.setOption = [](ZygiskModule *m, auto opt) { m->setOption(opt); };
return true; return true;
} }
@ -297,10 +297,17 @@ int ZygiskModule::connectCompanion() const {
return -1; return -1;
} }
void ZygiskModule::forceDenyListUnmount() { void ZygiskModule::setOption(zygisk::Option opt) {
if (g_ctx == nullptr) if (g_ctx == nullptr)
return; return;
switch (opt) {
case zygisk::FORCE_DENYLIST_UNMOUNT:
g_ctx->toggle_unmount(); g_ctx->toggle_unmount();
break;
case zygisk::DLCLOSE_MODULE_LIBRARY:
unload = true;
break;
}
} }
void HookContext::run_modules_pre(const vector<int> &fds) { void HookContext::run_modules_pre(const vector<int> &fds) {
@ -311,7 +318,7 @@ void HookContext::run_modules_pre(const vector<int> &fds) {
void (*module_entry)(void *, void *); void (*module_entry)(void *, void *);
*(void **) &module_entry = dlsym(h, "zygisk_module_entry"); *(void **) &module_entry = dlsym(h, "zygisk_module_entry");
if (module_entry) { if (module_entry) {
modules.emplace_back(i); modules.emplace_back(i, h);
auto api = new ApiTable(&modules.back()); auto api = new ApiTable(&modules.back());
module_entry(api, env); module_entry(api, env);
} }
@ -334,6 +341,9 @@ void HookContext::run_modules_post() {
} else if (flags[SERVER_SPECIALIZE]) { } else if (flags[SERVER_SPECIALIZE]) {
m.postServerSpecialize(server_args); m.postServerSpecialize(server_args);
} }
if (m.unload) {
dlclose(m.handle);
}
} }
} }

View File

@ -82,10 +82,13 @@ struct ZygiskModule {
} }
int connectCompanion() const; int connectCompanion() const;
static void forceDenyListUnmount(); void setOption(zygisk::Option opt);
static bool registerModule(ApiTable *table, long *module); static bool registerModule(ApiTable *table, long *module);
ZygiskModule(int id) : id(id) {} ZygiskModule(int id, void *handle) : handle(handle), id(id) {}
void * const handle;
bool unload = false;
private: private:
int id; int id;
@ -108,7 +111,7 @@ struct ApiTable {
bool (*pltHookCommit)(); bool (*pltHookCommit)();
int (*connectCompanion)(ZygiskModule *); int (*connectCompanion)(ZygiskModule *);
void (*forceDenyListUnmount)(ZygiskModule *); void (*setOption)(ZygiskModule *, zygisk::Option);
} v1; } v1;
}; };
ApiTable(ZygiskModule *m) : module(m), registerModule(&ZygiskModule::registerModule) {} ApiTable(ZygiskModule *m) : module(m), registerModule(&ZygiskModule::registerModule) {}