The Age of Zygote Injection

Tricta (Pentester · hakaisecurity.io)

BSides Las Vegas 2025 · Day 1

Overview

This presentation makes a focused case for zygote injection as a powerful, comparatively stealthy way to instrument or subvert Android applications at scale. The speaker—who asks the audience to call him Trito, describes himself as a young Brazilian penetration tester and Mario developer at Hakai Offensive Security, and jokes about pizza and cats—frames the technique as an alternative to Frida and conventional debuggers when applications implement anti-tamper or anti-analysis checks. The core idea is simple to state and difficult to defend against on a compromised or rooted device: because every application process is forked from Zygote, code that becomes part of Zygote’s early initialization is inherited by child processes before most app-level protections run. The talk moves from ART and DEX basics through Native Bridge, PLT and inline hooking, then details a Magisk module that swaps in a loader library via the native bridge property, drops an operator in memory, and hooks fork/specialization paths and libart.so interpreter routines. Live demos on an Android 12 emulator show logcat proof of injection into Zygote and child apps, flip a demo app’s isRoot result from true to false by substituting DEX behavior, and alter native output strings loaded from a companion .so. The speaker also previews Lihoo, a JISK-oriented companion for hook configuration. The material is offensive research and assumes elevated control of the device.

Watch on YouTube

Visual summary for The Age of Zygote Injection by Tricta
Visual summary for The Age of Zygote Injection by Tricta

Key moments

  1. 2:00 Speaker defines Zygote as Android’s parent app process and introduces specialization and SELinux isolation after fork.
  2. 8:00 Explanation of PLT hooking and inline hooking as primitives for redirecting control flow.
  3. 10:00 High-level attack chain: modify Native Bridge loading, drop loader/operator, hook fork/specialize JNI paths.
  4. 12:00 Magisk module layout and using post-fs-data to point the VM’s native bridge property at the attacker loader.
  5. 18:00 Operator uses Xhook on ClassLinker/fork registration; discussion of pre- vs post-specialization hook windows.
  6. 22:00 Live logcat demo: code loaded into zygote PID and per-app injection as Chrome and a dummy app start.
  7. 26:00 DEX-layer plan: hook PrettyMethod/DoCall in libart, scope to target package, swap ArtMethod for isRoot demo.
  8. 32:00 Lihoo overview: configure post-app-specialize hooks for native and DEX bypasses with bypass DEX under /data/local/tmp.

The Age of Zygote Injection

Speakers: Trito (speaker name as stated; also introduces himself as “drone” in transcript), Penetration Tester and Researcher, Hakai Offensive Security

Conference: BSides Las Vegas

YouTube: https://www.youtube.com/watch?v=RxAbrMWkyU4

Overview

This presentation makes a focused case for zygote injection as a powerful, comparatively stealthy way to instrument or subvert Android applications at scale. The speaker—who asks the audience to call him Trito, describes himself as a young Brazilian penetration tester and Mario developer at Hakai Offensive Security, and jokes about pizza and cats—frames the technique as an alternative to Frida and conventional debuggers when applications implement anti-tamper or anti-analysis checks. The core idea is simple to state and difficult to defend against on a compromised or rooted device: because every application process is forked from Zygote, code that becomes part of Zygote’s early initialization is inherited by child processes before most app-level protections run. The talk moves from ART and DEX basics through Native Bridge, PLT and inline hooking, then details a Magisk module that swaps in a loader library via the native bridge property, drops an operator in memory, and hooks fork/specialization paths and libart.so interpreter routines. Live demos on an Android 12 emulator show logcat proof of injection into Zygote and child apps, flip a demo app’s isRoot result from true to false by substituting DEX behavior, and alter native output strings loaded from a companion .so. The speaker also previews Lihoo, a JISK-oriented companion for hook configuration. The material is offensive research and assumes elevated control of the device.

Background

▶ Watch: Speaker defines Zygote as Android’s parent app process and introduces special... (2:00)

Android’s Zygote process is described as the parent of app processes. When a user launches an app, Zygote forks; the child is then specialized with SELinux context and policy so processes remain isolated. The Android Runtime (ART) executes DEX bytecode produced from Java/Kotlin, using JIT interpretation for some code and AOT compilation for hot paths, while native components ship as .so libraries. The speaker distinguishes libandroidruntime, associated with environment setup and policy around fork/specialization, from libart.so, which acts as the interpreter for managed code execution.

Native Bridge enters the story as an architecture translation mechanism (for example running x86 code on ARM in emulators). It loads inside Zygote on Android 5 and later when needed, and can unload when translation is unnecessary—behavior the speaker exploits by inserting a loader that always runs early enough to plant an operator before the legitimate bridge is restored. Hooking primitives include PLT redirection (changing resolved addresses for symbols) and inline hooks (patching the first instructions at a target address to branch to attacker code, then return).

The talk briefly relates this approach to Magisk-era frameworks such as Zygisk and Heru, noting version ranges and deprecation/incompatibility themes as stated in the recording.

Key Findings

▶ Watch: High-level attack chain: modify Native Bridge loading, drop loader/operator, ... (10:00)

  1. Native Bridge replacement is the chosen injection rail: set the VM property that selects the native bridge library to the attacker’s loader, which runs during Zygote bring-up, maps the operator, and preserves pointers to restore the original bridge behavior when appropriate.
  1. Fork/specialization hooks land in JNI registration paths for methods such as native fork and specialize, native fork system server, and native specialize process (exact naming follows AOSP-style terminology in the talk). The speaker stores originals and replaces them with wrappers that can run pre- and post-specialization logic—critical because pre hooks execute before SELinux constraints are fully applied to the new process.
  1. Vendor variance matters: Samsung and Motorola are called out for sometimes changing JNI signatures, so portable implants must validate method signatures rather than assuming stock AOSP layouts.
  1. DEX-layer control targets libart.so’s DoCall pipeline (multiple overloads) and PrettyMethod, which exposes readable class and method names at execution time. By scoping to a specific package/process via nice_name and /data/data/..., the demo replaces the ArtMethod for an isRoot check with a DEX loaded from disk that returns false.
  1. Native-layer control hooks android_dlopen_ext (speaker prefers this path over hooking the linker directly) to detect loads of a target library (transcript: libmetry.so) and then patch exported functions, demonstrating UI string changes including a “hacked” label.
  1. Lihoo configuration (as described) lets operators declare DEX or native replacements in post-app-specialize, with bypass DEX files placed under /data/local/tmp, and mentions combining with Magisk denylist behavior so root is hidden from the app while hooks remain active.
  1. Q&A notes: if Native Bridge were absent from a build, this path would not apply; on typical shipping images it remains present (often for emulator scenarios). Google Play Protect is discussed in terms of static repackaging vs dynamic modification; treat those claims as anecdotal from the session.

Technical Deep Dive

▶ Watch: Operator uses Xhook on ClassLinker/fork registration; discussion of pre- vs p... (18:00)

Magisk module and boot timing

The module layout follows common Magisk conventions: module.prop, install.sh, and scripts such as post-fs-data.sh (runs during boot filesystem preparation). The system subtree mirrors /system, placing per-architecture .so files under lib. post-fs-data.sh sets ro.dalvik.vm.native.bridge (wording in the transcript varies slightly) to the loader library name so the VM loads it during Zygote initialization.

Reverse-engineered startup path

The speaker walks Zygote’s startup at a high level: Runtime::Start, JNI_CreateJavaVM, Runtime::Create, Runtime::Init, with developer comments in AOSP that discuss Native Bridge loading in Zygote. The loader’s JNI_OnLoad checks /proc/self/cmdline for zygote, ensuring the payload maps only in the parent process context described.

Operator and Xhook

The operator uses Xhook (named explicitly) on libandroidruntime / JNI surfaces to intercept registration of native methods tied to fork and specialization. When a hooked registration occurs, the code saves the original function pointer and installs a trampoline that calls attacker pre/post handlers around the real implementation. The app process hook path logs the target process name when new apps start.

ART symbol recovery without exports

For PrettyMethod and DoCall, the speaker describes parsing /proc/self/maps, reconstructing ELF images in memory, and walking dynamic and static symbol tables—functions named find_name, do_load, get_symbols on slides—to recover addresses when symbols are not conveniently exported for linking.

DEX swap mechanics

The PrettyMethod hook identifies when execution belongs to the demo package. On the isRoot method in the main activity, instead of invoking the original ArtMethod, the code loads mydex.dex from the process-private data directory (with appropriate permissions), resolves the replacement method, and substitutes ArtMethod structures so the interpreter runs attacker-controlled DEX. The speaker notes patching DEX or generating a bypass class that returns false.

Native hook path

Hooking android_dlopen_ext allows the implant to watch for libmetry.so. Upon load, it resolves stringFromNativeCode (as transcribed) and replaces behavior with a return value that surfaces “hacked” in the UI demo.

Lihoo

Lihoo is presented as a JISK partnering project to configure hooks without manually re-implementing zygote injection each time—supporting DEX method replacement and native function replacement with pointers for originals. The demo bypasses ADB detection, emulator checks, and JDWP flags (as shown in slides), with stack traces logged for visibility into which methods were patched.

Demo / Proof of Concept

▶ Watch: Live logcat demo: code loaded into zygote PID and per-app injection as Chrome... (22:00)

The speaker uses a setup.sh script, ADB push, Magisk module install, and a reboot. Logcat shows code loaded in zygote process with a concrete PID (e.g., 334 in the recording), followed by messages as system and user apps spawn. Opening Chrome and a dummy app produces logs indicating the package name and confirming hooks in each new process.

The isRoot demo begins with true on screen; after reboot with the module, the same app shows false, accompanied by detailed stack traces of hooked DEX calls. A second pass demonstrates native string changes. The Lihoo segment shows an app that previously crashed under debugger detection running with a “hacked” banner instead.

The speaker acknowledges a gap: static DEX methods are “a little bit different” and not fully handled in the same way as instance methods at the time of the talk.

Defensive Implications

▶ Watch: Lihoo overview: configure post-app-specialize hooks for native and DEX bypass... (32:00)

This talk is not a blueprint for stopping determined local attackers on jailbroken devices; it is a threat model clarifier. Application authors who rely on user-space checks for Frida, JDWP, or known hook frameworks should understand that pre-app initialization hooks can satisfy those checks while still instrumenting the process. Enterprise mobility programs should pair MDM posture with integrity signals that include boot chain, system partition state, and hardware attestation where available—understanding each has bypass classes.

For blue teams, unusual zygote memory maps, unexpected dlopen patterns, or suspicious JNI registration churn on non-developer builds may merit hunting hypotheses, though the base rate on pristine corporate devices should be low. The primary risk aggregates around malware with root, custom ROMs, and research tooling—not remote drive-by compromise of stock phones.

Key Takeaways

  • Zygote injection chains Native Bridge loading to run a loader and operator inside the parent process that forks apps.
  • Pre-specialization hooks can execute before SELinux fully constrains the child—high leverage for stealth instrumentation.
  • ART hooking via DoCall and PrettyMethod enables DEX-level method substitution scoped to a target package.
  • android_dlopen_ext hooking enables native function redirection when libraries load.
  • Vendor JNI differences require signature-aware hook code.
  • Lihoo demonstrates packaging similar ideas for JISK users with post-app-specialize configuration.
  • Static DEX methods were an explicit to-do in the speaker’s framework.

About the Speaker(s)

The speaker introduces himself as Trito, a 19-year-old Brazilian penetration tester and researcher, Mario developer at Hakai Offensive Security, enthusiastic about C internals, reverse engineering, development, and mobile security. He presents Yaga as an explanatory project and references GitHub and on-slide QR codes for materials (exact repository URLs are not confirmed from the transcript). Hakai is described as focused on offensive security services such as penetration testing, red teaming, and threat intelligence.

Reviews

Dr. Zero (Offensive Security Researcher) — STRONG ACCEPT

A hands-on, code-level tour of early-process Android instrumentation that connects OS bring-up details to working Magisk-era implants and dual-stack (DEX + native) hook demos—valuable for people who need to understand what “root” bypasses can actually look like beneath app checks.

Heather Calloway (CISO) — SOLID

The session is technically interesting for security leaders chiefly as a threat-model illustration: on compromised devices, app-level integrity controls are fragile, and supply-chain trust in mobile endpoints must be explicit.

→ Top-rated talks at BSides Las Vegas 2025

All talks from BSides Las Vegas 2025