Library / SDK
acidanthera/Lilu avatar
acidanthera/Lilu

Lilu: a kernel patching platform for macOS kexts, processes and libraries

Arbitrary kext and process patching on macOS

3,860 stars429 forksCBSD-3-Clause

At a glance

What is it?
Lilu is an open source macOS kernel extension that provides a plugin API for patching kexts, processes and frameworks at runtime. It is infrastructure for other kexts, not a user-facing tool, and the README documents both its boot-argument controls and its limits.
Who is it for?
Adopt Lilu only if you are running or building a plugin that depends on it, such as VirtualSMC or WhateverGreen, and you can add the kext to your bootloader's kext set. Do not install it expecting it to do anything on its own: the README describes it as a platform, and the actual behaviour lives in the plugins.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Lilu actually patches, and who depends on it

Lilu is not an application and it is not a driver for any specific piece of hardware. The README describes it as "a platform for arbitrary kext, library, and program patching throughout the system for macOS." The features list names four capabilities: a generic kext patcher, a generic process patcher (64-bit with basic 32-bit functionality), a generic framework and library patcher (64-bit with basic 32-bit functionality), and a unified plugin API.

That framing tells you who the project is for. The direct audience is kext developers who need to alter Apple's kernel code or the behaviour of a running process without shipping a modified system binary. The indirect audience is anyone running a Hackintosh or an older Mac who installs a plugin built on Lilu. The README points to a KnownPlugins.md file in the repository for existing plugins and code samples, and the related search data shows VirtualSMC and WhateverGreen as the names people associate with the project. Neither of those is part of Lilu itself; they are separate kexts that link against it.

So the practical unit of installation is a set, not a single file. If you install Lilu alone, nothing observable changes. That is a deliberate design choice and also the first thing a new user gets wrong.

The plugin API and the patching mechanism

The repository layout shows what the patching machinery is built from. Alongside the Lilu/ source directory there are vendored components: capstone/ for disassembly, hde/ for a simple x86-64 instruction decoder, lzvn/ for decompression, sha256/, and umm_malloc/ for a static pool allocator. The credits section confirms the provenance: capstone is credited to Nguyen Anh Quynh, hde64 to Vyacheslav Patkov, the lzvn decompression to Pike R. Alpha, the SHA-256 implementation to Brad Conte, and umm_malloc to Ralph Hempel. The kernel patcher is credited as being based on fG!'s Onyx The Black Cat.

For a plugin author, the interaction is through the unified plugin API the README mentions, and the README says the headers are filled with AppleDOC comments for contributors with programming skills. Plugins register with Lilu and then request patches; Lilu locates the target code, applies the patch, and keeps the bookkeeping. The disassembler modules exist because locating a function in a stripped kernel or framework binary cannot rely on symbol names alone.

The README does not describe the matching strategy in detail, and it does not document how a failed patch is reported or rolled back. That is a real gap. A patcher that silently fails to match is indistinguishable from one that was never loaded, unless you enable debug output.

Installing Lilu and turning on debug output

The README gives the installation route directly: install this kext along with the plugin kexts depending on it, and get prebuilt binaries from the releases page. There is no package manager step documented. In practice this means placing Lilu.kext into the kext directory your bootloader reads, next to the plugin kexts, and injecting it at boot.

The README also gives the build path for plugin authors: to compile a plugin, copy the debug version of Lilu.kext into its directory.

text
-liludbg

That argument enables debug printing, and the README notes it is available in DEBUG binaries. To enable debug printing in Lilu and all loaded plugins at once, use -liludbgall, which carries the same DEBUG-build requirement.

text
-liludbgall

For troubleshooting, liludelay=1000 inserts a one second delay after each print, and the DEBUG build's liludump=N writes the log to /var/log/Lilu_VERSION_KERN_MAJOR.KERN_MINOR.txt after N seconds.

text
liludelay=1000
liludump=60

After a reboot with these set, the reader should see Lilu's log lines in the kernel log, or the dumped file under /var/log. If nothing appears, the kext was not injected.

The boot arguments that disable or force Lilu

Lilu has an unusually large set of off switches for a single kext, and reading them is the fastest way to understand its operational constraints. -liluoff disables Lilu entirely. -liluuseroff disables only the user patcher, which the README associates with dyld_shared_cache manipulations. -liluslow enables the legacy user patcher. -lilulowmem disables kernel unpack, which the README notes disables Lilu in recovery mode.

Version gating is separate. -lilubeta enables Lilu on unsupported OS versions, with the README stating that macOS 26 and below are enabled by default. -lilubetaall does the same for Lilu and all loaded plugins, and the README marks it "use _very_ carefully." -liluforce enables Lilu regardless of mode, OS, installer or recovery.

Two more arguments change assumptions rather than enablement. lilucpu=N tells Lilu and plugins to assume the Nth CPUInfo::CpuGeneration, which matters when the CPU is misidentified. liludelay and liludump, covered above, exist purely for diagnosis.

The Peculiarities section adds the constraints that matter most in practice: most plugins cease to function in safe (-x) mode, and Lilu itself does not function in single-user (-s) mode by default unless -liluforce is present. If your recovery workflow depends on a plugin, that is the argument you need.

Where Lilu stops: safe mode, single-user mode and unsupported OS versions

The clearest limitation is the one the README states plainly. Most plugins stop working in safe mode. Lilu does not run in single-user mode without -liluforce. If you boot into either to diagnose a problem, the plugin you are trying to test is not loaded, and its absence will look like a hardware fault.

The second limitation is version support. Lilu is enabled by default on macOS 26 and below, per the README. Anything newer needs -lilubeta, and plugins need -lilubetaall if they are to follow. The README's warning on -lilubetaall is not decorative: it applies an unsupported-version override to every plugin in the set, including ones you did not intend to test.

A third issue is that patch matching is not guaranteed. The README does not document what happens when a patch target is not found, and it does not document rollback. There is no stated mechanism for reverting a patch that was applied and then caused a crash, beyond rebooting without the kext. For a component that modifies kernel memory, that absence is worth knowing before you enable it on a machine you depend on.

Finally, Lilu is the wrong tool if you want a supported, vendor-sanctioned change. It exists to alter Apple's code at runtime. If your goal can be met by a configuration profile, a driver from the hardware vendor, or simply not modifying the system, Lilu adds risk without adding value.

Alternatives: OpenCore kernel patching and standalone kexts

The nearest alternative is not another kext but the bootloader. OpenCore and Clover can apply kernel and kext patches directly from their configuration, without a resident patching platform. The difference in approach is where the patch lives. A bootloader patch is declared in the config and applied once during boot; Lilu is a loaded kext that plugins call into at runtime, which lets a plugin decide what to patch based on what it detects, and lets several plugins share one patching implementation.

The trade-off runs the other way too. A bootloader patch needs no plugin API, no version gating and no boot arguments, and it does not sit in kernel memory after boot. If you have one specific patch to apply, a bootloader entry is simpler and easier to audit. If you are building a plugin that must adapt to different hardware or OS versions, Lilu's API is the reason the plugin ecosystem uses it.

A second alternative is a standalone kext that does its own patching. That removes the dependency but duplicates the disassembly, decompression and allocation code that Lilu already vendors. The repository layout shows how much that is: capstone, hde, lzvn, sha256 and umm_malloc are all present as separate directories. Reimplementing that set is the cost of going without Lilu.

Maintenance, licence and upgrade cost

The last push to the repository was on 2026-03-20, the same day release 1.7.2 was published. The release before it, 1.7.1, is dated 2025-07-07, and 1.7.0 is dated 2024-12-03. The cadence is therefore irregular: roughly seven months between 1.7.0 and 1.7.1, then about eight months to 1.7.2. The repository is not archived, but the spacing means you should not expect a fix to arrive on a short timeline.

Upgrade cost is tied to the plugin set, not to Lilu alone. Because plugins link against Lilu's API, a Lilu update can require matching plugin updates, and the README's boot arguments for version gating exist precisely because the combination can be mismatched. The debug arguments are DEBUG-build only, so a release build will not produce the diagnostic output you may be relying on.

Lilu is licensed under BSD-3-Clause, and the LICENSE.txt file is at the top level of the repository. The vendored components carry their own origins, listed in the credits: capstone, hde64, lzvn, SHA-256, umm_malloc and the Onyx The Black Cat base for the kernel patcher. If you redistribute Lilu, those attributions are part of what you are redistributing. This is a description of what the repository states, not legal advice; check the licence texts yourself before shipping anything.

Editorial conclusion

Adopt Lilu only if you are running or building a plugin that depends on it, such as VirtualSMC or WhateverGreen, and you can add the kext to your bootloader's kext set. Do not install it expecting it to do anything on its own: the README describes it as a platform, and the actual behaviour lives in the plugins. Before installing, verify which plugins you need, whether your macOS version is supported or requires -lilubeta, and whether you boot in safe or single-user mode, since Lilu and most plugins stop working there without -liluforce.

Frequently asked questions

What is Acidanthera Lilu used for?

The README describes Lilu as a platform for arbitrary kext, library and program patching on macOS, with a generic kext patcher, a generic process patcher, a generic framework and library patcher, and a unified plugin API. It is used by other kexts that depend on it rather than doing anything visible on its own.

How do I download and install the Lilu kext?

The README says prebuilt binaries are available on the releases page and that you should install this kext along with the plugin kexts depending on it. There is no package manager or installer step documented; you place Lilu.kext where your bootloader reads kexts and inject it at boot.

Does Lilu work in safe mode or single-user mode?

The Peculiarities section states that most plugins cease to function in safe (-x) mode, and that Lilu itself does not function in single-user (-s) mode by default unless -liluforce is present.

How do I enable Lilu debug logging?

Add -liludbg to enable debug printing in DEBUG binaries, or -liludbgall to enable it in Lilu and all loaded plugins. The DEBUG build's liludump=N argument writes the log to /var/log/Lilu_VERSION_KERN_MAJOR.KERN_MINOR.txt after N seconds.

Official sources

  1. acidanthera/Lilu on GitHub
  2. Issues
  3. License: BSD-3-Clause
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/acidanthera-lilu.svg)](https://hysenlabs.com/projects/acidanthera-lilu)