Android Kernel Hooking: Bypassing GKI Limits & Memory Protection

This article examines the security challenges of Android and IoT devices built on ARM/ARM64 platforms, explains how Google's Generic Kernel Image (GKI) restricts kernel modifications, and provides detailed techniques—including memory‑page attribute manipulation, remap_pfn_range, and assembly‑level hook implementations—to safely inject custom functionality into the kernel while addressing write‑protection, concurrency, and module‑unloading issues.

OPPO Amber Lab
OPPO Amber Lab
OPPO Amber Lab
Android Kernel Hooking: Bypassing GKI Limits & Memory Protection

Background

Android and IoT devices based on ARM/ARM64 dominate the non‑PC internet landscape, and their security issues threaten the entire industry.

Fragmentation and GKI

Historically, manufacturers could modify the Linux kernel source directly, making it easy to add security features. However, low compatibility among vendor kernels makes unified fixes difficult, prompting Google to introduce the Generic Kernel Image (GKI) that forbids source‑level kernel modifications and forces all extra functionality into separate kernel modules, dramatically raising the difficulty of kernel security development.

Impact on Hooking

Previously, adding a system‑call hook required only a few lines of C code in the appropriate *.c file. Under GKI, developers must master low‑level skills such as ARM disassembly, interrupt handling, pre‑emptive scheduling, memory management, and thread migration, making even simple hooks practically impossible without deep expertise.

Hook Fundamentals

A hook redirects the execution flow of a system function to custom code, optionally returning to the original flow later.

Bypassing Write‑Protection

Kernel code pages are read‑only at runtime; attempting to modify them triggers a protection fault. To make a page writable, one can modify the page‑table entry (PTE) to set the _PAGE_RW flag. This requires understanding virtual‑address composition, locating the corresponding PTE, and updating its attributes.

Solution ① – Direct PTE Modification

Locate the PTE for the target virtual address and set the write‑enable bit, allowing direct patching of kernel instructions.

Solution ② – Remap with Writable Attributes

Use the kernel’s remap_pfn_range function to create a new mapping of the physical page with read‑write permissions, avoiding direct PTE edits.

Comparison

Solution ① is straightforward but its compatibility and stability depend on the specific platform and kernel implementation. Solution ② is slightly more complex and involves more code, but offers better portability and stability through a standardized interface; it is generally recommended.

Additional Hooking Challenges

Inline hooks must handle instruction‑length mismatches and multi‑CPU concurrency, which can cause incomplete instruction reads and kernel panics. To mitigate this, one can occupy the CPU (e.g., using DPC on Windows or irq_queue_on on Linux) to prevent other threads from executing during the patch.

Module Unload Issues

Since the original execution flow is redirected to a custom module, unloading the module without restoring the original code can cause a panic. Reference counting (e.g., __module_get) and careful restoration of overwritten instructions are required, though even with these measures, unloading is risky and often avoided.

Parameter Parsing and Stack Restoration

Hooking system‑call entry points is difficult because they are stub code without standard calling conventions. Understanding ARM/ARM64 register usage (R7/R8 for syscall numbers, R0‑R3 for arguments, etc.) and stack layout is essential for correctly extracting parameters and restoring the execution environment.

Practical Hook Implementation for sys_ni_call

1. Overwrite the first bytes of sys_ni_call with a jump to a custom proxy function. 2. In the proxy, handle parameters according to ARM/ARM64 conventions and perform the desired logic. 3. Before returning, restore registers and the stack pointer, optionally execute the overwritten instructions, and jump back to the original flow.

Conclusion

Implementing kernel hooks on modern Android devices requires low‑level assembly work, careful handling of memory protection, concurrency, and module lifecycle issues. The article covers the fundamental problems and two primary solutions, with more advanced topics to be explored in future installments.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AndroidSecurityARMmemory protectionGKIKernel Hooking
OPPO Amber Lab
Written by

OPPO Amber Lab

Centered on user data security and privacy, we conduct research and open our tech capabilities to developers, building an information‑security fortress for partners and users and safeguarding OPPO device security.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.