diff --git a/loader/src/external/lsplt b/loader/src/external/lsplt index b254b5b..5d2b820 160000 --- a/loader/src/external/lsplt +++ b/loader/src/external/lsplt @@ -1 +1 @@ -Subproject commit b254b5b9a56a16cfddfd78887afc702af5380c38 +Subproject commit 5d2b820cf968fcd8162697d208ad406805b6db25 diff --git a/loader/src/include/api.hpp b/loader/src/include/api.hpp index ab77a74..ab616a9 100644 --- a/loader/src/include/api.hpp +++ b/loader/src/include/api.hpp @@ -26,14 +26,40 @@ #define ZYGISK_API_VERSION 4 /* + +*************** +* Introduction +*************** + +On Android, all app processes are forked from a special daemon called "Zygote". +For each new app process, zygote will fork a new process and perform "specialization". +This specialization operation enforces the Android security sandbox on the newly forked +process to make sure that 3rd party application code is only loaded after it is being +restricted within a sandbox. + +On Android, there is also this special process called "system_server". This single +process hosts a significant portion of system services, which controls how the +Android operating system and apps interact with each other. + +The Zygisk framework provides a way to allow developers to build modules and run custom +code before and after system_server and any app processes' specialization. +This enable developers to inject code and alter the behavior of system_server and app processes. + +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! + +********************* +* Development Guide +********************* + 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 { @@ -51,8 +77,26 @@ private: zygisk::Api *api; JNIEnv *env; }; + REGISTER_ZYGISK_MODULE(ExampleModule) + +----------------------------------------------------------------------------------------- + +Since your module class's code runs with either Zygote's privilege in pre[XXX]Specialize, +or runs in the sandbox of the target process in post[XXX]Specialize, the code in your class +never runs in a true superuser environment. + +If your module require access to superuser permissions, you can create and register +a root companion handler function. This function runs in a separate root companion +daemon process, and an Unix domain socket is provided to allow you to perform IPC between +your target process and the root companion process. + +Example code: + +static void example_handler(int socket) { ... } + REGISTER_ZYGISK_COMPANION(example_handler) + */ namespace zygisk { @@ -84,7 +128,7 @@ namespace zygisk { // This method 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 method runs as the same privilege of the app's own code. + // This means that this method runs with the same privilege of the app's own code. virtual void postAppSpecialize([[maybe_unused]] const AppSpecializeArgs *args) {} // This method is called before the system server process is specialized. @@ -219,7 +263,16 @@ namespace zygisk { // will be set to nullptr. void hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods); - // For ELFs loaded in memory matching `inode`, replace function `symbol` with `newFunc`. + // Hook functions in the PLT (Procedure Linkage Table) of ELFs loaded in memory. + // + // Parsing /proc/[PID]/maps will give you the memory map of a process. As an example: + // + //