This is the official repository for Gillyweed, a Linux Loadable Kernel Module (LKM) Rootkit. Building on our track record of sharing offensive research with the community - from Abyss (Windows UEFI Bootkit) and Benthic (Windows Kernel-Mode Rootkit) to Antarctic (first Public Linux UEFI Bootkit) - Gillyweed dives into the kernel-mode persistence and stealth techniques that have long defined the LKM rootkit landscape, making them accessible for study, education, and defensive improvement.
Gillyweed is a Linux kernel-mode rootkit implemented as a Loadable Kernel Module (LKM). It demonstrates the core techniques used by real-world rootkits to achieve stealth on a running Linux system: hiding files, concealing processes, and making network connections invisible to both user-space tools and packet capture utilities. The project is structured into two components that work together - a kernel module that performs the actual hooking and manipulation, and a user-space console application that communicates with it through a custom device and IOCTL interface to control its behavior at runtime.
The project follows a two-depth architecture that separates kernel-mode logic from user-space control:
-
ConsoleApplication is the user-space component. It acts as the operator interface, sending commands to the kernel module through IOCTLs on a custom device node. This is where the operator decides what to hide - which files to conceal, which processes to make invisible, which connections to suppress - and the console application translates those decisions into IOCTL calls that the kernel module processes.
-
LoadableKernelModule is the kernel-space component. Once loaded via insmod, it registers a character device and exposes an IOCTL handler that the console application uses to issue directives. The module's core logic lives in the "Functions/" directory, where each capability - hooking, file hiding, process hiding, and connection hiding - is implemented in its own dedicated source pair.
At its core, Gillyweed relies on ftrace to intercept kernel functions. Ftrace is a tracing framework built into the Linux kernel, originally designed for debugging and performance analysis, but it also exposes the ability to redirect function calls. which is exactly what a rootkit needs to insert itself between the kernel and its normal behavior.
The general flow works as follows: the rootkit first needs to find the address of the kernel function it wants to hook. Since modern kernels no longer export most internal symbols directly, the module uses "kallsyms_lookup_name" to resolve function addresses at runtime by walking the kernel's symbol table. Once the address of a target function is known, the rootkit registers an ftrace callback on that function. When the hooked function is called by the kernel, ftrace redirects execution to the rootkit's replacement function instead. The replacement function can inspect arguments, modify data, suppress results, or simply call through to the original - depending on what the rootkit wants to achieve. This approach avoids overwriting kernel code in memory (no inline patching, no modifying the syscall table directly), making it cleaner and more compatible across kernel versions than traditional hooking methods.
Gillyweed hooks seven kernel functions, grouped by the capability they enable.
The rootkit hooks getdents64, the system call that user-space tools like ls, find, and tree rely on to list directory contents. When the kernel returns directory entries to a calling process, the hooked function inspects the results and removes any entries that match the rootkit's hide list before they reach user space. The file still exists on disk - it can still be accessed by name if you know it's there - but it becomes invisible to any tool that enumerates directories.
The rootkit hooks kill, the system call used to send signals to processes. By intercepting kill, the rootkit can prevent tools from discovering or interacting with hidden processes. When combined with file hiding on /proc (where each running process has a numbered directory), this makes target processes invisible to ps, top, htop, and similar tools.
Network connection hiding is the most layered capability, requiring hooks on four separate kernel functions to cover all the ways user-space tools can enumerate connections.
tcp4_seq_show and tcp6_seq_show are the seq_file show functions for /proc/net/tcp and /proc/net/tcp6 respectively. Tools like netstat that read these proc files to list active TCP connections will never see the hidden entries because the hooked functions simply skip them during output generation.
inet_sk_diag_fill is the function used by the netlink-based socket diagnostics interface, which is what modern tools like ss use instead of reading /proc/net/tcp directly. Hooking this function ensures that even ss - which many administrators have switched to as a replacement for netstat - cannot reveal the rootkit's hidden connections.
Beyond hiding connections from enumeration, the rootkit also hides network traffic from capture and inspection.
ip_rcv is the kernel's main IP packet reception function - the entry point where incoming packets first hit the network stack. By hooking this function, the rootkit can selectively drop or hide packets before they are processed further, making certain traffic invisible at the network layer.
tpacket_rcv is the function responsible for delivering packets to raw sockets using the AF_PACKET interface with the TPACKET ring buffer. This is the fast path that packet capture tools like tcpdump, Wireshark, and any libpcap-based application use to sniff traffic. Hooking this function means that even if an administrator runs a packet capture on the machine, the rootkit's traffic never appears in the capture output.
