46 min read

The Registry Adventure: How One Researcher Read 100,000 Lines of Windows Kernel C and Found 50 Bugs

Between May 2022 and December 2023, Mateusz Jurczyk audited the Windows registry parser and produced 50 CVEs. The methodology is the story.

Permalink

1. I Loaded a Registry Hive From a Network Share and the Kernel Crashed

In May 2022, Mateusz Jurczyk pointed a coverage-guided fuzzer at the Windows registry. Within days the fuzzer crashed the kernel and produced CVE-2022-35768. Twenty months later, when he stopped, Jurczyk had filed thirty-nine bug reports against the same subsystem, Microsoft had assigned fifty CVEs to his name, and the fuzzer was sitting unused. Somewhere in those first few days, Jurczyk had realised that the bugs he actually wanted were ones a fuzzer could not see [1].

The threat model is almost too small to fit on a slide. An unprivileged process running at Medium Integrity Level calls RegLoadAppKey with the path of a file the attacker controls. The kernel opens the file, runs its in-house binary parser on the bytes, and exposes the resulting tree of keys back to the caller through a private handle. Microsoft's own documentation describes the surface this way: the hive becomes a private namespace reachable only through that handle, but "the registry will prevent an application from accessing keys in this hive using an absolute path" [2]. The handle is sandboxed. The parser, which is the interesting part, is not. It runs in the kernel with attacker-supplied input, and it has been doing so since Windows Vista.

Hive

A file-and-in-memory tree of registry keys and values, encoded in Microsoft's regf binary format and operated on by the Windows kernel's Configuration Manager. Hives live on disk as *.dat files (plus .log and .alt companions) and are loaded into the kernel's address space when an application or the operating system opens them [3].

Medium IL

Medium Integrity Level: the integrity label an ordinary logged-in Windows user runs at. Crossing from Medium IL to SYSTEM is what a kernel local privilege escalation does. The class of bug this article is about reliably accomplishes that crossing from an attacker-supplied file.

The fifty CVEs that Jurczyk's audit produced are not a uniform pile. Most of them are kernel local privilege escalations (LPEs); a handful are information disclosures; one is a denial of service [1]. The seventeen that matter for this article are the cohort Jurczyk later catalogued in his Project Zero post on practical exploitation: a tight set of memory-corruption bugs that share a single root cause and a single exploitation primitive, which he named hive-based memory corruption [4].

Ctrl + scroll to zoom
The attacker-reachable path from a Medium-IL process to the kernel-mode regf parser. The hive file is the input the kernel runs binary code on.

Two questions are doing all the work in this article. Why is a thirty-year-old binary parser running in the Windows kernel willing to accept arbitrary input from unprivileged users? And why did it take a single researcher twenty months to map the consequences? The first question is about Microsoft and design. The second is about Jurczyk and method. To take either one seriously, we have to start at the very beginning -- with Windows 3.1.

2. Why There Is a Hive Parser in the Kernel

In 1992 the registry was 64 kilobytes. Windows 3.1 shipped with a single file at C:\WINDOWS\REG.DAT, encoded in a small custom format whose magic bytes spelled SHCC3.10. It held one top-level key, no named values, and existed solely to register OLE objects and shell file-type associations [5]. The first regedit.exe shipped alongside it. There was no security descriptor, no recovery story, and no kernel involvement. You could fit the whole thing in the L2 cache of a 2026 laptop.

Windows NT 3.1, released in July 1993, swept that design away and introduced something different. The new format was called regf, and the design decision that has determined the next thirty-three years of Windows kernel security was made here: the on-disk format and the in-memory format are the same format. Jurczyk's blog post on the regf file format states this plainly: "the regf format aims to bypass the reparsing step -- likely to optimize the memory/disk synchronization process -- and reconcile the two types of data encodings into a single one... This unique approach comes with its own set of challenges, and has been a contributing factor in a number of historical vulnerabilities" [6].

regf

Microsoft's binary registry file format, introduced in Windows NT 3.1 (1993) and stabilized at v1.3 in NT 4.0 (1996). Later versions (v1.4 Whistler beta, v1.5 XP, v1.6 Win10 AU) layer features on top but all remain cross-compatible with the v1.3 baseline. The same format encodes a hive on disk and in kernel memory; there is no separate "loaded" representation [6]. Microsoft has never published an official regf specification [6].

The motivation was reasonable. NT was a multi-user, securable, network-capable operating system targeting servers; its configuration store needed access control, transactional recovery, and the ability to grow well past 64 KiB. Reusing the same byte layout for disk and memory meant a hive could be loaded by mapping or copying its file image, modified in place, and flushed back without a serialization step.

Pre-release builds used regf v1.0; the first shipping NT used v1.1; NT 3.5 and 3.51 used v1.2 [5]. The Win9x consumer line went a different direction entirely, with an incompatible format called CREG that never made it into the NT lineage and quietly died with Windows Me. Windows 95, 98, and Me used a completely incompatible CREG format that did not survive into NT. The modern registry inherits nothing from the Win9x line; every memory corruption bug Jurczyk found descends from the NT 3.1 decision.

The next stabilization happened on July 29, 1996. Windows NT 4.0 (whose pre-RTM development builds had introduced v1.3 in 1995) froze the backward-compatibility baseline at regf v1.3, added a "fast leaves" optimization for subkey lookups, and locked in the binary layout that the modern Windows kernel still reads thirty years later. Later versions layered features on top -- v1.4 (Whistler beta, big values), v1.5 (Windows XP, 2001, hash leaves), and v1.6 (Windows 10 Anniversary Update, 2016, layered keys) -- but every one of them remains cross-compatible with v1.3-aware parsers, and v1.3 itself still encodes a number of Windows 11 hives [6].

Microsoft's own documentation for RegSaveKeyExA describes REG_STANDARD_FORMAT as "the only format supported by Windows 2000," meaning that hives written by Windows 2000 and later, in the default format, are interchangeable with hives produced by Windows NT 4.0 [7]. A hive file authored on NT 4.0 in 1996 will still mount on Windows 11 in 2026. That backward compatibility is not an accident; it is a load-bearing requirement of system-image management, forensics, and third-party installers.

Ctrl + scroll to zoom
A condensed timeline of the registry's evolution from a 64 KiB OLE/COM database to the section-backed kernel data structure shipping in Windows 11. Six format generations, no architectural reset.

Ten years later, in November 2006, Windows Vista added the second design decision that completes the threat model. RegLoadAppKey shipped as a public Win32 API, allowing an unprivileged application to load an arbitrary hive file as a private "application hive" reachable only through the returned handle [2]. The motivation was legitimate; per-application configuration sidecars are a reasonable feature.

The consequence was that the kernel-mode regf parser, frozen at v1.3 a decade earlier and unchanged in any of its load-bearing routines, was now reachable from Medium IL with no special privileges. Jurczyk's introduction to the series says it plainly: "arbitrary registry hives can be loaded from disk without any special privileges via the RegLoadAppKey API (since Windows Vista)" [1].

RegLoadAppKey

A Win32 API introduced in Windows Vista (2006) that lets an unprivileged process load an arbitrary hive file as a private "app hive," running the full kernel-mode regf parser on attacker-supplied bytes. Microsoft documents the API as one that "loads the specified registry hive as an application hive" reachable only through a private handle; the parser itself is not sandboxed [2].

With the parser reachable from low privilege and the format frozen for thirty years, the only question left was who would notice.

3. Prior Attempts: The "Fuzzed Precisely Once" Misconception

Before we go further, a fact you may have heard in a conference Q&A: the Windows registry is "the most-fuzzed subsystem in Windows," "fuzzed precisely once," by one person. It is not true. The registry has been poked at, in one form or another, since 1996. None of those efforts found the bug class that Jurczyk would eventually name -- but that is a different statement, and the difference is the point of this section.

The first instrument to touch the registry from outside Microsoft was Mark Russinovich and Bryce Cogswell's RegMon, released in 1996 as a Sysinternals utility. RegMon was a kernel driver that intercepted every registry call and surfaced the path, type, process identifier, and result to a user-mode console. It was operational tooling, not a bug-finding tool. Microsoft's own page on the modern successor, Process Monitor, attributes the lineage to Russinovich and notes that Procmon "combines the features of two legacy Sysinternals utilities, Filemon and Regmon" [8]. RegMon made the registry observable from outside the kernel. It could not see corruption inside a hive.

The next wave came from forensics. Microsoft never published a regf specification, so the digital-forensics community reverse-engineered one. Timothy D. Morgan's regfi paper appeared at DFRWS in 2009. Joachim Metz's libregf project published its first format-spec document in July 2009 and has been updated continuously through 2026 [9]. Maxim Suhanov's regf specification covers, among other things, the old single-.log dirty-vector recovery format and the new two-file LOG1/LOG2 layout introduced in Windows 8.1 [10]. These were user-space parsers built to mount hive files for evidence extraction. They exercised the format from the outside. They never touched the kernel parser.

A separate research line, in parallel, pursued the layer above the parser. James Forshaw of Project Zero spent years hunting capability and access-control bugs in the registry's name-resolution and permission logic -- registry symbolic links, virtualization quirks, sandbox-escape paths that ride on registry redirection. Jurczyk's PZ #4 covers some of this surface in passing, noting that the registry has at least four distinct ways in which "access to a registry key can be transparently redirected to another path" [11]. These were logic bugs, not memory-corruption bugs. The parser was not the target.

Then, in 2016, Jurczyk and Forshaw collaborated on a black-box bitflipping fuzzing pass against RegLoadKey and RegLoadAppKey. Jurczyk acknowledges the collaboration directly in his retrospective: "I was also somewhat familiar with basic harnessing of the registry, having fuzzed it in 2016 together with James Forshaw" [1]. The cohort produced a handful of registry bug reports filed as Project Zero issues #873, #874, #876, and #993.

It did not find the hive-memory-corruption class. The reason is the same one that would defeat the 2022 fuzzer: random byte flips on a hive file produce a malformed-but-rejected hive far more often than they produce one that passes base-block validation, enters the parser proper, and exercises an interesting bug. Per-issue contents of the 2016 cohort are not anonymously fetchable; the Project Zero tracker now lives at project-zero.issues.chromium.org and redirects unauthenticated requests to a Google sign-in page [12]. The cohort's existence is primary-source-confirmed by Jurczyk's reference in PZ #1.

"The hive binary format is not very well suited for trivial bitflipping-style fuzzing, because it is structurally simple, and random mutations are much more likely to render (parts of) the hive unusable than to trigger any interesting memory safety violations." -- Mateusz Jurczyk, The Windows Registry Adventure #1 [1]

In early 2022, Jurczyk made a more serious attempt. He built a coverage-guided Bochs-based kernel fuzzer, the same lineage as his earlier Bochspwn work, and pointed it at the kernel's hive-loading path. Within days the harness produced its first registry kernel bug, filed as Project Zero issue #2299 and assigned CVE-2022-35768 by Microsoft. The fuzzer worked. It just did not scale to the bug class Jurczyk actually wanted, which is the part of the story that matters.

A frequent third-party confusion is worth naming and dispatching here. Bochspwn Reloaded is not the registry-research tool. The repository's own README describes the goal as detecting "the disclosure of uninitialized kernel stack/heap memory," not memory corruption, and reports "over 70 bugs in the Windows kernel" found by the tool in 2017 and early 2018 [13]. The 2018 white paper makes the same scope clear; the project's technical content is about shadow-memory representation and tainting stack frames and pool allocations to catch infoleaks [14]. The 2022 Bochs-based registry harness is a separate, unreleased instrument sharing the lineage but not the codebase.

Bochspwn Reloaded

A 2018 Bochs-based Project Zero tool by Mateusz Jurczyk for detecting uninitialized kernel memory disclosures via taint tracking [13]. Not the registry-audit instrument. The 2022 coverage-guided Bochs registry harness is a separate, unreleased tool that shares Bochspwn's general design but is not the public Bochspwn Reloaded repository.

Ctrl + scroll to zoom
Six methodological generations of researchers approaching the Windows registry from outside Microsoft. Each new wave inherited from but did not subsume the previous one.

Every prior attempt had hit the same ceiling. The bug class lived in the code, not in the file. And the code had not yet been read.

4. Six Generations of Hardening Without Redesign

Between 1992 and 2018, Microsoft shipped six generations of registry changes. Not one of them redesigned the parser. Every generation added a feature, hardened a recovery path, lifted a scale limit, or shifted a memory model. Each of those changes also created new surface for the next decade's attackers. The cell allocator at the heart of the format has been substantively the same routine for twenty-five years.

The table below collapses Stage 2's defensive arc into one view. Each row is a generation; the "Surface effect" column captures the bug class that became reachable as a side effect of the improvement.

GenYearWhat was addedSurface effect
A-11992reg.dat / SHCC3.10, 64 KiB OLE databaseNone in the kernel; user-mode only [5]
A-21993regf v1.0/v1.1, hybrid on-disk and in-memoryEvery memory-corruption bug class to follow [6]
A-31996regf v1.3 lock-in, fast-leaves optimization30-year backward compatibility freezes the parser [7]
A-3b2001 / 2016regf v1.5 (XP, hash leaves), v1.6 (Win10 AU, layered keys)New features, same v1.3-cross-compatible parser core [6]
A-42006RegLoadAppKey, KTM transactionsParser becomes reachable from Medium IL with no privileges [2]
A-52013LOG1/LOG2 incremental write-ahead loggingNew log-replay path becomes attacker-influenceable [6]
A-62018Section-backed hive mappingPages become pageable; double-fetch class enabled [6]

Each row deserves a sentence. A-1 is the registry's prehistory; nothing here lives in the kernel, but the hierarchical key/value mental model is established. A-2 is the load-bearing decision: hybrid on-disk and in-memory format, modified in place [6]. A-3 is the moment Microsoft signed a thirty-year contract; the format defined by REG_STANDARD_FORMAT is binary-compatible with NT 4.0 [7].

A-3b is the format-level feature layering done since: v1.5 (Windows XP, 2001) added hash leaves to speed up large subkey lookups, and v1.6 (Windows 10 Anniversary Update, 2016) added layered keys for differencing hives; both stay cross-compatible with v1.3-aware parsers, and v1.3 still encodes a number of Windows 11 hives [6]. A-4 is the entry-point change: RegLoadAppKey and the Kernel Transaction Manager arrive together in Vista, and both are now attacker-reachable [2].

A-5 introduces the new log format; PZ #5 describes "incremental logging added in Windows 8.1" as one of the two big runtime-recovery overhauls of the modern era [6]. A-6 is the section-backed mapping shipped in Windows 10 RS4 (April 2018), and is the change that makes a hive on an SMB share into a moving target -- hive pages become pageable, and a page that was validated on load can be evicted and re-read with different contents [6]. Some Windows 11 system hives, such as UsrClass.dat under HKU\<SID>_Classes, are still written in regf v1.3 -- a format frozen in 1996. The backward-compatibility freeze is not a hypothetical concern [6].

Cell

The unit of allocation inside a hive. A length-prefixed chunk of bytes; positive prefix means the cell is free, negative prefix means it is allocated, and the absolute value of the prefix is the size in bytes (multiples of eight). Cells are the building blocks of keys, values, security descriptors, and index nodes [10].

KCB

Key Control Block: the in-memory kernel object that represents an open registry key. It holds the cell index of the on-disk key node, a parent pointer, a refcount, and a per-key synchronization primitive [15]. The KCB tree is the live representation of every currently-open registry key.

Mapping the result is helpful before we get to the audit. Here is what a hive looks like in the 2025-era kernel from the bytes on disk up to the kernel-object tree that user-mode code touches.

Ctrl + scroll to zoom
A 2025-era hive in the Windows kernel: the on-disk file maps into a section, which is referenced by an _HHIVE inside a _CMHIVE, which the Configuration Manager exposes as a tree of Key Control Blocks.

The diagram is not a model; it is the structure. PZ #6 documents the exact sizes: _CMHIVE is 0x12F8 bytes and contains an embedded _HHIVE of 0x600 bytes at offset zero [15]. None of these objects existed in NT 3.1; what existed was the bottom three layers and a simpler kernel-side wrapper. The architecture grew. The cell allocator did not.

By 2018 the parser had been substantively unchanged for twenty-five years, and nobody had read all of it.

5. The Pivot: Audit, Not Fuzz

Return to May 2022, but now with the full context loaded. Six generations of hardening have created a thirty-year-old attack surface. Forty years of forensic and security research have not penetrated the parser. Jurczyk is sitting at his desk with a working coverage-guided Bochs harness and one good registry bug, and instead of letting the fuzzer run for another six months, he stops.

The detective work that produced the stop is documented in the introduction to the series. Jurczyk noticed two facts that together amount to a methodology critique.

First, the regf format is "structurally simple" in the sense that bitflipping a random byte usually produces an invalid base-block checksum, an out-of-range cell offset, or some other condition that the kernel rejects long before it reaches anything interesting [1]. The base-block validator is doing a lot of work.

Second, the bug class he was chasing -- one that produces kernel memory corruption from an attacker-controlled hive -- requires legal-on-disk hives that exercise particular combinations of features. The interesting bugs live in interactions: transactions plus virtualization plus predefined keys plus log replay, all in the same legal hive image. No byte-level mutator is going to synthesize that.

So Jurczyk did something almost retro. He pulled ntoskrnl.exe with public PDB symbols into the kind of static-and-dynamic analysis toolchain PZ #3 enumerates -- IDA Pro for cross-referencing, WinDbg attached to a kernel target, Ghidra alongside [16] -- and started reading the Configuration Manager. He cross-referenced every entry point against libregf, against Suhanov's spec, and against Windows Internals, Part 2, 7th edition by Allievi, Russinovich, Ionescu, and Solomon [@winint7-part2; @libregf-spec; @msuhanov-spec]. Every attacker-reachable function got traced to every cell read, write, free, and allocation on every path. PZ #3 lists the bibliography he assembled along the way and marks the Russinovich book with the equivalent of a gold star [16]. The methodology is twentieth-century. The yield is not.

The numbers came in twenty months later. Per PZ #1, the audit produced 39 bug reports, which Microsoft serviced as 44 CVEs in the 90-day cohort plus 6 more in a March 2024 low-severity batch, for 50 CVEs total; the average time from report to fix was 81 days [1]. By December 2024, with more Microsoft CVE assignments rolling in, PZ #5 was reporting 52 CVEs [6]. By May 2025, PZ #7 was at 53 [17]. The growth across the publication arc reflects CVE assignment, not new discoveries. "50+" is the safe headline figure.

Inside those 50 CVEs, a tight subset of 17 share a single root cause and a single exploitation primitive [4]. Jurczyk's PZ #8 gives them a name -- hive-based memory corruption -- and divides them into two subclasses. Spatial violations are cell-boundary overflows: writes that cross the boundary of a legitimately-allocated cell into an adjacent cell whose type, owner, or pointer the attacker now controls. Temporal violations are cell-reuse use-after-frees: writes through a cell-index reference whose backing storage has been freed and reallocated to attacker-influenced content. Spatial and temporal together; everything else is detail.

Hive-based memory corruption

Mateusz Jurczyk's coinage for the bug class that corrupts the in-memory representation of an active hive via the deterministic cell allocator [4]. The spatial subclass is cell-boundary overflows. The temporal subclass is cell-reuse use-after-frees. The class is named in PZ #8 and demonstrated on Windows 11 with all modern kernel mitigations enabled.

The exploitation primitive is the deliberate engineering of the cell allocator, and PZ #8 is unsentimental about it.

"The registry cell allocator... completely lacks any safeguards against memory corruption, and... has no element of randomness, making its behavior entirely predictable." -- Mateusz Jurczyk, The Windows Registry Adventure #8 [4]

A deterministic, unrandomized allocator with no integrity checks on its cell metadata is what you would design if you wanted recovery from a torn write to produce the same byte image every time. It is also, identically, what you would design if you wanted an exploit primitive that places a controlled object at a predictable cell index. The property that makes the parser correct under crash recovery and the property that makes it exploitable are the same property.

The bug class was semantic. The fuzzer was syntactic. That mismatch is the audit's entire reason for existing.

How does an attacker-controlled hive actually become a corruption primitive? The sequence is shorter than you might expect.

Ctrl + scroll to zoom
Lifecycle of an attacker-controlled hive from RegLoadAppKey to a corrupted cell. The kernel validates the base block, parses the bins, and allocates cells, but the cell allocator places attacker-influenced bytes at predictable indices.

The diagram makes the loss of generality clear. The base-block validator does its job; the bin and cell parser accept a legal hive; the cell allocator places attacker-shaped cells at deterministic indices; and then a second-stage operation -- a transaction abort, a log replay, a predefined-key dereference -- reuses a cell index whose backing storage no longer means what the kernel assumes. There is no point in the lifecycle where a fuzzer's mutator could have engineered the legal-on-disk-but-semantically-explosive hive that the audit's reader engineered by hand.

Coverage-guided fuzzing and manual audit are not equivalent tools on this target. The empirical numbers from the same researcher, on the same target, are instructive.

MethodResearcher-monthsGood registry kernel bugsEmpirical rate
Bitflipping fuzz of RegLoadKey / RegLoadAppKey (2016)~few [1]4 (PZ #873, #874, #876, #993)~1 per month or worse
Bochs coverage-guided harness (early 2022)~1 to 21 (CVE-2022-35768)~0.5 to 1 per month
Manual audit (May 2022 -- December 2023)2050 CVEs across 39 reports [1]~2.5 CVEs per month

To understand why hive-based memory corruption works as a primitive, we have to look at what the parser actually is.

6. Anatomy of the Configuration Manager

If you want to find bugs in the registry, you have to know exactly what a hive is. Here is what one looks like on disk and in memory.

A hive begins with a base block: a 4 KiB header that contains the magic string regf, the format version (v1.3 in modern hives), a sequence-number pair for crash recovery, a checksum, the root cell index, the hive length, the boot type and recovery information [@pz5-registry-adventure-5; @libregf-spec]. The validator that runs at hive load time vets this block first. If the checksum does not match, if the version is unrecognized, if the lengths do not add up, the parser refuses the file and no further code runs. This is the line of defense that ate 99% of the bitflipping fuzzer's effort in 2016 and again in 2022.

After the base block come one or more HBIN blocks. Each HBIN is a 4-KiB-multiple chunk of the hive carved into cells. Microsoft's documentation on registry hives describes the on-disk supporting files alongside the main hive: an .alt backup of the critical HKLM\System hive, a .log transaction log, and a .sav backup [3]. The HBIN is the layer the cells live in.

A cell is a length-prefixed chunk of bytes whose first 32-bit field is a signed integer. Positive means free, negative means allocated, and the absolute value is the cell size in bytes (cells are 8-byte aligned). The Suhanov spec documents the convention plainly, alongside the cell types we are about to walk through [10]. The signed-size convention is not just a curiosity; it is the load-bearing invariant that the cell allocator must protect, and it is the convention an attacker exploits when they convince the kernel to walk one allocated cell into the next.

JavaScript How a hive cell's signed-size prefix encodes free-versus-allocated
// Demonstrates the regf signed-size cell convention from Suhanov's spec.
// A cell whose first 32-bit field is positive is FREE.
// A cell whose first 32-bit field is negative is ALLOCATED; |size| is bytes.

function readCellHeader(buf, offset) {
const raw = new DataView(buf).getInt32(offset, true); // little-endian
const allocated = raw < 0;
const sizeBytes = Math.abs(raw);
return { allocated, sizeBytes, raw };
}

// Build a 16-byte buffer: cell #1 allocated, 16 bytes, then a sentinel.
const buf = new ArrayBuffer(20);
new DataView(buf).setInt32(0, -16, true); // header: -16 -> allocated, 16 B
new DataView(buf).setInt32(16, 1234, true); // sentinel "next cell" prefix

console.log("Cell 1:", readCellHeader(buf, 0));
console.log("Cell 2 sentinel:", readCellHeader(buf, 16));

// A trivial validator that only checks "is the size positive after abs()"
// will accept a maliciously flipped header that overlaps into the next cell.
const tampered = buf.slice();
new DataView(tampered).setInt32(0, -24, true); // size now spans into cell 2
console.log("Tampered cell 1:", readCellHeader(tampered, 0));

Press Run to execute.

A hive holds a small number of cell types. The five that matter for security analysis are catalogued below. Each describes a different on-disk concept, and each can be malformed in ways the parser must catch.

Cell typeSignatureWhat it storesFailure mode
Key nodenkA registry key: name, parent index, child-list index, value-list index, security index, timestamp [9]Dangling indices; malformed name length; recursive parenting
ValuevkA registry value: name, type tag, length, inline data or data-block index [9]Length-versus-buffer mismatch; type-tag confusion
Security descriptorskA security descriptor for one or more keys; reference-counted [9]Refcount underflow on shared SDs
Index nodelf / lh / li / riA subkey list: leaves with hash hints, intermediate ri lists [10]Out-of-order entries; phantom subkeys
Big-data blockdbA continuation cell for values larger than 16,344 bytes (just under 16 KiB) [9]Length math overflow; truncated continuation

Between the cells and the parser sits a layer most people do not know about: the cell map. Bins are not guaranteed to be contiguously mapped in kernel virtual address space, so the Configuration Manager maintains a page-table-like indirection that translates a 32-bit cell index into a virtual address. PZ #6 documents this in detail in its discussion of _HHIVE and _CMHIVE, with the latter spanning 0x12F8 bytes and the former 0x600 bytes at offset zero [15]. Per PZ #6: _CMHIVE is 0x12F8 bytes and contains an embedded _HHIVE of 0x600 bytes at offset 0. The depth of Jurczyk's reverse-engineering is reflected in these exact offsets, which are not in any Microsoft-published documentation.

Cell map

A page-table-like indirection layer that translates a 32-bit cell index into a kernel virtual address [15]. The cell map exists because the bins making up a hive are not guaranteed to be contiguously mapped. Most cell-boundary exploitation primitives walk through the cell map.

Ctrl + scroll to zoom
The cell map translates a 32-bit cell index into a kernel virtual address through a page-table-style indirection. Bins live as discontiguous mapped pages; the directory and table layers stitch them together.

The cell allocator itself -- HvAllocateCell, HvReallocateCell, HvFreeCell [4] -- is small, deterministic, and unrandomized. There is no allocator metadata integrity check; freed cells are eagerly reused; cell placement is a function of the bins' free lists, which the attacker can influence by shaping the input hive. Combined with the cell map, the result is that the attacker can place a chosen byte pattern at a chosen cell index with reasonable predictability, and -- because the same allocator services both attacker-influenced and kernel-managed cells -- the attacker can place that pattern adjacent to a kernel-managed object whose corruption hands them an elevation primitive [4].

Since Windows 10 RS4, hive pages are not copied into the paged kernel pool; they are backed by memory-mapped sections that can be paged in from the underlying file [6]. The performance and footprint benefits are real. The security side effect is a new bug class: the kernel can read a hive byte at validation time, then read the same byte again at use time, and the underlying page can have been re-fetched in between. This is the double-fetch pattern, and CVE-2024-43452 -- a double-fetch while loading hives from remote network shares -- is the canonical example Jurczyk cites in PZ #5 [6].

Double-fetch

A vulnerability pattern where the kernel reads the same attacker-influenced memory location twice and treats both reads as authoritative. The section-backed registry (Windows 10 RS4) made hive pages pageable, which enables this on hive files served from remote SMB shares: between the kernel's two reads, the attacker swaps the byte under the kernel's feet. CVE-2024-43452 is the canonical example [6].

A small but stubborn misconception about the registry deserves a callout before we move on. The registry is not lock-free. The Configuration Manager uses pushlocks -- a Windows kernel synchronization primitive supporting shared and exclusive modes -- on a per-Key-Control-Block basis, plus a hive-wide pushlock for operations that touch the hive globally [15]. PZ #6's discussion of _CMHIVE and _HHIVE documents the pushlock placements directly. The design is fine-grained pushlock synchronization, not lock-free concurrency, and the difference matters because temporal hive-memory-corruption bugs frequently exploit the gap between unlocking a parent and re-locking it, which exists in pushlock designs and would not exist in a true lock-free one.

Pushlock

A Windows kernel synchronization primitive supporting shared and exclusive modes [15]. The registry uses per-KCB pushlocks and a hive-wide pushlock. The implementation is not lock-free; that is a third-party misconception, and several of Jurczyk's temporal hive-memory-corruption bugs exploit the moment a pushlock is released and re-acquired.

Two other runtime subsystems sit on top of the parser. The Kernel Transaction Manager (KTM) lets registry writes be grouped into atomic, rollbackable transactions; KTM rides on the Common Log File System (CLFS). KTM's CLFS backing is interesting in its own right: CLFS has had its own significant CVE history, and a transactional registry write whose KTM log can be tampered with reaches a separate kernel subsystem with its own attack surface. The transactional layer is one of the "semantic combinators" Jurczyk explicitly lists as outside the syntactic-fuzzer reach.

Incremental write-ahead logging via LOG1 and LOG2 provides crash-recoverable durability for individual writes that have not yet been flushed to the main hive [6]. Both layers add features. Both layers add cell-lifetime states the parser must reason about. Both layers contributed bugs to the audit.

The PZ #1 summary breakdown of the 50-CVE cohort is the clearest single statistic in the entire series.

CategoryCount
Elevation of privilege39 [1]
Information disclosure9 [1]
Memory information disclosure1 [1]
Denial of service1 [1]
Total50

Of those 50, the subset PZ #8 picks out as exploitable via the hive-memory-corruption primitive numbers seventeen: CVE-2022-34707, CVE-2022-34708, CVE-2022-37956, CVE-2022-37988, CVE-2022-38037, CVE-2023-21675, CVE-2023-21748, CVE-2023-23420, CVE-2023-23421, CVE-2023-23422, CVE-2023-23423, CVE-2023-28248, CVE-2023-35382, CVE-2023-38139, CVE-2024-26182, CVE-2024-43641, and CVE-2024-49114 [4]. Seventeen kernel LPEs from one researcher, one subsystem, one bug class, one exploitation primitive.

Microsoft has known about every one of these issues since the day they were reported. Why has the parser not been rewritten?

7. Why Doesn't Microsoft Just Rewrite It?

The first thing anyone asks after seeing the architecture is the obvious question. Why doesn't Microsoft rewrite this thing? The answer is, roughly, "because they cannot."

Backward compatibility is the dominant constraint. A hive file from NT 4.0 in 1996 still mounts on Windows 11 in 2026; that is the published behaviour of REG_STANDARD_FORMAT in RegSaveKeyExA [7]. Three decades of system images, third-party installers, forensic tooling, configuration-management products, and group-policy templates depend on the regf v1.3 format being readable. A new on-disk format with a hardened in-memory representation would not be a parser change; it would be the kind of compatibility break Microsoft has not made since the move from Win9x to NT.

There are databases inside Windows that look like reasonable alternatives at a glance. None of them is a drop-in replacement, for reasons that have less to do with their internals than with what the registry is asked to do.

SystemImplementationUsed forWhy it is not a drop-in
Registryregf, kernel parserAll Windows configuration, COM, security, policy [18]The thing we are auditing
ESEesent.dll, full ACID DBActive Directory, Windows Search, Mail, Exchange [19]Different access model; userland; not designed for boot-path config
LSA Secrets / SECURITY hiveregf substrate, restricted accessCached credentials, Kerberos keys [19]Same parser, same bug class -- moving the lock does not move the bug
Object Manager NamespaceKernel object directoryNamed kernel objects (events, mutexes, sections)Different threat model; not a config store
MSIX / AppX statePer-package JSON/XML in app containerUWP/Store-app configurationNew apps only; cannot host legacy registry consumers

ESE -- the Extensible Storage Engine -- is the closest existing internal candidate. It is a full ACID embedded database, used by Active Directory and Windows Search, and it is much better-engineered as a storage layer than regf is. It is also userland, designed for very different consumers, and not on the kernel boot path. Reusing it would require porting every kernel-mode registry caller across the kernel-user boundary, which has performance implications that nobody has signed off on publicly.

ESE database

Microsoft's Extensible Storage Engine, an embedded ACID database implemented in esent.dll. Active Directory, Windows Search, Exchange, and Windows Mail all use it as their internal data store [19]. It is a much more modern design than the registry's regf, but it is userland, not boot-path, and its access model is different enough that it is not a drop-in replacement for the kernel-mode configuration store.

The LSA Secrets and SECURITY hive are even more instructive. They are regf-format hives with stricter access controls. They inherit the entire hive-memory-corruption bug class verbatim; restricting who can talk to the parser does not change what the parser does with the bytes it receives.

The structural argument is the one to remember. The registry's on-disk format and its in-memory format are the same format, and its recovery semantics depend on deterministic cell placement; the attack surface and the recovery semantics are therefore literally the same code [@pz5-registry-adventure-5; @pz8-registry-adventure-8]. You cannot harden one without weakening the other unless you give up the hybrid-format premise entirely -- in which case, you are not hardening the parser; you are rewriting it. And rewriting it is what backward compatibility forbids.

If a wholesale redesign is off the table, can the existing parser be hardened in place?

8. The Theoretical Limits of In-Place Hardening

If Microsoft cannot rewrite the parser, can they at least harden it? Four levers are theoretically available. Each one trades against a different property the existing design depends on.

LeverWhat it would achieveBackward-compat costEffectiveness against hive-memory-corruption
Allocator randomizationBreak the placement predictability the exploitation primitive relies onBreaks log-replay recovery semantics that depend on deterministic cell placement [4]High in principle; incompatible in practice
Cell-metadata integrity checksCatch naive corruption at allocator boundariesModest format change for in-memory layout; on-disk format unaffectedLow; catches accidental corruption, not crafted-input semantic violations
Structured deserialization at load timeValidate the entire hive into a separate in-memory structureAbandons the hybrid-format premise; effectively rewrites the parserHigh but indistinguishable from rewriting
Move the parser to user modeReduce blast radius of a parser bug to one processPerformance and correctness implications for boot-path configMitigation only; the bug class survives in userland

Allocator randomization is the obvious idea. ASLR-like randomization of cell placement would defeat the "place attacker-controlled bytes at predictable index" half of the primitive, but it would also break recovery semantics: log replay assumes that after a crash, the cells in the recovered hive end up at the same indices the log expected, because the on-disk-equals-in-memory format encodes the cell index in the hive itself. PZ #8's framing of the allocator's lack of randomness as a design property rather than an oversight is precisely about this trade-off [4].

Cell-metadata integrity checks are cheap to add and have an obvious limit. The cell allocator currently has no metadata integrity at all; adding a checksum or a canary would catch a corrupted size header, a stale free-list pointer, or a write that accidentally overran a cell boundary. It would not catch an attacker who shapes a legal hive that exercises the parser's combinatorial logic. The semantic bugs Jurczyk hunted do not write garbage cells; they trick the parser into reusing valid cells for purposes the parser does not realize it is being asked to.

Structured deserialization at hive-load time is the option computer-science textbooks recommend. Validate the entire input file against a formal grammar, deserialize into a separate in-memory representation that is unrelated to the on-disk byte layout, and let the kernel operate on that. This is what the LangSec discipline calls for, and what structure-aware fuzzing surveys treat as the right shape for parser hardening [20]. It is also identical to "rewrite the parser." The hybrid-format premise that has been load-bearing since 1993 has to die for this option to exist.

LangSec

Language-theoretic security: a discipline that treats parsers as recognizers for a formal grammar, rejecting inputs outside the grammar instead of recovering from malformed input. The registry parser does the opposite by design: it accepts inputs that the recognizer would call "marginal" (a slightly-malformed log, an off-by-one bin) because recovery from a torn write requires acceptance, not rejection.

Moving the parser to user mode -- running the parser inside an isolated process and exposing only sanitized handles to kernel callers -- is what the academic literature recommends for other kernel parsers. There is no public Microsoft work on doing this for the registry specifically, and the performance cost of a kernel/user boundary on the boot-path configuration store is, charitably, "unstudied." The bug class would still exist; the blast radius would shrink.

The honest answer is the one Jurczyk gives in PZ #7 and PZ #8: the parser can be incrementally hardened, and is being, in response to each individual CVE [@pz7-registry-adventure-7; @pz8-registry-adventure-8]. The deeper design choices that make the parser exploitable are the same choices that make it work at all. We have a thirty-year-old parser that cannot be redesigned, cannot easily be replaced, and can only be hardened in ways that trade safety for compatibility. So what does that tell us about the rest of the Windows kernel?

9. Open Problems and What the Audit Implies

Jurczyk read one Windows kernel subsystem for twenty months and produced fifty CVEs. Windows has dozens of kernel subsystems. None of them has been read this way.

That sentence is the article. The rest of this section is bookkeeping.

First, the open business inside the audit itself. Microsoft chose not to fix some of Jurczyk's low-severity reports; PZ tracker issue #2508 is the canonical example of a WontFix close, and the broader "low severity in isolation" category is not "not exploitable in combination" -- modern kernel exploitation is bug-chaining, and a benign-looking primitive plus a benign-looking infoleak often compose into something less benign [17]. PZ #1 also explicitly flags higher-level wrapper logic (path translation in CmpDoOpen, predefined-key abuses, virtualization layers) as parts of the surface that the 20-month audit did not exhaust [1]. There are more registry bugs to find.

Second, the cross-subsystem implication. Microsoft's Windows Insider Preview bounty program pays "from $500 to $100,000 USD" for qualifying critical kernel bugs [21]. The 50-CVE cohort, valued at the upper bound of the Insider Preview range, is somewhere in the neighbourhood of $5M in latent bounty value, all produced by one person reading code.

What does that imply for the Object Manager Namespace, the I/O Manager, the print stack, the transactional file system, the Common Log File System, or the WinUSB stack? No public audit of any of those subsystems at the depth of Jurczyk's registry work exists. Some of them have had targeted fuzzing campaigns; none has had a 100,000-line code review by a single expert reader. The expected yield is, charitably, unknown.

Ctrl + scroll to zoom
Public audit status of selected Windows kernel subsystems (editorial characterization as of May 2026). The registry is the only subsystem with a sustained, single-researcher, deep code review at the scale of the Jurczyk audit. Most subsystems have had only episodic fuzzing or no public deep audit at all.

Third, Microsoft's own internal posture. The MSRC SDL pipeline includes OneFuzz-lineage tooling internally, though the public OneFuzz repository was archived in September 2023 [22]. No public Microsoft statement confirms or denies whether the registry was systematically fuzzed or audited inside Microsoft before Jurczyk's 2022 audit. The absence of such a statement is itself information: if Microsoft had a parallel internal effort that found these bugs first, they would normally publish that.

Fourth, the methodological question that the article cannot answer because nobody has the data. Does manual code audit scale? One researcher, twenty months, one subsystem, fifty CVEs. Two researchers do not produce twice the bugs because of overlap and coordination cost; the typical second-researcher contribution on the same target is sublinear. There is no obvious path to ten Jurczyks reading ten subsystems in parallel and producing five hundred CVEs.

The registry is not interesting because it had bugs. The registry is interesting because someone read it.

Jurczyk did not break new ground by finding a bug. He broke new ground by reading the code -- and the implication for everything else nobody has read is left, as Jurczyk himself might say, as an exercise for the reader.

10. A Practical Guide

Up to here, this article has been about the research. The rest is for practitioners.

For vulnerability researchers

If you want to understand Jurczyk's audit at the level required to repeat it, the Project Zero series is the primary text and the reading order is not the publication order. PZ #4 (hives and the registry layout) and PZ #5 (the regf file format) are the canonical references for the substrate; PZ #6 (kernel-mode objects) is the reverse-engineering of the in-memory structures; PZ #7 (attack surface analysis) is the bug-class taxonomy; PZ #8 (practical exploitation) is the exploitation primitive on Windows 11 with modern mitigations [@pz4-registry-adventure-4; @pz5-registry-adventure-5; @pz6-registry-adventure-6; @pz7-registry-adventure-7; @pz8-registry-adventure-8]. PZ #1 and #2 are the framing and the history; PZ #3 is the bibliography. Read 4 -- 5 -- 6 -- 7 -- 8, in that order, with PZ #1 alongside as a CVE-index lookup.

AudienceWhere to startWhy
Researcher learning the surfacePZ #4 then PZ #5 [@pz4-registry-adventure-4; @pz5-registry-adventure-5]Substrate first; specifics later
Defender / SOC engineerPZ #7 attack-surface taxonomy [17]Detection patterns map to bug classes
Kernel engineer (defensive)PZ #4--6 collectivelyBest non-Microsoft technical reference on the Configuration Manager
Patch managerPZ #8's 17-CVE list + PZ #1 full table [@pz8-registry-adventure-8; @pz1-registry-adventure-1]Prioritize the hive-memory-corruption cohort

For defenders

The detection story for hive-memory-corruption attempts is unusual. Most real-world exploitation chains will load an attacker-controlled hive via RegLoadAppKey (or its close relatives RegLoadKey, RegLoadKeyEx, RegRestoreKey) from an unusual path -- typically a temporary directory under the calling user's profile or an SMB share. The hive file itself can be analyzed offline by mounting it with a forensic parser such as libregf [23] or Suhanov's regf tools [24].

The kernel exposes the operation via the Microsoft-Windows-Kernel-Registry ETW provider, and Sysmon surfaces registry operations under event IDs 12 (key create/delete), 13 (value set), and 14 (key/value rename) [25]. A simple detection heuristic is "Medium-IL process performs an unusual rate of hive-load operations on attacker-shaped paths." Detection logic looks like the following.

JavaScript Sysmon-style detection logic for unusual RegLoadAppKey patterns
// Toy detection: Medium-IL process loads multiple app hives from
// non-standard paths within a short window. Inspired by Sysmon event IDs
// 12 (registry create/delete) and 13 (registry value set).

function suspiciousHiveLoad(event, profileWindowMs) {
const isLoad = event.operation === 'CreateKey' || event.operation === 'LoadAppKey';
if (!isLoad) return false;

const path = event.targetPath || '';
const fromTempOrShare =
  path.match(/AppData\\Local\\Temp/i) ||
  path.match(/^\\\\[^\\]+\\/) ||
  path.match(/Users\\Public/i);

const lowIntegrity = event.integrityLabel === 'Medium' || event.integrityLabel === 'Low';

const recentCount = countRecentEventsFromPid(event.pid, profileWindowMs);
const burst = recentCount > 5;

return lowIntegrity && fromTempOrShare && burst;
}

function alert(event) {
if (suspiciousHiveLoad(event, 60000)) {
  console.log('ALERT: anomalous hive load from PID ' + event.pid +
              ' path=' + event.targetPath);
}
}

Press Run to execute.

For engineers maintaining adjacent code

PZ #4, #5, and #6 collectively are the most accessible non-Microsoft technical reference on the Configuration Manager [@pz4-registry-adventure-4; @pz5-registry-adventure-5; @pz6-registry-adventure-6]. If you are doing security review of a subsystem that interacts with the registry -- ETW, KTM, AppX state, group policy -- those three posts plus PZ #7 give you the model of the in-kernel data structures you are talking to.

For everyone else

The 50 CVE IDs spanning CVE-2022-34707 through CVE-2024-49114 are a checklist for "have these been rolled across our fleet?" [1]. The 17-CVE hive-memory-corruption subset is the priority order [4]. The fixes are in Microsoft's monthly servicing channel; there are no out-of-band patches required, but the cohort is large enough that a fleet that fell behind on Patch Tuesday in 2022 -- 2024 may have several of these still outstanding.

The research is published. The detection is uncomplicated. The next twenty months of Windows kernel research will not be about the registry, which makes the question this article ends on -- what about everything else nobody has read -- the only question left.

11. FAQ

A handful of questions worth correcting before they propagate. These are the misconceptions inherited from secondary summaries of the research, including the prompt for this article.

Frequently asked questions

Wasn't this project called Bochspwn Reloaded?

No. Bochspwn Reloaded is a separate 2017--2018 Project Zero tool, also by Jurczyk, that detects uninitialized kernel memory disclosures via x86 taint tracking [@bochspwn-reloaded-repo; @bochspwn-reloaded-paper]. The 2022--2023 registry research is The Windows Registry Adventure, an eight-part Project Zero blog series [1]. The 2022 coverage-guided Bochs harness Jurczyk briefly used on the registry was a separate, unreleased tool sharing the same general lineage, but it is not the public Bochspwn Reloaded repository. Conflating the two is the most common third-party error about this research.

Was the registry really 'fuzzed precisely once'?

No. At a minimum, Jurczyk and Forshaw fuzzed it in 2016 -- the bug reports filed as Project Zero issues #873, #874, #876, and #993 are the surviving artifacts of that effort [1] -- and Jurczyk built a coverage-guided Bochs harness against it in early 2022 that produced CVE-2022-35768 within days. The 2022--2023 work that produced 50 CVEs was a manual code audit, not a fuzzing campaign. The "fuzzed precisely once" claim mixes up "no published fuzzing campaign at scale" with "no one ever pointed a fuzzer at this," and the latter is just not true.

Is the Windows registry lock-free?

No. The Configuration Manager uses pushlocks (shared and exclusive modes) on a per-Key-Control-Block basis, plus a hive-wide pushlock for global hive operations [15]. "Lock-free" is a misconception that appears in some secondary summaries -- including the prompt for this article. The actual design is fine-grained pushlock-synchronized, and several of Jurczyk's temporal hive-memory-corruption bugs exploit the moment a pushlock is released and re-acquired.

How many CVEs is it actually -- 44, 50, 52, or 53?

All of those are correct at different points in the publication arc. PZ #1 (April 2024) counts 44 from the 90-day cohort plus 6 from the March 2024 low-severity batch = 50 [1]. PZ #5 (December 2024) reports 52 [6]. PZ #7 (May 2025) reports 53 [17]. The growth reflects Microsoft assigning more CVE IDs to Jurczyk's existing bug reports over time, not new discoveries. "50+" is the safe shorthand; "50 in the original cohort, 53 by mid-2025" is the precise version.

When was the OffensiveCon talk?

OffensiveCon 2024, in Berlin. The talk was "Practical Exploitation of Registry Vulnerabilities in the Windows Kernel"; slides and recording are public [@offcon24-jurczyk-speaker; @offcon24-slides; @offcon24-video]. The earlier BlueHat Redmond 2023 talk (titled "Exploring the Windows Registry as a powerful LPE attack surface") was the first public disclosure of the research [@bluehat23-slides; @bluehat23-video]. "OffensiveCon 2025" is wrong; that talk has not happened.

Is the regf format documented officially?

No. Microsoft has never published a regf specification; PZ #5 states this directly: "Throughout the 30 years of the format's existence, Microsoft has never released its official specification" [6]. Unofficially, two community-maintained specs cover almost all of it: Joachim Metz's libregf, updated continuously since July 2009 [9], and Maxim Suhanov's regf project [10]. The Microsoft-blessed reference book is Windows Internals, Part 2, 7th Edition by Allievi, Russinovich, Ionescu, and Solomon [19]. Everything else is forensics-community reverse engineering.

Study guide

Key terms

regf
Microsoft's binary registry file format, introduced in NT 3.1 (1993) and frozen at v1.3 in NT 4.0 (1996). The on-disk format and the in-memory format are the same format.
Hive
A file-and-in-memory tree of registry keys and values, encoded in regf and parsed by the Windows kernel's Configuration Manager.
Cell
The unit of allocation inside a hive: length-prefixed bytes whose signed prefix marks free (positive) or allocated (negative), with size in multiples of eight bytes.
Cell map
A page-table-like indirection layer that translates a 32-bit cell index into a kernel virtual address.
RegLoadAppKey
Win32 API since Vista that lets an unprivileged process load an arbitrary hive file. The kernel parser runs on attacker-supplied bytes.
Hive-based memory corruption
Jurczyk's bug class: spatial (cell-boundary overflows) and temporal (cell-reuse use-after-frees) memory corruption via the deterministic cell allocator.
Pushlock
Windows kernel synchronization primitive (shared/exclusive). The registry uses per-KCB and hive-wide pushlocks; it is not lock-free.
Double-fetch
Pattern where the kernel reads the same attacker-influenced memory twice; section-backed hives since Windows 10 RS4 made this exploitable on hive files from SMB shares.
Bochspwn Reloaded
A 2018 Project Zero tool for detecting kernel infoleaks via Bochs-based taint tracking. NOT the registry-research instrument.
LangSec
Language-theoretic security: parsers as recognizers for a formal grammar. The regf parser is not a LangSec recognizer by design.

Comprehension questions

  1. Why does the Windows kernel run a binary parser on attacker-supplied bytes at Medium IL?

    `RegLoadAppKey`, introduced in Vista (2006), explicitly allows an unprivileged process to load an arbitrary hive file as a private app hive. The kernel-mode regf parser runs on those bytes; only the resulting handle is sandboxed.

  2. Why was bitflipping fuzzing ineffective against regf?

    The base-block validator rejects most random mutations before the parser proper sees them; the interesting bugs are semantic, requiring legal hive images that exercise multi-feature combinations (transactions, virtualization, log replay).

  3. Why is the cell allocator unrandomized?

    Recovery semantics require deterministic cell placement after log replay; cells encode their indices in the on-disk format. Randomization would break crash recovery.

  4. Distinguish spatial from temporal hive-memory-corruption violations.

    Spatial: a write crosses a cell boundary into an adjacent cell. Temporal: a write uses a cell-index reference whose backing storage has been freed and reallocated to attacker-influenced content.

  5. Why is the section-backed hive design in Windows 10 RS4 a double-fetch enabler?

    Hive pages became pageable. The kernel can read a hive byte at validation time and again at use time, and the underlying page can be re-fetched in between -- especially over SMB. CVE-2024-43452 is the canonical example.

The eight Project Zero posts run roughly 120,000 words across April 2024 -- May 2025. Microsoft has serviced 53 CVEs from them so far. The registry's parser remains substantively the same routine it has been since Windows NT 4.0. There is no public roadmap for a redesign. The question that follows -- what is the expected yield of similar audits of every other Windows kernel subsystem that no one has read end-to-end -- is the one a research community could answer in another twenty months, if it chose to.

References

  1. Mateusz Jurczyk (2024). The Windows Registry Adventure #1: Introduction and research results. https://googleprojectzero.blogspot.com/2024/04/the-windows-registry-adventure-1.html
  2. RegLoadAppKeyA function (winreg.h). https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regloadappkeya
  3. Registry Hives -- Win32 apps. https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-hives
  4. Mateusz Jurczyk (2025). The Windows Registry Adventure #8: Practical exploitation of hive memory corruption. https://googleprojectzero.blogspot.com/2025/05/the-windows-registry-adventure-8-exploitation.html
  5. Mateusz Jurczyk (2024). The Windows Registry Adventure #2: A brief history of the feature. https://googleprojectzero.blogspot.com/2024/04/the-windows-registry-adventure-2.html
  6. Mateusz Jurczyk (2024). The Windows Registry Adventure #5: The regf file format. https://googleprojectzero.blogspot.com/2024/12/the-windows-registry-adventure-5-regf.html
  7. RegSaveKeyExA function (winreg.h). https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regsavekeyexa
  8. Mark Russinovich Process Monitor -- Sysinternals. https://learn.microsoft.com/en-us/sysinternals/downloads/procmon
  9. Joachim Metz (2026). Windows NT Registry File (REGF) format specification. https://github.com/libyal/libregf/blob/main/documentation/Windows%20NT%20Registry%20File%20(REGF)%20format.asciidoc
  10. Maxim Suhanov Windows registry file format specification. https://github.com/msuhanov/regf/blob/master/Windows%20registry%20file%20format%20specification.md
  11. Mateusz Jurczyk (2024). The Windows Registry Adventure #4: Hives and the registry layout. https://googleprojectzero.blogspot.com/2024/10/the-windows-registry-adventure-4-hives.html
  12. Project Zero issue tracker. https://project-zero.issues.chromium.org/
  13. Mateusz Jurczyk (2018). googleprojectzero/bochspwn-reloaded. https://github.com/googleprojectzero/bochspwn-reloaded
  14. Mateusz Jurczyk (2018). Detecting Kernel Memory Disclosure with x86 Emulation and Taint Tracking. https://j00ru.vexillium.org/papers/2018/bochspwn_reloaded.pdf
  15. Mateusz Jurczyk (2025). The Windows Registry Adventure #6: Kernel-mode objects. https://googleprojectzero.blogspot.com/2025/04/the-windows-registry-adventure-6-kernel.html
  16. Mateusz Jurczyk (2024). The Windows Registry Adventure #3: Learning resources. https://googleprojectzero.blogspot.com/2024/06/the-windows-registry-adventure-3.html
  17. Andrea Allievi, Mark E. Russinovich, Alex Ionescu, & David A. Solomon (2021). Windows Internals, Part 2, 7th Edition. https://learn.microsoft.com/en-us/sysinternals/resources/windows-internals
  18. Mateusz Jurczyk (2025). The Windows Registry Adventure #7: Attack surface analysis. https://googleprojectzero.blogspot.com/2025/05/the-windows-registry-adventure-7-attack-surface.html
  19. Structure of the Registry -- Win32 apps. https://learn.microsoft.com/en-us/windows/win32/sysinfo/structure-of-the-registry
  20. Valentin J. M. Manès, HyungSeok Han, Choongwoo Han, Sang Kil Cha, Manuel Egele, Edward J. Schwartz, & Maverick Woo (2019). The Art, Science, and Engineering of Fuzzing: A Survey. https://arxiv.org/abs/1812.00140
  21. Microsoft Windows Insider Preview Bounty Program. https://www.microsoft.com/en-us/msrc/bounty-windows-insider-preview
  22. (2023). microsoft/onefuzz (archived). https://github.com/microsoft/onefuzz
  23. Joachim Metz libyal/libregf. https://github.com/libyal/libregf
  24. Maxim Suhanov msuhanov/regf. https://github.com/msuhanov/regf
  25. Mark Russinovich & Thomas Garnier Sysmon -- Sysinternals. https://learn.microsoft.com/en-us/sysinternals/downloads/sysmon
  26. Mateusz Jurczyk (2024). Practical Exploitation of Registry Vulnerabilities in the Windows Kernel (OffensiveCon 2024). https://www.offensivecon.org/speakers/2024/mateusz-jurczyk.html
  27. Mateusz Jurczyk (2024). Practical Exploitation of Registry Vulnerabilities in the Windows Kernel -- OffensiveCon 2024 slides. https://j00ru.vexillium.org/slides/2024/offensivecon.pdf
  28. Mateusz Jurczyk (2024). OffensiveCon 2024 recording. https://www.youtube.com/watch?v=qllMa2UUPvY
  29. Mateusz Jurczyk (2023). Exploring the Windows Registry as a powerful LPE attack surface -- BlueHat Redmond 2023 slides. https://j00ru.vexillium.org/slides/2023/bluehat.pdf
  30. Mateusz Jurczyk (2023). BlueHat Redmond 2023 recording. https://www.youtube.com/watch?v=8mJLe8sZki8
  31. Dmitry Vyukov google/syzkaller. https://github.com/google/syzkaller
  32. Axel Souchet 0vercl0k/wtf -- what the fuzz. https://github.com/0vercl0k/wtf
  33. Ivan Fratric googleprojectzero/winafl. https://github.com/googleprojectzero/winafl
  34. google/security-research -- kernel CodeQL analysis. https://github.com/google/security-research/blob/master/analysis/kernel/README.md
  35. Sergej Schumilo, Cornelius Aschermann, Robert Gawlik, Sebastian Schinzel, & Thorsten Holz (2017). kAFL: Hardware-Assisted Feedback Fuzzing for OS Kernels. https://www.usenix.org/conference/usenixsecurity17/technical-sessions/presentation/schumilo
  36. Sergej Schumilo, Cornelius Aschermann, Ali Abbasi, Simon Wörner, & Thorsten Holz (2021). Nyx: Greybox Hypervisor Fuzzing using Fast Snapshots and Affine Types. https://www.usenix.org/conference/usenixsecurity21/presentation/schumilo
  37. Andrea Fioraldi, Dominik Maier, Heiko Eißfeldt, & Marc Heuse (2020). AFL++: Combining Incremental Steps of Fuzzing Research. https://www.usenix.org/conference/woot20/presentation/fioraldi
  38. S2E -- A platform for in-vivo analysis of software systems. https://s2e.systems/