HanSoBored
Zygisk-Loader
C

A dynamic, Zygisk module for hot-swapping native libraries into Android applications without rebooting.

Last updated Jul 5, 2026
84
Stars
15
Forks
0
Issues
0
Stars/day
Attention Score
43
Language breakdown
No language data available.
โ–ธ Files click to expand
README

โšก Zygisk-Loader

Language API Channel

Zygisk-Loader is a stealthy, ultra-lightweight Zygisk module written in Pure C. It acts as a universal bridge that dynamically injects external shared libraries (.so) into specific Android application processes.

Rewritten from Rust to C, this module now boasts an incredibly small footprint (< 20KB) with zero runtime dependencies. Unlike traditional modules that require rebuilding and rebooting, Zygisk-Loader enables a "Hot-Swap" workflow. You can recompile your instrumentation library, push it to the device, and simply restart the target app to apply changes instantly.

Key Features

  • Hot-Swap Capable: Update your payload (.so) and deploy instantly by just restarting the target app. No device reboot required.
  • Ultra-Lightweight: Built with Pure C and standard Android NDK libraries. The module binary is microscopic (<20KB), ensuring minimal memory usage and maximum performance.
  • Multi-App Support: JSON-based configuration allows targeting multiple apps with different payloads simultaneously.
  • Robust Injection: Uses memfd-based RAM injection via memfdcreate + androiddlopenext. The payload is loaded directly from anonymous memory into the target process โ€” no disk writes at any point. This approach works across all Android 10+ SELinux domains including untrustedapp.
  • Stealthy (Zero-Forensic-Trace): The payload is written into an anonymous memory file (memfd), loaded directly from the file descriptor, and the memfd is closed. No file is ever written to disk โ€” even temporarily. Zero forensic trace for file scanners.
  • Zygisk API v5: Utilizes the latest Zygisk API for maximum compatibility with Magisk, KernelSU, and APatch.
  • Config-Driven: Simple JSON-based configuration. No hardcoded package names.
  • Zero Dependencies: Native lightweight JSON parser with no external library dependencies.

Architecture

Zygisk-Loader separates the Injector (The Module) from the Payload (Your Logic). It bridges the permission gap between the Zygote process (Root) and the App process (Untrusted).

flowchart TD
    subgraph Storage [" /data/adb/modules/zygisk-loader/config/ "]
        Config[("target.json")]
        PayloadBin[("payload_*.so")]
    end

subgraph Zygote [" Zygote Process (Root) "] Step1[Parse JSON Config] Step2[Match App Package] Step3[Buffer Payload to RAM] end

subgraph App [" Target App Process (User UID) "] Fork((Fork)) Step4[memfd_create anonymous mem] Step5[Write Payload to memfd] Step6[androiddlopenext with ANDROIDDLEXTUSELIBRARYFD] Step7["close(memfd)"] Logic[Payload Active] end

Config --> Step1 Step1 --> Step2 Step2 --> PayloadBin PayloadBin --> Step3 Step3 --> Fork Fork --> Step4 Step4 --> Step5 Step5 --> Step6 Step6 --> Logic Step6 -.-> Step7

Directory Structure

After installation, the module creates a configuration directory:

/data/adb/modules/zygisk-loader/
โ”œโ”€โ”€ module.prop
โ”œโ”€โ”€ zygisk/
โ”‚   โ””โ”€โ”€ ...
โ””โ”€โ”€ config/              <-- WORKSPACE
    โ”œโ”€โ”€ target.json      (JSON configuration with app-package to payload mapping)
    โ””โ”€โ”€ payload_*.so     (Your compiled libraries for each target)

Usage

1. Installation

  • Download the latest release .zip.
  • Flash via Magisk / KernelSU / APatch.
  • Reboot device.

2. Configuration (Multi-App Support)

Create or edit the JSON configuration file at /data/adb/modules/zygisk-loader/config/target.json:

# Create the config file with multiple app targets
cat > /data/adb/modules/zygisk-loader/config/target.json << 'EOF'
[
  {
    "app": "com.instagram",
    "lib": "/data/adb/modules/zygisk-loader/config/payload_ssl.so"
  },
  {
    "app": "com.facebook",
    "lib": "/data/adb/modules/zygisk-loader/config/payload_custom.so"
  },
  {
    "app": "com.threads",
    "lib": "/data/adb/modules/zygisk-loader/config/payload_research.so"
  }
]
EOF

Features:

  • Multiple Targets: Each app can have its own dedicated payload
  • Sub-Process Coverage: Base package name matching automatically handles processes like com.app:remote or com.app:bg
  • Flexible Formatting: JSON parser is whitespace-tolerant

3. Deploy Payloads

Copy your compiled libraries to the config folder:

# Copy payload libraries for each target
cp libpayloadssl.so /data/adb/modules/zygisk-loader/config/payloadssl.so
cp libpayloadcustom.so /data/adb/modules/zygisk-loader/config/payloadcustom.so

Set permissions (Important for Zygote to read them)

chmod 644 /data/adb/modules/zygisk-loader/config/*.so

4. Apply (Hot-Swap)

Force stop the target application. The next time it launches, the loader will inject the corresponding payload:

am force-stop com.instagram
am force-stop com.facebook

Developing a Payload

Your payload does not need to know about Zygisk. It acts as a standard shared library. You can write your payload in C, C++, or Rust.

Option A: Using C/C++ (Constructor Attribute)

#include <android/log.h>
#include <unistd.h>

// Choose a descriptive tag for your payload's log messages #define LOG_TAG "ExamplePayload" #define LOGI(...) androidlogprint(ANDROIDLOGINFO, LOGTAG, VAARGS__)

// This function runs automatically when dlopen() is called attribute((constructor)) void init() { LOGI("Hello from inside the target application!"); LOGI("I have been loaded and my file on disk is likely already gone.");

// Your hooking logic (e.g., Dobby, And64InlineHook) goes here }

Option B: Using Rust (ctor crate)

Cargo.toml:

[lib] crate-type = ["cdylib"]

[dependencies] ctor = "0.2" android_logger = "0.13" log = "0.4"

src/lib.rs:

use ctor::ctor; use log::LevelFilter; use android_logger::Config;

#[ctor] fn init() { androidlogger::initonce( Config::default().withmaxlevel(LevelFilter::Info).with_tag("ExamplePayload") );

// logic hooking start here log::info!("Hello from inside the target application!"); }

Technical Constraints

  • SELinux Compatibility: This module uses RAM-only injection via memfdcreate + androiddlopenext. The payload is never written to disk, leaving no forensic trace. This approach works across all Android versions (10+) and SELinux domains including untrustedapp, as memfd pages have a dedicated SELinux context that permits executable mappings (per mo-jit project research).
  • Isolated Processes: The loader automatically handles isolated processes (e.g., :remote services) by intelligently resolving the correct data directory path.

Disclaimer

This tool is for educational purposes and security research only. The author is not responsible for any misuse of this software.

License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ”— More in this category

ยฉ 2026 GitRepoTrend ยท HanSoBored/Zygisk-Loader ยท Updated daily from GitHub