ReFS Forensics Reference

$OBJ_LINK

$OBJ_LINK is the object → name backpointer — it stores a filename and its parent OID directly in the object’s own record, so a path can be reconstructed from the Object Table alone, without walking directory trees. It is a multi-instance embedded sub-record, type 0x39 on v3.7+ and type 0x38 on v3.4. (It is the same on-disk row historically called $DIR_LINK — the legacy v3.4-era debug/management-API name.)

There is one row per NAME, not one per object. A hard link adds a row. Measured across the corpus, the number of distinct (parent OID, name) pairs in an object’s backing equals the number of directory entries pointing at that object on 40,966 of 40,966 backings — ReFS 3.7, 3.9, 3.10 and 3.14, for objects carrying anywhere from 1 to 19 names, with no exceptions. That makes these rows the object’s own enumeration of every path that reaches it, and the most direct way to count and list a file’s hard links.

Two things to handle when counting:

  • Deduplicate. Some backings carry the same (parent, name) row twice, byte-for-byte. Count distinct pairs, not rows. (Observed on moved files; the operation that produces the second copy is not yet pinned.)
  • Scope “always present”. These rows live on objects that have their own record: directories (in their type-0x10 row) and files whose record was split out into a type-0x40 backing. A file whose name row still embeds its record (key_flags 0x01) has none — 0 of 219 on the audited volume. On ReFS 3.4 no directory carries one either (0 of 309 measured), so the v3.4 form is not a drop-in equivalent.

Value layout

The format differs between v3.7+ (compact: parent OID + name) and v3.4 (a full metadata block with timestamps).

v3.7+ — key (the value overlaps the key from byte 8):

OffsetSizeFieldDescription
0x008Value length
0x084Marker0x80000002 (multi-instance)
0x0C2Type code0x0039
0x0E2Sub-type0x000D
0x104Parent OIDthe parent directory OID
0x14varFilenameUTF-16LE, in the key/value overlap

v3.7+ — value: 0x00 marker 0x80000002, 0x04 type 0x0039, 0x06 sub-type 0x000D, 0x08 parent OID, 0x0C reserved (12 bytes, 0), 0x18 filename (UTF-16LE, null-terminated).

v3.4 — value (the common 12-byte sub-record header, then a full metadata block):

OffsetSizeFieldDescription
0x004Padding0
0x044Data-area sizevalue length − 12
0x084Content offset0x0C
0x0C8Reserved0
0x144Parent OID
0x184Reserved0
0x1C8Creation timeFILETIME
0x248Modification timeFILETIME
0x2C8Change timeFILETIME
0x348Access timeFILETIME
0x3C4File attributesWin32 flags
0x4C4Flags word0x10000006
0x542Name lengthfilename length (UTF-16 chars)
0x5EvarFilenameUTF-16LE, null-terminated

The v3.4 key is 0x00 value length, 0x08 type code 0x00000038 (no instance marker).

v3.4 stores independent, frozen timestamps. The v3.4 $OBJ_LINK value carries its own four timestamps: the creation time matches the directory entry exactly, but the modify/change/access times are frozen at object creation while the directory entry tracks later updates — so the two diverge by the time between object creation and the next metadata update. (v3.7+ stores only the parent OID and name, not timestamps.)

Forensic significance

$OBJ_LINK is critical for deleted-file and damaged-tree recovery. If a directory B+-tree page is corrupted but the Object Table survives, each surviving type-0x10 row’s $OBJ_LINK still yields the file’s exact name, its parent OID, and — by chaining parent OIDs — the full path. On v3.4 it additionally yields the file’s creation timestamp.

Driver and versioning

The on-disk form is selected by VCB+0x2ACC (the same flag as RefsHardlinksSupported): 0x38 = the legacy v3.4 backpointer, 0x39 = the current form. The v3.7+ row is built by RefsInitializeObjLinkRow; the v3.4 row by RefsBackpointerValueFromFileNameCreateAttribute(0x38). Both are driven by RefsAttributeManager::CreateLinkAttribute / DeleteLinkAttribute (the “$DIR_LINK” management API). Upgraded v3.4→v3.14 volumes keep the old 0x38 rows.

Cross-references

Evidence

Type 0x38 / 0x39 and the layouts are confirmed in the decompiled driver (RefsInitializeObjLinkRow, RefsBackpointerValueFromFileName) and raw-disk decoded across the corpus; $OBJ_LINK is present on nearly every user object. The remaining field-level statements on this page are registered as — each with its own evidence tier and witness in the claim register.