C++ Developer API Guide

Zygisk C++ Module Development Guide

Master the official zygisk.hpp C++ API. Learn how to write native shared libraries that intercept Zygote process specialization, communicate with privileged root companion daemons over UNIX sockets, and compile with 16KB memory page alignment.

The Zygisk Module Class Contract

Every Zygisk module inherits from the pure virtual class zygisk::ModuleBase defined in zygisk.hpp. The module registers its entry point via REGISTER_ZYGISK_MODULE(MyModule) and optionally registers a root daemon companion via REGISTER_ZYGISK_COMPANION(companion_handler).

The 5 Core Lifecycle Methods in zygisk::ModuleBase

Method Signature Privilege Context Purpose & Timing
onLoad(Api *api, JNIEnv *env) Zygote Root Called once when the module shared library is loaded into Zygote memory.
preAppSpecialize(AppSpecializeArgs *args) Process Root (Pre-drop) Called immediately after fork(). Code runs with ROOT privileges inside the app process.
postAppSpecialize(const AppSpecializeArgs *args) App Sandbox (Post-drop) Called after the kernel applies UID/GID and SELinux sandbox. Runs right before app main().
preServerSpecialize(ServerSpecializeArgs *args) System Server Root Called before Android system_server specializes.
postServerSpecialize(const ServerSpecializeArgs *args) System Server Context Called after system_server drops privileges.

Complete Production-Ready C++ Module Example

Below is a complete, working Zygisk C++ module (module.cpp) demonstrating package name inspection and root companion communication:

module.cpp (Zygisk C++ Implementation)
#include <cstdlib> #include <unistd.h> #include <fcntl.h> #include <android/log.h> #include "zygisk.hpp" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "MyZygiskModule", __VA_ARGS__) using zygisk::Api; using zygisk::AppSpecializeArgs; using zygisk::ServerSpecializeArgs; class MyZygiskModule : public zygisk::ModuleBase { public: void onLoad(Api *api, JNIEnv *env) override { this->api = api; this->env = env; } void preAppSpecialize(AppSpecializeArgs *args) override { // Read the target app nice_name const char *process = env->GetStringUTFChars(args->nice_name, nullptr); if (process) { LOGD("preAppSpecialize: forking process: %s", process); env->ReleaseStringUTFChars(args->nice_name, process); } // Connect to our privileged root companion daemon int fd = api->connectCompanion(); if (fd >= 0) { int request_code = 1001; write(fd, &request_code, sizeof(request_code)); close(fd); } } void postAppSpecialize(const AppSpecializeArgs *args) override { LOGD("postAppSpecialize: process sandboxing complete"); } private: Api *api; JNIEnv *env; }; // Companion process handler (executes in privileged root daemon) static void companion_handler(int client_fd) { int request_code = 0; read(client_fd, &request_code, sizeof(request_code)); LOGD("Companion handler received request: %d", request_code); } // Register module and companion entry points REGISTER_ZYGISK_MODULE(MyZygiskModule) REGISTER_ZYGISK_COMPANION(companion_handler)

Module Packaging & Directory Structure

Zygisk shared libraries must be placed inside the zygisk/ subfolder of your Magisk module zip:

Module ZIP Structure
my_zygisk_module.zip ├── META-INF/com/google/android/update-binary ├── META-INF/com/google/android/updater-script ├── module.prop └── zygisk/ ├── arm64-v8a.so (64-bit ARM - Compiled with 16KB alignment) ├── armeabi-v7a.so (32-bit ARM) ├── x86_64.so (64-bit x86 Emulator) └── x86.so (32-bit x86 Emulator)

CMakeLists.txt & 16KB Memory Page Alignment

On Android 15 and 16, kernels require all 64-bit native binaries to be aligned to 16KB virtual memory page boundaries. Add this linker flag to your CMakeLists.txt:

CMakeLists.txt Linker Configuration
target_link_options(my_zygisk_module PRIVATE "-Wl,-z,max-page-size=16384")
Source & Verification Standard

Verified against official upstream zygisk.hpp API v4 on Magisk v30.7 (February 23, 2026).