ReFS Forensics Reference

Block Refcount Table

The Block Refcount Table (root #6, table ID 0x05, schema 0xe0b0) tracks shared data clusters used by snapshots, deduplication, and clones. The schema and root #6 have existed since v3.4 as an empty B+-tree; the table is only populated on v3.14 volumes with snapshot, dedup, or hard-link sharing activity.

Key — 16 bytes

OffsetSizeFieldDescription
0x008Start LCN (u64)First cluster of the tracked range
0x088Cluster count (u64)Range length in clusters = 0x400 = 1,024 (one u16 array entry per cluster)

Value — 2,080 bytes (0x820, normal)

OffsetSizeFieldDescription
0x008Start LCN (u64)Redundant copy of key
0x088Cluster count (u64)Redundant copy of key (0x400 = 1,024)
0x108Modification stamp (u64)Low byte varies (e.g. 0xE4 / 0xF0) — NOT always 0x01
0x184TotalRefCount (u32)= Σ(array entry & 0x3FFF); upper 16 bits always 0
0x1C2,048Per-cluster refcount array (u16[1024])Spans 0x1C..0x81B; one entry per cluster (4 KiB); bits 0–13 = refcount, bits 14–15 = flags
0x81C4Unknown (4 bytes)Not padding: zero on most rows, structured content on the rest. Non-zero on 159 of 1,441 rows across 8 volumes, all of them format 3.14, in 15 distinct values whose high half is always 0xFFFF. Meaning undetermined

Two value forms. The table above is the long form, 2,080 bytes when BlockCount is 0x400. A 32-byte compact form also exists: the same 28-byte header and the same 4-byte trailer, with the u16[BlockCount] array omitted (28 + 4 = 32). Measured on winsider: 108 rows, 106 long and 2 compact, both compact rows carrying a well-formed header (the key’s StartLCN/BlockCount mirrored into the value at +0x00/+0x08), so they are a second encoding rather than damage. What the compact form means — whether it encodes a uniform refcount across the range — is not established: two rows on one volume cannot separate that reading from others.

The normal value is 2,080 bytes (0x820): a 28-byte header (0x00..0x1B, including TotalRefCount@0x18) + the u16[1024] array @ 0x1C..0x81B (one entry per cluster) + a 4-byte trailing field @ 0x81C. The header’s TotalRefCount@0x18 equals the sum of the refcount fields across the whole array (Σ of entry & 0x3FFF), with the upper 16 bits always 0. Do not confuse this with the allocator bitmap row, which is a different structure with a different value length.

A compact/stale variant of 32 bytes also exists.

Per-cluster refcount entry bit fields (u16; one entry per cluster / 4 KiB)

BitsMaskFieldNotes
13:00x3FFFReference countHow many references hold this cluster
140x4000Dedup metadata flagMarks dedup management clusters (only on entries with rc=0)
150x8000Shared / dedup-managedMarks clusters managed by the Data Deduplication engine

Interpreting an entry

  • Hard link sharing: rc ≥ 2, bit 15 clear (normal multi-reference).
  • CoW orphans: rc ≥ 2, a previous checkpoint still references the clusters.
  • Dedup store: bit 15 set, rc = 0 (data present but no live file reference).
  • Example: entry value 0x81F9 = rc=505, shared=1 — a single 4 KiB cluster referenced by 505 files.

Bit 15 (Shared) and bit 14 (Flag14) appear only on dedup-enabled volumes, and bit 14 is never combined with bit 15 — the bit positions and this dedup-only appearance are what the corpus establishes; the field names are interpreted from that correlation. Common entry shapes are 0x4000 (dedup metadata, rc=0), 0x8000 (dedup-shared, rc=0), and 0x8000 | rc (dedup-shared with a live reference count).

Population by version

VersionStateNotes
v3.4–v3.10Not populatedRoot #6 exists but the table holds no rows
v3.14 (no dedup)PopulatedTracks CoW references and snapshot sharing
v3.14 (dedup)Populated with flag bitsDedup engine uses bits 14 and 15

Implementation notes

  • The Win11 driver uses a cache-based model (LookupCacheEntry / PersistCacheEntry / PopulateCacheEntry), replacing the Win10 driver’s direct B+-tree manipulation (InsertEntry / DeleteEntry / UpdateEntry). The CmsBlockRefcount table’s refcount is adjusted through IncrementRefcount (the Win10 v3.4 driver also carries a paired DecrementRefcount; v3.14/Insider retain only IncrementRefcount).
  • The root page meta_type is always 0x0 (not 0xe0b0).
  • Root #6 has no failover pair — it is the sole copy.

Cross-references

Evidence

Identity (root #6 / table ID 0x05 / schema 0xe0b0 / virtual addressing / no failover pair) is confirmed in the driver: the CmsBlockRefcount class implements the table, and root #6 carries table ID 0x05 on valid MSB+ pages. The key/value layout, the per-cluster bitfields, and the TotalRefCount@0x18 == Σ(entry & 0x3FFF) invariant are raw-disk decoded across the populated v3.14 corpus and corroborated by the decompiled access functions named above.

Also registered for statements on this page:.