Windows Heap Internals for Exploiters

Last updated: 2026-04-10
Related: Pool Internals, Heap Grooming, Use After Free, Mitigations
Tags: user-mode, nt-heap, segment-heap

Summary

Windows user-mode heap exploitation has evolved through two major allocator generations: the NT Heap (pre-Win10 RS5 for most processes) and the Segment Heap (Win10 RS5+). Understanding both is critical — legacy NT Heap still appears in many targets (older processes, specific allocator contexts), and the Segment Heap is now the primary attack surface in modern Windows user-mode exploitation.


NT Heap (Legacy)

Architecture

Each process has one or more heap instances (_HEAP). The default process heap is at PEB.ProcessHeap.

typedef struct _HEAP {
    // ...
    HEAP_SEGMENT Segment;           // first segment embedded
    ULONG Flags;
    ULONG ForceFlags;
    // Free lists, virtual allocation lists...
    LIST_ENTRY FreeLists[128];      // 8-byte granularity, up to 1024 bytes
    HEAP_LOOKASIDE* Lookaside[128]; // per-size lookaside (pre-Vista: FS:[0x18])
    // ...
} HEAP;

Chunk Header (NT Heap)

typedef struct _HEAP_ENTRY {
    USHORT Size;             // chunk size in 8-byte units (encoded)
    UCHAR  Flags;            // HEAP_ENTRY_BUSY | HEAP_ENTRY_LAST_ENTRY, etc.
    UCHAR  SmallTagIndex;    // used for overflow detection
    USHORT PreviousSize;     // previous chunk size (encoded)
    UCHAR  SegmentOffset;
    UCHAR  UnusedBytes;
} HEAP_ENTRY; // 8 bytes

Header encoding (Vista+): Size, PreviousSize, SmallTagIndex are XORed with HEAP.Encoding (random per-heap). Prevents straightforward header forgery — must leak the encoding key.

Low Fragmentation Heap (LFH)

Activated for size buckets that have ≥18 allocations. Uses _HEAP_SUBSEGMENT structures:

  • Fixed-size blocks within subsegments
  • No chunk headers between blocks — blocks tracked by bitmap
  • Overflow into adjacent LFH block hits data directly (same as kernel Segment Heap LFH)
  • Subsegment list can be corrupted to achieve larger-scope impact

Safe Unlinking (Vista+)

Free list doubly-linked list unlink validates Flink->Blink == current. Broken → heap corruption exception.


Segment Heap (Win10 RS5+ Default)

Windows 10 RS5 (October 2018) switched most processes to the Segment Heap. Controlled by PEB.NtGlobalFlag bit or image policy. The new allocator is also the kernel pool allocator since 20H1.

Components

_SEGMENT_HEAP
├── SegmentContext[2]   ← VS (Variable Size) segments
├── LargeAllocMetadata ← RB tree for allocations > 128KB
├── LfhContext         ← Low-Fragmentation Heap
└── StackTraceContext  ← debug-only

Backend (VS Segments)

Handles allocations not serviced by LFH (generally > 128KB threshold or first few allocations per size).
Uses _HEAP_VS_CHUNK_HEADER with encoding (XOR with random key per-heap).

LFH (Segment Heap)

Handles allocations ≤ some threshold (typically 128KB with bucketing).

  • 128 size classes (buckets)
  • Per-bucket _HEAP_LFH_SUBSEGMENT containing fixed-size blocks
  • Bitmap-based allocation tracking (no inline headers)
  • Exploit implication: overflow within same LFH subsegment hits adjacent block’s data directly

Large Allocation

128KB → _HEAP_LARGE_ALLOC_DATA metadata stored in RB tree (not adjacent to data)
Overflow into large allocation → hits data, not heap metadata

Guard Pages

Random guard pages interspersed in heap — overflow detection, not fully deterministic


Heap Exploitation Techniques

1. Free List Corruption (NT Heap, encoded headers)

  • Goal: corrupt a free chunk header to redirect next allocation to attacker-controlled address
  • Requirement: leak heap encoding key (look for pointer leaks in heap objects, or partial overwrite)
  • Steps: overflow → overwrite encoded Size/PreviousSize → HeapAlloc returns attacker-controlled pointer

2. LFH Bucket Overflow (Both Allocators)

  • Goal: overflow into adjacent same-bucket block
  • Requirement: precise allocation sizing to land in same LFH bucket
  • Steps: spray bucket → create layout AB → overflow A → corrupt B’s data (often vtable pointer)
  • LFH bucket selection: sizes 8, 16, 24, … 1024 bytes in 8-byte increments; then 1040, 1056… up to 16KB

3. Heap Grooming

See Heap Grooming for detailed strategies.

4. Type Confusion via Free

  • Free an object but keep a pointer (UAF)
  • Re-allocate same slot with different object type
  • Use pointer assuming original type → type confusion → vtable dispatch to controlled address

5. Use-After-Free

See Use After Free.


Heap Metadata Security Features

FeatureAllocatorEffect
Header encodingNT Heap + Segment HeapHeader forgery requires encoding key
Guard pagesSegment HeapRandom overflow detection
Safe unlinkingNT HeapFree list pointer validation
LFH bitmapBothNo inline chunk headers in LFH
Separate large alloc metadataSegment HeapLarge alloc overflow hits data only
Heap base ASLRBothPer-heap random base address

Useful Heap Internals for Exploitation

Getting Heap Base

PVOID heapBase = (PVOID)__readgsqword(0x60);  // PEB
heapBase = *(PVOID*)((UCHAR*)heapBase + 0x30); // PEB.ProcessHeap

Forcing Specific Size Class

Control your allocation size to land in desired LFH bucket:

  • Bucket 1: 1-8 bytes
  • Bucket N: (N-1)*8 + 1 to N*8 bytes
  • For exploiting specific target, size spray objects to same bucket as vulnerable object

Heap Spray Considerations

  • Modern defenses: ASLR of heap base, guard pages, nonce encoding
  • Spray is still viable for controlling relative layout within a heap segment
  • Prioritize: land specific objects adjacent to vulnerable object (feng shui over raw spray)

Exploit Relevance

  • NT Heap still present in many legacy codepaths and older Windows targets
  • Segment Heap LFH exploitation (no inline headers) is now the dominant approach
  • Type confusion via re-use (UAF) remains the most common user-mode exploitation pattern
  • Heap grooming quality directly determines exploit reliability — invest time here

References

  • “Heap Exploitation on Windows” — Chris Valasek
  • “Understanding the LFH” — Ben Hawkes (Google Project Zero)
  • “Segment Heap Internals” — Mark Yason, Black Hat 2016
  • “Windows 10 Segment Heap” — Corentin Bayet, Synacktiv
  • Phrack #68 “MS Windows NT Kernel-mode User and GDI Object Exploitation”