A virus wants to reproduce. A rootkit wants to stay.
More precisely: a rootkit wants to become the operating system's memory of what is running. Destruction and exfiltration come later. The first objective is to own the record. To become the source of truth that every monitoring tool, every task manager, every security scanner consults when it asks the question: what is actually happening on this machine?
If you own the answer to that question, you own the machine. The user can look directly at the process list and see a clean system. The administrator can run diagnostics and get reassuring output. The security tool can scan and report nothing. The malware is present, active, and consuming resources — and the OS has simply stopped reporting it.
Greg Hoglund and James Butler documented exactly how this worked in Rootkits: Subverting the Windows Kernel (2005). Two decades later, the technique is still operational. The delivery method has changed. The target has moved deeper. The trust problem has not been solved.
Ring 0 and the Hierarchy of Truth
The x86 architecture divides CPU privilege into rings. Ring 3 is where applications run — your browser, your text editor, your terminal. Ring 0 is where the operating system kernel runs. The kernel has access to everything: physical memory, hardware registers, the complete list of every process, thread, file, and network connection on the system.
When your Task Manager asks what processes are running, it does not look directly at the hardware. It asks the kernel. The kernel tells it. The kernel is the witness.
A rootkit that achieves Ring 0 access does not need to hide from the hardware. It needs to modify what the witness reports.
The 2005 technique was the SSDT hook — System Service Descriptor Table. The SSDT is the kernel's index of system calls: a table of function pointers that maps every system call name to its actual implementation. When any application — including security tools — calls ZwQuerySystemInformation to get the process list, the kernel looks up that function in the SSDT and executes it.
A rootkit with kernel access replaces the pointer in that table with a pointer to its own function. The real function still runs — the rootkit calls it to get the genuine data. Then it filters the output before returning it to the caller.
// 2005-era SSDT hook: intercept the process list query
NTSTATUS HookedZwQuerySystemInformation(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength)
{
// Get the real answer from the real kernel function
NTSTATUS status = OriginalZwQuerySystemInformation(
SystemInformationClass,
SystemInformation,
SystemInformationLength,
ReturnLength
);
// If the caller is asking for the process list, edit it
if (SystemInformationClass == SystemProcessInformation) {
RemoveProcessFromList(SystemInformation, TARGET_PID);
// The caller now receives a list that omits the rootkit's process
}
return status;
}
The Task Manager calls ZwQuerySystemInformation. It gets back a complete, accurate-looking list. The rootkit's process is not on it. The user sees a clean system. The wolf is in the room reading the newspaper.
DKOM: Editing the Kernel's Memory of Itself
The SSDT hook has a detection surface: if you know where the SSDT is and what the legitimate function pointers should be, you can check for modifications. Hoglund and Butler documented the deeper technique — Direct Kernel Object Manipulation.
The kernel maintains its own internal list of running processes in a structure called EPROCESS. Every process has an EPROCESS block. The blocks are linked in a doubly-linked list — each one points to the next and the previous. When the kernel needs to enumerate processes, it walks this list.
DKOM edits the list directly in kernel memory. No hook required. You find your process's EPROCESS block and relink the pointers around it — the previous entry points to the next entry, skipping yours entirely. The entry still exists in memory. The kernel has just stopped walking past it.
Before DKOM:
[svchost] ←→ [malware.exe] ←→ [explorer.exe]
After DKOM:
[svchost] ←→ [explorer.exe]
malware.exe still in memory — the list just no longer includes it
Tools that check for SSDT hooks find nothing because no hooks exist. The kernel consults its own data structures, which have been surgically modified. Even a kernel debugger examining the process list through the official API will not see the hidden process. You have to walk raw physical memory and compare it to the linked list to find the discrepancy.
This is the technique that made administrators distrust their own machines — a discrepancy between what the system reported and what was actually present, with no reliable way to know which one was the truth.
PatchGuard, HVCI, Secure Boot — and the Attack Surface Moved Down
Between 2005 and 2026, Microsoft deployed a serious stack of kernel defenses:
Kernel Patch Protection (PatchGuard) — introduced in 64-bit Windows, periodically checks critical kernel structures including the SSDT for unauthorized modifications. If it detects tampering, it issues a BSOD. This killed the naive SSDT hook on 64-bit systems.
Driver Signature Enforcement — kernel-mode drivers must be signed by Microsoft-approved certificates. Loading unsigned code into Ring 0 is blocked by default. This raised the cost of kernel access significantly.
Hypervisor-Protected Code Integrity (HVCI) — uses the CPU's virtualization extensions to place the kernel itself in a protected memory region that even Ring 0 code cannot write to. Code integrity checks run at the hypervisor level, below the OS.
Secure Boot — the UEFI firmware verifies the bootloader signature before executing it, and the bootloader verifies the kernel. An unsigned or tampered kernel should not load.
Each of these is a real defense. None of them solved the trust problem. They moved the attack surface.
