### Install Cython using pip or easy_install Source: https://github.com/acidanthera/lilu/blob/master/capstone/bindings/python/BUILDING.txt Install Cython using pip or easy_install. Ensure you have the necessary Python development files installed. ```bash sudo pip install cython ``` ```bash sudo easy_install cython ``` -------------------------------- ### Install Cython using apt-get Source: https://github.com/acidanthera/lilu/blob/master/capstone/bindings/python/BUILDING.txt On Ubuntu, you may be able to install Cython directly from your distribution's repositories. ```bash sudo apt-get install cython ``` -------------------------------- ### Install Cython-based Python Bindings Source: https://github.com/acidanthera/lilu/blob/master/capstone/bindings/python/BUILDING.txt Install the Cython-based bindings for better Python performance. Ensure Cython is installed first. ```bash sudo make install_cython ``` -------------------------------- ### Install Capstone & Python Bindings Source: https://github.com/acidanthera/lilu/blob/master/capstone/bindings/python/BUILDING.txt Run this command to install the Capstone library and its Python bindings on *nix systems. Use 'make install3' for Python 3. ```bash sudo make install ``` ```bash sudo make install3 ``` -------------------------------- ### Install Static Library Source: https://github.com/acidanthera/lilu/blob/master/capstone/CMakeLists.txt Installs the static Capstone library, including runtime, library, and archive destinations, if static build is enabled. ```cmake install(TARGETS capstone-static RUNTIME DESTINATION bin LIBRARY DESTINATION ${INSTALL_LIB_DIR} ARCHIVE DESTINATION ${INSTALL_LIB_DIR}) ``` -------------------------------- ### Interact with IORegistry - C++ Source: https://context7.com/acidanthera/lilu/llms.txt Provides examples of finding IORegistry entries by prefix, reading typed OSData properties, accessing PCI configuration registers, retrieving device addresses, and renaming devices using WIOKit. Use awaitPublishing to ensure a device is ready. ```cpp #include void ioKitDemo(IORegistryEntry *pciRoot) { // Find IGPU by prefix under PCI root auto *igpu = WIOKit::findEntryByPrefix("IODeviceTree:/PCI0@0", "IGPU", gIOServicePlane); if (igpu) { // Read typed OSData property uint32_t devId = 0; if (WIOKit::getOSDataValue(igpu, "device-id", devId)) SYSLOG("wio", "IGPU device-id=0x%04X", devId); // Read PCI config register uint16_t vendor = (uint16_t)WIOKit::readPCIConfigValue( igpu, WIOKit::kIOPCIConfigVendorID, 0, 2); SYSLOG("wio", "vendor=0x%04X", vendor); // Retrieve bus/device/function uint8_t bus, dev, fn; WIOKit::getDeviceAddress(igpu, bus, dev, fn); SYSLOG("wio", "BDF %02X:%02X.%X", bus, dev, fn); // Rename device with compatible fix WIOKit::renameDevice(igpu, "GFX0", true); } // Iterate all GFX0 entries using a callback WIOKit::findEntryByPrefix("IODeviceTree:/PCI0@0", "GFX0", gIOServicePlane, [](void *user, IORegistryEntry *entry) -> bool { SYSLOG("wio", "found eGPU: %s", entry->getName()); return false; // keep searching }, false, nullptr); // Await publishing before accessing if (WIOKit::awaitPublishing(igpu)) SYSLOG("wio", "IGPU published"); } ``` -------------------------------- ### Install Common Headers Source: https://github.com/acidanthera/lilu/blob/master/capstone/CMakeLists.txt Installs the common header files to the 'include/capstone' directory of the installation prefix. ```cmake install(FILES ${HEADERS_COMMON} DESTINATION include/capstone) ``` -------------------------------- ### Install Python Development Headers Source: https://github.com/acidanthera/lilu/blob/master/capstone/bindings/python/BUILDING.txt On Ubuntu, install the Python development headers required for building Cython. ```bash sudo apt-get install python-dev ``` -------------------------------- ### Build and Install CSTool Source: https://github.com/acidanthera/lilu/blob/master/capstone/CMakeLists.txt Builds and installs the 'cstool' executable if both shared library and CSTool support are enabled. It links against the default Capstone library and installs the pkg-config file. ```cmake FILE(GLOB CSTOOL_SRC cstool/*.c) add_executable(cstool ${CSTOOL_SRC}) target_link_libraries(cstool ${default-target}) install(TARGETS cstool DESTINATION bin) install(FILES ${CMAKE_BINARY_DIR}/capstone.pc DESTINATION lib/pkgconfig) ``` -------------------------------- ### Get Help for Capstone Disassembly Cmdlet Source: https://github.com/acidanthera/lilu/blob/master/capstone/bindings/powershell/README.md Retrieve detailed help information for the Get-CapstoneDisassembly cmdlet. This is useful for understanding its parameters, usage, and examples. ```powershell Get-Help Get-CapstoneDisassembly -Full ``` -------------------------------- ### Manage EFI Variables and System Reset - C++ Source: https://context7.com/acidanthera/lilu/llms.txt Shows how to obtain and release an EFI runtime services handle, read and write EFI variables (including Lilu's GUID), and set the system reset. Ensure the EFI runtime is available before proceeding. ```cpp #include void efiDemo() { // Obtain a locked EFI runtime services handle auto *efi = EfiRuntimeServices::get(true /* lock */); if (!efi) { SYSLOG("efi", "EFI runtime not available"); return; } // Read a variable (e.g. Lilu vendor GUID variable "boot-args") char buf[512] = {}; uint64_t size = sizeof(buf); uint32_t attr = 0; uint64_t status = efi->getVariable( u"boot-args", &EfiRuntimeServices::LiluVendorGuid, &attr, &size, buf); if (status == 0 /* EFI_SUCCESS */) SYSLOG("efi", "boot-args (%llu bytes): %s", size, buf); // Write a variable const char *value = "debug=0x100"; efi->setVariable( u"my-var", &EfiRuntimeServices::LiluVendorGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, strlen(value) + 1, (void *)value); efi->put(); // release lock } ``` -------------------------------- ### Install Shared Library Source: https://github.com/acidanthera/lilu/blob/master/capstone/CMakeLists.txt Installs the shared Capstone library, including runtime, library, and archive destinations, if shared build is enabled. ```cmake install(TARGETS capstone-shared RUNTIME DESTINATION bin LIBRARY DESTINATION ${INSTALL_LIB_DIR} ARCHIVE DESTINATION ${INSTALL_LIB_DIR}) ``` -------------------------------- ### Set Installation Directory for Libraries Source: https://github.com/acidanthera/lilu/blob/master/capstone/CMakeLists.txt Defines the installation directory for libraries, appending the determined suffix for 64-bit systems. This path is marked as advanced to allow user configuration. ```cmake set(INSTALL_LIB_DIR lib${LIBSUFFIX} CACHE PATH "Installation directory for libraries") mark_as_advanced(INSTALL_LIB_DIR) ``` -------------------------------- ### Capstone API for Architecture-Specific Information Source: https://github.com/acidanthera/lilu/blob/master/capstone/bindings/python/BUILDING.txt These examples illustrate how to retrieve architecture-specific details for each supported architecture using the Capstone API. ```python import capstone # Example usage of test_.py # These code show how to access architecture-specific information for each # architecture. ``` -------------------------------- ### Verify Cython Version Source: https://github.com/acidanthera/lilu/blob/master/capstone/bindings/python/BUILDING.txt Verify that the installed Cython version is 0.19 or newer, which is required for the cython-based binding. ```bash apt-cache policy cython ``` -------------------------------- ### ThreadLocal Storage in C++ Source: https://context7.com/acidanthera/lilu/llms.txt Illustrates the use of ThreadLocal for managing thread-specific data. It shows how to set, get, and erase values, with a specified limit on concurrent threads. ```cpp // --- ThreadLocal --- ThreadLocal tls; // up to 8 concurrent threads tls.set(42); auto *p = tls.get(); // returns &42 on same thread tls.erase(); ``` -------------------------------- ### Determine Library Suffix for 64-bit Source: https://github.com/acidanthera/lilu/blob/master/capstone/CMakeLists.txt Determines the appropriate library suffix (e.g., '64') based on the operating system and whether 64-bit paths are being used. This is relevant for installation paths. ```cmake get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS) if (NOT APPLE AND "${LIB64}" STREQUAL "TRUE") set(LIBSUFFIX 64) else() set(LIBSUFFIX "") endif () ``` -------------------------------- ### Query CPU Information - C++ Source: https://context7.com/acidanthera/lilu/llms.txt Demonstrates how to query CPU topology, raw CPUID information, and CPU generation using the CPUInfo utility. Ensure CPUInfo is initialized before use. ```cpp #include void queryCPU() { CPUInfo::CpuTopology topo {}; if (CPUInfo::getCpuTopology(topo)) { SYSLOG("cpu", "packages=%u physical=%u logical=%u", topo.packageCount, topo.totalPhysical(), topo.totalLogical()); } // Raw CPUID uint32_t eax, ebx, ecx, edx; if (CPUInfo::getCpuid(1, 0, &eax, &ebx, &ecx, &edx)) { CPUInfo::CpuVersion ver; memcpy(&ver, &eax, sizeof(ver)); SYSLOG("cpu", "family=%u extModel=%u model=%u stepping=%u", ver.family, ver.extendedModel, ver.model, ver.stepping); bool hasAVX2 = (ecx & CPUInfo::bit_AVX2) != 0; // leaf 7, but same bit constant bool hasAESNI = (ecx & CPUInfo::bit_AESNI) != 0; SYSLOG("cpu", "AESNI=%d", hasAESNI); } // Generation (prefer BaseDeviceInfo::get().cpuGeneration) uint32_t family, model, stepping; auto gen = CPUInfo::getGeneration(&family, &model, &stepping); SYSLOG("cpu", "generation=%d model=0x%02X", (int)gen, model); } ``` -------------------------------- ### Plugin Bootstrap with PluginConfiguration Source: https://context7.com/acidanthera/lilu/llms.txt Defines the identity, supported environments, and boot-argument names for a Lilu plugin. The `plugin_start.cpp` framework uses this struct to manage the standard `IOService` lifecycle, requiring plugins to implement `pluginStart()`. ```cpp #include #include #include static const char *disableArgs[] = { "-mypluginoff" }; static const char *debugArgs[] = { "-myplugindbg" }; static const char *betaArgs[] = { "-mypluginbeta" }; static void pluginStart(); // Declared extern in plugin_start.hpp via the ADDPR macro PluginConfiguration ADDPR(config) = { xStringify(PRODUCT_NAME), // "MyPlugin" parseModuleVersion(xStringify(MODULE_VERSION)), // 100 LiluAPI::AllowNormal | LiluAPI::AllowInstallerRecovery, disableArgs, arrsize(disableArgs), debugArgs, arrsize(debugArgs), betaArgs, arrsize(betaArgs), KernelVersion::Yosemite, // min macOS 10.10 KernelVersion::Sequoia, // max macOS 15 pluginStart }; static void pluginStart() { DBGLOG("myplugin", "plugin loaded, requesting patcher callback"); lilu.onPatcherLoadForce([](void *, KernelPatcher &patcher) { SYSLOG("myplugin", "patcher ready, kernel slide is set"); }); } ``` -------------------------------- ### NVStorage Demo: Read/Write NVRAM with Compression and Checksum Source: https://context7.com/acidanthera/lilu/llms.txt Demonstrates reading and writing data to NVRAM using NVStorage, with options for compression and checksum. Ensure NVStorage is initialized before use. ```cpp #include void nvramDemo() { NVStorage nv; if (!nv.init()) { SYSLOG("nv", "NVStorage init failed"); return; } // Write with compression + checksum const char *data = "my-plugin-state-data"; bool ok = nv.write( NVRAM_PREFIX(LILU_VENDOR_GUID, "my-plugin-key"), reinterpret_cast(data), (uint32_t)strlen(data) + 1, NVStorage::OptCompressed | NVStorage::OptChecksum); SYSLOG("nv", "write %s", ok ? "OK" : "failed"); // Read back uint32_t sz = 0; auto *buf = nv.read( NVRAM_PREFIX(LILU_VENDOR_GUID, "my-plugin-key"), sz, NVStorage::OptCompressed | NVStorage::OptChecksum); if (buf) { SYSLOG("nv", "read %u bytes: %s", sz, (char *)buf); Buffer::deleter(buf); } // Check existence and delete if (nv.exists(NVRAM_PREFIX(LILU_VENDOR_GUID, "my-plugin-key"))) nv.remove(NVRAM_PREFIX(LILU_VENDOR_GUID, "my-plugin-key")); nv.sync(); nv.deinit(); } ``` -------------------------------- ### Compression Demo: Decompress LZVN and Compress LZSS Source: https://context7.com/acidanthera/lilu/llms.txt Illustrates decompressing data using LZVN mode and compressing data using LZSS mode. Ensure LILU_COMPRESSION_SUPPORT is defined for compression functionality. ```cpp #include void compressionDemo(const uint8_t *compressedBlob, uint32_t compressedSize, uint32_t expectedDecompSize) { // Decompress an lzvn blob (e.g. from kernelcache) uint32_t dstLen = expectedDecompSize; uint8_t *decompressed = Compression::decompress( Compression::ModeLZVN, &dstLen, compressedBlob, compressedSize); if (decompressed) { SYSLOG("comp", "decompressed %u bytes", dstLen); Buffer::deleter(decompressed); } // Compress with lzss const uint8_t raw[] = "data to compress for NVRAM storage"; uint32_t outLen = sizeof(raw) * 2; // upper bound uint8_t *compressed = Compression::compress( Compression::ModeLZSS, outLen, raw, sizeof(raw))); if (compressed) { SYSLOG("comp", "compressed to %u bytes", outLen); Buffer::deleter(compressed); } } ``` -------------------------------- ### Boot Argument Check in C++ Source: https://context7.com/acidanthera/lilu/llms.txt Illustrates how to check for the presence of a specific boot argument using checkKernelArgument(). If the argument is found, the function returns early, allowing for runtime configuration of plugin behavior. ```cpp // --- Boot argument check --- if (checkKernelArgument("-mypluginoff")) return; // plugin disabled ``` -------------------------------- ### Plugin Configuration and Bootstrap Source: https://context7.com/acidanthera/lilu/llms.txt Defines the PluginConfiguration struct and the pluginStart function, which are essential for initializing a Lilu plugin. ```APIDOC ## Plugin Bootstrap — `PluginConfiguration` + `plugin_start.hpp` Every Lilu plugin declares a `PluginConfiguration` struct that describes its identity, supported environments, boot-argument names, and kernel version range. The framework's `plugin_start.cpp` reads this struct to drive the standard `IOService` lifecycle, so plugins need only implement `pluginStart()`. ```cpp // MyPlugin.cpp (compiled with PRODUCT_NAME=MyPlugin, MODULE_VERSION=1.0.0) #include #include #include static const char *disableArgs[] = { "-mypluginoff" }; static const char *debugArgs[] = { "-myplugindbg" }; static const char *betaArgs[] = { "-mypluginbeta" }; static void pluginStart(); // Declared extern in plugin_start.hpp via the ADDPR macro PluginConfiguration ADDPR(config) = { xStringify(PRODUCT_NAME), // "MyPlugin" parseModuleVersion(xStringify(MODULE_VERSION)), // 100 LiluAPI::AllowNormal | LiluAPI::AllowInstallerRecovery, disableArgs, arrsize(disableArgs), debugArgs, arrsize(debugArgs), betaArgs, arrsize(betaArgs), KernelVersion::Yosemite, // min macOS 10.10 KernelVersion::Sequoia, // max macOS 15 pluginStart }; static void pluginStart() { DBGLOG("myplugin", "plugin loaded, requesting patcher callback"); lilu.onPatcherLoadForce([](void *, KernelPatcher &patcher) { SYSLOG("myplugin", "patcher ready, kernel slide is set"); }); } ``` ``` -------------------------------- ### Crypto Demo: AES Encryption, Decryption, and SHA-256 Hashing Source: https://context7.com/acidanthera/lilu/llms.txt Shows how to generate a device-unique key, encrypt/decrypt data using AES-128-CBC, and compute SHA-256 hashes. Remember to securely erase keys after use. ```cpp #include void cryptoDemo() { // Generate a device-unique 16-byte key uint8_t *key = Crypto::genUniqueKey(Crypto::BlockSize); if (!key) { SYSLOG("cry", "key gen failed"); return; } const uint8_t plaintext[] = "sensitive-data"; uint32_t encSize = sizeof(plaintext); // Encrypt uint8_t *ciphertext = Crypto::encrypt(key, plaintext, encSize); if (ciphertext) { SYSLOG("cry", "encrypted %u bytes", encSize); // Decrypt uint32_t decSize = encSize; uint8_t *recovered = Crypto::decrypt(key, ciphertext, decSize); if (recovered) { SYSLOG("cry", "recovered: %s", (char *)recovered); Buffer::deleter(recovered); } Buffer::deleter(ciphertext); } // Hash (SHA-256) uint8_t *digest = Crypto::hash(plaintext, sizeof(plaintext)); if (digest) { SYSLOG("cry", "SHA-256 digest computed (%u bytes min)", Crypto::MinDigestSize); Buffer::deleter(digest); } // Securely erase key Crypto::zeroMemory(Crypto::BlockSize, key); Buffer::deleter(key); } ``` -------------------------------- ### Lightweight Capstone API Usage Source: https://github.com/acidanthera/lilu/blob/master/capstone/bindings/python/BUILDING.txt Shows how to use disasm_lite(), a faster and more memory-efficient method for disassembling binary data when only basic instruction details are needed. It returns tuples instead of CsInsn objects. ```python import capstone # Example usage of test_lite.py # Similarly to test_basic.py, but this code shows how to use disasm_lite(), a lighter # method to disassemble binary. Unlike disasm() API (used by test.py), which returns # CsInsn objects, this API just returns tuples of (address, size, mnemonic, op_str). # # The main reason for using this API is better performance: disasm_lite() is at least # 20% faster than disasm(). Memory usage is also less. So if you just need basic # information out of disassembler, use disasm_lite() instead of disasm(). ``` -------------------------------- ### LiluAPI - Core Functionality Source: https://context7.com/acidanthera/lilu/llms.txt Demonstrates the usage of the LiluAPI singleton for registering callbacks at various lifecycle points, including kernel patcher initialization, kext loading, process execution, and entitlement requests. ```APIDOC ## LiluAPI — `kern_api.hpp` `LiluAPI` (global singleton `lilu`) is the main entry point for plugin authors. It provides `shouldLoad()` to determine whether the plugin should activate, and callback registration APIs (`onPatcherLoad`, `onKextLoad`, `onProcLoad`, `onEntitlementRequest`) that are invoked at the appropriate lifecycle points. ```cpp #include #include // Called from pluginStart() after shouldLoad() succeeds // 1. Register a patcher-ready callback lilu.onPatcherLoadForce([](void *user, KernelPatcher &patcher) { SYSLOG("demo", "KernelPatcher initialised"); }, nullptr); // 2. Declare a kext to watch and register a load callback static KernelPatcher::KextInfo kextList[] = { { "com.apple.iokit.IOGraphicsFamily", nullptr, 0, { /* sys flags */ }, { /* user flags */ } } }; lilu.onKextLoadForce(kextList, arrsize(kextList), [](void *user, KernelPatcher &patcher, size_t id, mach_vm_address_t slide, size_t size) { SYSLOG("demo", "IOGraphicsFamily loaded at " PRIKADDR, CASTKADDR(slide)); }, nullptr); // 3. Register a userspace process callback static UserPatcher::ProcInfo procs[] = { { "/usr/bin/coreaudiod", (uint32_t)strlen("/usr/bin/coreaudiod"), 1 /* section */, UserPatcher::ProcInfo::MatchExact } }; lilu.onProcLoadForce(procs, arrsize(procs), [](void *user, UserPatcher &patcher, vm_map_t map, const char *path, size_t len) { SYSLOG("demo", "coreaudiod launched, map=%p", map); }, nullptr); // 4. Hook entitlement checks lilu.onEntitlementRequestForce([](void *user, task_t task, const char *ent, OSObject *&val) { if (!strcmp(ent, "com.apple.private.allow-explicit-graphics-priority")) { val = kOSBooleanTrue; // grant the entitlement } }, nullptr); ``` ``` -------------------------------- ### LiluAPI Callbacks for Plugin Events Source: https://context7.com/acidanthera/lilu/llms.txt The `LiluAPI` singleton (`lilu`) provides entry points for plugins to register callbacks for various lifecycle events. Use these to hook into kernel patcher initialization, kext loading, process execution, and entitlement checks. ```cpp #include #include // Called from pluginStart() after shouldLoad() succeeds // 1. Register a patcher-ready callback lilu.onPatcherLoadForce([](void *user, KernelPatcher &patcher) { SYSLOG("demo", "KernelPatcher initialised"); }, nullptr); // 2. Declare a kext to watch and register a load callback static KernelPatcher::KextInfo kextList[] = { { "com.apple.iokit.IOGraphicsFamily", nullptr, 0, { /* sys flags */ }, { /* user flags */ } } }; lilu.onKextLoadForce(kextList, arrsize(kextList), [](void *user, KernelPatcher &patcher, size_t id, mach_vm_address_t slide, size_t size) { SYSLOG("demo", "IOGraphicsFamily loaded at " PRIKADDR, CASTKADDR(slide)); }, nullptr); // 3. Register a userspace process callback static UserPatcher::ProcInfo procs[] = { { "/usr/bin/coreaudiod", (uint32_t)strlen("/usr/bin/coreaudiod"), 1 /* section */, UserPatcher::ProcInfo::MatchExact } }; lilu.onProcLoadForce(procs, arrsize(procs), [](void *user, UserPatcher &patcher, vm_map_t map, const char *path, size_t len) { SYSLOG("demo", "coreaudiod launched, map=%p", map); }, nullptr); // 4. Hook entitlement checks lilu.onEntitlementRequestForce([](void *user, task_t task, const char *ent, OSObject *&val) { if (!strcmp(ent, "com.apple.private.allow-explicit-graphics-priority")) { val = kOSBooleanTrue; // grant the entitlement } }, nullptr); ``` -------------------------------- ### DeviceInfo / BaseDeviceInfo Source: https://context7.com/acidanthera/lilu/llms.txt APIs for enumerating PCI devices and accessing base system information early in the boot process. ```APIDOC ## DeviceInfo / BaseDeviceInfo ### Description `DeviceInfo` enumerates PCI devices (IGPU, external GPUs, audio controllers, ME) and provides framebuffer/layout-id resolution. `BaseDeviceInfo` is available earlier in boot and exposes CPU generation, firmware vendor, model identifier, and bootloader type. ### Methods - `BaseDeviceInfo::get()`: Returns a const reference to the `BaseDeviceInfo` object. - `DeviceInfo::create()`: Creates a `DeviceInfo` object. - `DeviceInfo::deleter(DeviceInfo *di)`: Deletes the `DeviceInfo` object. - `DeviceInfo::processSwitchOff()`: Processes properties to disable external GPUs. - `DeviceInfo::isConnectorLessPlatformId(uint32_t framebufferId)`: Checks if the platform ID indicates a connector-less platform. ### Members #### `BaseDeviceInfo` Members - **cpuVendor** (uint8_t): CPU vendor information. - **cpuGeneration** (uint8_t): CPU generation. - **modelIdentifier** (const char *): System model identifier. - **boardIdentifier** (const char *): System board identifier. - **firmwareVendor** (uint8_t): Firmware vendor information. - **bootloaderVendor** (uint8_t): Bootloader vendor information. #### `DeviceInfo` Members - **videoBuiltin** (void *): Pointer to the built-in GPU. - **audioBuiltinAnalog** (void *): Pointer to the built-in analog audio controller. - **reportedFramebufferId** (uint32_t): The reported framebuffer ID. - **reportedLayoutId** (uint32_t): The reported layout ID. - **videoExternal** (vector): A vector of information about external GPUs. #### `ExternalGPUInfo` Members (within `videoExternal`) - **vendor** (uint16_t): Vendor ID of the external GPU. - **video** (void *): Pointer to the video controller of the external GPU. - **audio** (void *): Pointer to the audio controller of the external GPU. ### Return Value - `BaseDeviceInfo::get()`: Returns a const reference to `BaseDeviceInfo`. - `DeviceInfo::create()`: Returns a pointer to `DeviceInfo` or `nullptr` on failure. - `DeviceInfo::isConnectorLessPlatformId()`: Returns `true` if the platform ID is connector-less, `false` otherwise. ### Example ```cpp // BaseDeviceInfo: available at any time after Lilu init const auto &bdi = BaseDeviceInfo::get(); SYSLOG("dev", "CPU: vendor=%d gen=%d model=%s board=%s", (int)bdi.cpuVendor, (int)bdi.cpuGeneration, bdi.modelIdentifier, bdi.boardIdentifier); // DeviceInfo: full PCI device scan (use from onPatcherLoad onwards) auto *di = DeviceInfo::create(); if (!di) { SYSLOG("dev", "DeviceInfo::create failed"); return; } SYSLOG("dev", "IGPU=%p HDEF=%p framebufferId=0x%08X layoutId=%u", di->videoBuiltin, di->audioBuiltinAnalog, di->reportedFramebufferId, di->reportedLayoutId); for (size_t i = 0; i < di->videoExternal.size(); i++) { auto &egpu = di->videoExternal[i]; SYSLOG("dev", "eGPU[%zu] vendor=0x%04X video=%p audio=%p", i, egpu.vendor, egpu.video, egpu.audio); } di->processSwitchOff(); DeviceInfo::deleter(di); // Check connector-less platform bool noConn = DeviceInfo::isConnectorLessPlatformId(di->reportedFramebufferId); SYSLOG("dev", "connector-less: %d", noConn); ``` ``` -------------------------------- ### Basic Capstone API Usage Source: https://github.com/acidanthera/lilu/blob/master/capstone/bindings/python/BUILDING.txt Demonstrates the most basic usage of the Capstone API to retrieve essential instruction information like address, mnemonic, and operands. ```python import capstone # Example usage of test_basic.py # This code shows the most simple form of API where we only want to get basic # information out of disassembled instruction, such as address, mnemonic and # operand string. ``` -------------------------------- ### Logging Macros in C++ Source: https://context7.com/acidanthera/lilu/llms.txt Demonstrates the usage of different logging macros (SYSLOG, DBGLOG, PANIC_COND) for outputting messages at various severity levels. SYSLOG is always printed, DBGLOG is for debug builds, and PANIC_COND triggers a fatal log if the condition is met. ```cpp #include // --- Logging --- SYSLOG("module", "always printed: value=%d", 42); DBGLOG("module", "only in DEBUG builds: %s", "hi"); PANIC_COND(ptr == nullptr, "module", "fatal: null pointer received"); ``` -------------------------------- ### WIOKit - IOKit Registry Traversal and Property Access Source: https://context7.com/acidanthera/lilu/llms.txt Offers helper functions for navigating the IORegistry, accessing typed OSData properties, reading PCI configuration registers, and retrieving device information. ```APIDOC ## WIOKit — `kern_iokit.hpp` `WIOKit` provides helper functions for IORegistry traversal, typed OSData property access, PCI config register reads, device address retrieval, and device renaming. ```cpp #include void ioKitDemo(IORegistryEntry *pciRoot) { // Find IGPU by prefix under PCI root auto *igpu = WIOKit::findEntryByPrefix("IODeviceTree:/PCI0@0", "IGPU", gIOServicePlane); if (igpu) { // Read typed OSData property uint32_t devId = 0; if (WIOKit::getOSDataValue(igpu, "device-id", devId)) SYSLOG("wio", "IGPU device-id=0x%04X", devId); // Read PCI config register uint16_t vendor = (uint16_t)WIOKit::readPCIConfigValue( igpu, WIOKit::kIOPCIConfigVendorID, 0, 2); SYSLOG("wio", "vendor=0x%04X", vendor); // Retrieve bus/device/function uint8_t bus, dev, fn; WIOKit::getDeviceAddress(igpu, bus, dev, fn); SYSLOG("wio", "BDF %02X:%02X.%X", bus, dev, fn); // Rename device with compatible fix WIOKit::renameDevice(igpu, "GFX0", true); } // Iterate all GFX0 entries using a callback WIOKit::findEntryByPrefix("IODeviceTree:/PCI0@0", "GFX0", gIOServicePlane, [](void *user, IORegistryEntry *entry) -> bool { SYSLOG("wio", "found eGPU: %s", entry->getName()); return false; // keep searching }, false, nullptr); // Await publishing before accessing if (WIOKit::awaitPublishing(igpu)) SYSLOG("wio", "IGPU published"); } ``` ``` -------------------------------- ### Batch-Solve Kext Symbols and Apply Binary Patch Source: https://context7.com/acidanthera/lilu/llms.txt Use solveMultiple for batch symbol resolution in kexts with range validation. Apply binary find/replace patches using applyLookupPatch to modify code at runtime. ```cpp #include void onKextLoaded(void *, KernelPatcher &patcher, size_t id, mach_vm_address_t slide, size_t size) { // Batch-solve multiple kext symbols with range validation mach_vm_address_t addrA = 0, addrB = 0; KernelPatcher::SolveRequest solves[] = { { "__ZN15IOHIDEventQueue5startEP9IOService", addrA }, { "__ZN15IOHIDEventQueue4stopEP9IOService", addrB }, }; patcher.solveMultiple(id, solves, slide, size); // Binary find/replace patch (e.g. disable a check) static const uint8_t find[] = { 0x84, 0xC0, 0x74, 0x12 }; static const uint8_t replace[] = { 0x84, 0xC0, 0x90, 0x90 }; KernelPatcher::LookupPatch patch = { &kextList[0], find, replace, 4, 1 }; patcher.applyLookupPatch(&patch); patcher.clearError(); // Virtual function hook // KernelPatcher::routeVirtual(service, vtableOffset, myImpl, &orgImpl); } ``` -------------------------------- ### CircularBuffer Usage in C++ Source: https://context7.com/acidanthera/lilu/llms.txt Demonstrates the initialization, data pushing, data popping, and deinitialization of a CircularBuffer. It requires a pre-allocated storage array. ```cpp // --- CircularBuffer --- static uint32_t storage[64]; CircularBuffer ring; ring.init(storage); ring.push(0xCAFEBABE); uint32_t val; ring.pop(val); // val == 0xCAFEBABE ring.deinit(); ``` -------------------------------- ### EfiRuntimeServices - EFI Runtime Services Wrapper Source: https://context7.com/acidanthera/lilu/llms.txt Encapsulates EFI runtime services, allowing for the retrieval and setting of EFI variables and system resets directly from the kernel, with support for 32/64-bit EFI bridging. ```APIDOC ## EfiRuntimeServices — `kern_efi.hpp` `EfiRuntimeServices` wraps EFI runtime services, enabling get/set of EFI variables and system reset from within the kernel, with proper 32/64-bit EFI bridging. ```cpp #include void efiDemo() { // Obtain a locked EFI runtime services handle auto *efi = EfiRuntimeServices::get(true /* lock */); if (!efi) { SYSLOG("efi", "EFI runtime not available"); return; } // Read a variable (e.g. Lilu vendor GUID variable "boot-args") char buf[512] = {}; uint64_t size = sizeof(buf); uint32_t attr = 0; uint64_t status = efi->getVariable( u"boot-args", &EfiRuntimeServices::LiluVendorGuid, &attr, &size, buf); if (status == 0 /* EFI_SUCCESS */) SYSLOG("efi", "boot-args (%llu bytes): %s", size, buf); // Write a variable const char *value = "debug=0x100"; efi->setVariable( u"my-var", &EfiRuntimeServices::LiluVendorGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, strlen(value) + 1, (void *)value); efi->put(); // release lock } ``` ``` -------------------------------- ### CPUInfo - CPUID and Topology Source: https://context7.com/acidanthera/lilu/llms.txt Provides functions to query CPU vendor, generation, topology, and feature bits using the CPUID instruction. Includes raw CPUID access and generation retrieval. ```APIDOC ## CPUInfo — `kern_cpu.hpp` `CPUInfo` provides CPUID-based queries for CPU vendor, generation, topology, and individual feature bits. `getCpuid()` is the raw wrapper around the `cpuid` instruction. ```cpp #include void queryCPU() { CPUInfo::CpuTopology topo {}; if (CPUInfo::getCpuTopology(topo)) { SYSLOG("cpu", "packages=%u physical=%u logical=%u", topo.packageCount, topo.totalPhysical(), topo.totalLogical()); } // Raw CPUID uint32_t eax, ebx, ecx, edx; if (CPUInfo::getCpuid(1, 0, &eax, &ebx, &ecx, &edx)) { CPUInfo::CpuVersion ver; memcpy(&ver, &eax, sizeof(ver)); SYSLOG("cpu", "family=%u extModel=%u model=%u stepping=%u", ver.family, ver.extendedModel, ver.model, ver.stepping); bool hasAVX2 = (ecx & CPUInfo::bit_AVX2) != 0; // leaf 7, but same bit constant bool hasAESNI = (ecx & CPUInfo::bit_AESNI) != 0; SYSLOG("cpu", "AESNI=%d", hasAESNI); } // Generation (prefer BaseDeviceInfo::get().cpuGeneration) uint32_t family, model, stepping; auto gen = CPUInfo::getGeneration(&family, &model, &stepping); SYSLOG("cpu", "generation=%d model=0x%02X", (int)gen, model); } ``` ``` -------------------------------- ### Define and Apply User Patcher Binary Modifications Source: https://context7.com/acidanthera/lilu/llms.txt Define binary modifications using BinaryModPatch and BinaryModInfo for userspace binaries. Register these patches using onProcLoadForce to apply them when specific processes are loaded. ```cpp #include // Patch 4 bytes in WindowServer's __TEXT,__text static const uint8_t wsFind[] = { 0x85, 0xC0, 0x74, 0x0A }; static const uint8_t wsReplace[] = { 0x85, 0xC0, 0xEB, 0x0A }; static UserPatcher::BinaryModPatch wsPatch = { CPU_TYPE_X86_64, 0, // flags (0 = apply globally) wsFind, wsReplace, sizeof(wsFind), 0, // skip first N occurrences 1, // patch count (0 = all) UserPatcher::SegmentTextText, 0 }; static UserPatcher::BinaryModInfo wsMod = { "/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight", &wsPatch, 1, 0, 0, 0, 0 // TEXT/DATA bounds filled by Lilu at load time }; static UserPatcher::ProcInfo wsProc = { "/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight", (uint32_t)strlen("/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight"), 1, UserPatcher::ProcInfo::MatchExact }; // Called from pluginStart() void registerUserPatches() { lilu.onProcLoadForce(&wsProc, 1, [](void *, UserPatcher &up, vm_map_t map, const char *path, size_t len) { DBGLOG("user", "SkyLight loaded, applying patch"); }, nullptr, &wsMod, 1); } // Check shared cache membership at runtime bool inCache = UserPatcher::matchSharedCachePath( "/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics"); ``` -------------------------------- ### DeviceInfo - Enumerate PCI Devices and Resolve Framebuffer IDs Source: https://context7.com/acidanthera/lilu/llms.txt Enumerates PCI devices including GPUs and audio controllers, and provides framebuffer/layout-id resolution. `BaseDeviceInfo` is available earlier in boot for CPU and firmware information. ```cpp #include void onPatcherLoad(void *, KernelPatcher &) { // BaseDeviceInfo: available at any time after Lilu init const auto &bdi = BaseDeviceInfo::get(); SYSLOG("dev", "CPU: vendor=%d gen=%d model=%s board=%s", (int)bdi.cpuVendor, (int)bdi.cpuGeneration, bdi.modelIdentifier, bdi.boardIdentifier); SYSLOG("dev", "Firmware: %d Bootloader: %d", (int)bdi.firmwareVendor, (int)bdi.bootloaderVendor); // DeviceInfo: full PCI device scan (use from onPatcherLoad onwards) auto *di = DeviceInfo::create(); if (!di) { SYSLOG("dev", "DeviceInfo::create failed"); return; } SYSLOG("dev", "IGPU=%p HDEF=%p framebufferId=0x%08X layoutId=%u", di->videoBuiltin, di->audioBuiltinAnalog, di->reportedFramebufferId, di->reportedLayoutId); for (size_t i = 0; i < di->videoExternal.size(); i++) { auto &egpu = di->videoExternal[i]; SYSLOG("dev", "eGPU[%zu] vendor=0x%04X video=%p audio=%p", i, egpu.vendor, egpu.video, egpu.audio); } // Honour disable-external-gpu / -wegnoegpu properties di->processSwitchOff(); DeviceInfo::deleter(di); // Check connector-less platform bool noConn = DeviceInfo::isConnectorLessPlatformId(di->reportedFramebufferId); SYSLOG("dev", "connector-less: %d", noConn); } ``` -------------------------------- ### Capstone API for Detailed Instruction Information Source: https://github.com/acidanthera/lilu/blob/master/capstone/bindings/python/BUILDING.txt Demonstrates how to access architecture-neutral details within disassembled instructions, such as implicit registers read/written and instruction groups. ```python import capstone # Example usage of test_detail.py # This code shows how to access to architecture-neutral information in disassembled # instructions, such as implicit registers read/written, or groups of instructions # that this instruction belong to. ``` -------------------------------- ### Typed Buffer Allocation in C++ Source: https://context7.com/acidanthera/lilu/llms.txt Demonstrates allocating and deallocating a typed buffer using Buffer::create and Buffer::deleter. The buffer is allocated with a specified number of elements of a given type. ```cpp // --- Buffer allocation --- auto *arr = Buffer::create(256); // allocates 256 * sizeof(uint32_t) if (arr) { arr[0] = 0xDEADBEEF; Buffer::deleter(arr); } ``` -------------------------------- ### Build Static Library Source: https://github.com/acidanthera/lilu/blob/master/capstone/CMakeLists.txt Configures the build to create a static library named 'capstone-static'. This is used when dynamic linking is not desired. ```cmake add_library(capstone-static STATIC ${ALL_SOURCES} ${ALL_HEADERS}) set_property(TARGET capstone-static PROPERTY OUTPUT_NAME capstone) set(default-target capstone-static) ``` -------------------------------- ### Configure Package Configuration File Source: https://github.com/acidanthera/lilu/blob/master/capstone/CMakeLists.txt Configures the 'capstone.pc' file using a template, embedding version information. This file is used by pkg-config for dependency management. ```cmake configure_file(capstone.pc.in capstone.pc @ONLY) ``` -------------------------------- ### Kernel Version Check in C++ Source: https://context7.com/acidanthera/lilu/llms.txt Shows how to check the current kernel version against a specific version (e.g., BigSur) using the getKernelVersion() function. This is useful for applying version-specific logic. ```cpp // --- Kernel version check --- if (getKernelVersion() >= KernelVersion::BigSur) SYSLOG("util", "running macOS 11+"); ``` -------------------------------- ### OSObjectWrapper for Non-OSObject Types in C++ Source: https://context7.com/acidanthera/lilu/llms.txt Shows how to wrap non-OSObject types within the IOKit object hierarchy using OSObjectWrapper. This allows non-IOKit objects to be managed and interacted with using IOKit's reference counting. ```cpp // --- OSObjectWrapper (wrap non-OSObject into IOKit world) --- MyStruct *raw = new MyStruct(); auto *wrapper = OSObjectWrapper::with(raw); auto *recovered = wrapper->get(); wrapper->release(); ``` -------------------------------- ### Source Grouping Source: https://github.com/acidanthera/lilu/blob/master/capstone/CMakeLists.txt Organizes source files into logical groups within the build system's file explorer. This improves project navigation and management. ```cmake source_group("Source\\Engine" FILES ${SOURCES_ENGINE}) source_group("Source\\ARM" FILES ${SOURCES_ARM}) source_group("Source\\ARM64" FILES ${SOURCES_ARM64}) source_group("Source\\Mips" FILES ${SOURCES_MIPS}) source_group("Source\\PowerPC" FILES ${SOURCES_PPC}) source_group("Source\\Sparc" FILES ${SOURCES_SPARC}) source_group("Source\\SystemZ" FILES ${SOURCES_SYSZ}) source_group("Source\\X86" FILES ${SOURCES_X86}) source_group("Source\\XCore" FILES ${SOURCES_XCORE}) ``` ```cmake source_group("Include\\Common" FILES ${HEADERS_COMMON}) source_group("Include\\Engine" FILES ${HEADERS_ENGINE}) source_group("Include\\ARM" FILES ${HEADERS_ARM}) source_group("Include\\ARM64" FILES ${HEADERS_ARM64}) source_group("Include\\Mips" FILES ${HEADERS_MIPS}) source_group("Include\\PowerPC" FILES ${HEADERS_PPC}) source_group("Include\\Sparc" FILES ${HEADERS_SPARC}) source_group("Include\\SystemZ" FILES ${HEADERS_SYSZ}) source_group("Include\\X86" FILES ${HEADERS_X86}) source_group("Include\\XCore" FILES ${HEADERS_XCORE}) ``` -------------------------------- ### MachInfo::create - Parse Mach-O Binaries Source: https://context7.com/acidanthera/lilu/llms.txt Parses Mach-O binaries from disk, prelinked kernel, or live memory to resolve symbol addresses and manage kernel write protection. Use directly for advanced scenarios or indirectly via `KernelPatcher`. ```cpp #include void examineKernel() { // Locate and parse the running kernel auto *ki = MachInfo::create(true, "mach_kernel"); if (!ki) { SYSLOG("mach", "create failed"); return; } static const char *kernPaths[] = { "/System/Library/Kernels/kernel", "/mach_kernel" }; if (ki->init(kernPaths, arrsize(kernPaths)) == KERN_SUCCESS) { ki->getRunningAddresses(); uint8_t *header = nullptr; size_t size = 0; ki->getRunningPosition(header, size); SYSLOG("mach", "kernel header at %p, size 0x%zX", header, size); auto addr = ki->solveSymbol("_PE_halt_restart"); SYSLOG("mach", "_PE_halt_restart = " PRIKADDR, CASTKADDR(addr)); // Enable kernel writing before patching, then disable MachInfo::setKernelWriting(true, KernelPatcher::kernelWriteLock); // ... write to kernel memory here ... MachInfo::setKernelWriting(false, KernelPatcher::kernelWriteLock); } ki->deinit(); MachInfo::deleter(ki); } // Find section bounds in an arbitrary Mach-O buffer vm_address_t vmSeg = 0, vmSect = 0; void *sectPtr = nullptr; size_t sectSize = 0; MachInfo::findSectionBounds(kextBuf, kextBufSize, vmSeg, vmSect, sectPtr, sectSize, "__TEXT", "__text"); ```