1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
//! Shell Link (`.LNK`) binary file format constants — `[MS-SHLLINK]`.
//!
//! A shell link (`.lnk`) is a structured binary file Windows uses to reference
//! another data object (file, folder, network share, search). Forensically it
//! is a rich artifact: it records the target path, volume serial, MAC
//! timestamps, machine NetBIOS name, and a distributed-link-tracking droid
//! GUID — evidence of files that may no longer exist.
//!
//! A `.LNK` carries **two distinct timestamp sets that must not be conflated**:
//!
//! 1. **The host filesystem's `$STANDARD_INFORMATION` (`$SI`) MACB times of the
//! `.lnk` file itself** — when the shortcut was created/modified/accessed on
//! *this* machine. For shell-managed shortcuts (the `Recent` /
//! `AutomaticDestinations` folders) the shell rewrites the `.lnk` when the
//! target is accessed, so these track target-access on this host; a static
//! desktop `.lnk` is not rewritten on every open.
//! 2. **The embedded target timestamps** — `CreationTime` (offset `0x1C`),
//! `AccessTime` (`0x24`) and `WriteTime` (`0x2C`), each an 8-byte FILETIME
//! (`[MS-DTYP]` §2.3.3) recording the link *target's* MAC times captured at
//! the moment the shortcut was last written. Because they are copied into the
//! `.lnk`, they survive deletion of the target: a `.lnk` in a Recent /
//! AutoDest / jump-list can preserve a deleted file's creation/access/write
//! times when the file itself is gone. A zero value denotes an unset field
//! (per `[MS-SHLLINK]` §2.1 for CreationTime, AccessTime *and* WriteTime),
//! not the 1601 epoch — treat `0` as *absent*, never render it as a real
//! timestamp. These are the target's metadata as seen at link-write time, so
//! they are *consistent with* (not proof of) the target's true filesystem
//! times and can be stale or forged; a divergence from the host `$SI` set
//! supports no stronger inference on its own.
//!
//! This module is knowledge only — the fixed `HeaderSize`, the `LinkCLSID`, the
//! `LinkFlags` and `FileAttributesFlags` bit definitions, and the `ExtraData`
//! block signatures. The parser (header parse, `LinkTargetIDList` walk,
//! `LinkInfo`/string-data decode, ExtraData dispatch) lives in the consuming
//! reader (`lnk-core`), per forensicnomicon's knowledge-only charter.
//!
//! # Forensic interpretation — an automatic LNK is not proof the target was opened
//!
//! Prior to Windows 10, a LNK in the `Recent` folder generally meant the user
//! opened or accessed the target (Jones 2020). On Windows 10/11 the shell also
//! creates automatic LNKs for actions that never open the target's contents — a
//! `Save As` to a new location, a print-to-file / "create new file", and similar
//! save/create operations — so a file that was *created or saved* but never
//! opened still yields a LNK (with application-specific exceptions, e.g. 7-Zip).
//! Consequently the presence of an automatic LNK is *consistent with* the target
//! having existed and been created or saved on the system; it does not, by
//! itself, establish that the user opened or viewed the target's contents.
//! Corroborate against the LNK-vs-target timestamps and independent execution/
//! access artifacts. (Empirically established on a single build — Windows 10 Pro
//! 1903, Jones 2020 — so behaviour may vary across builds.)
//!
//! # Authoritative sources
//!
//! - `[MS-SHLLINK]` — *Shell Link (.LNK) Binary File Format*, the primary spec.
//! §2.1 ShellLinkHeader (HeaderSize / LinkCLSID), §2.1.1 LinkFlags,
//! §2.1.2 FileAttributesFlags, §2.5 ExtraData:
//! <https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/16cb4ca1-9339-4d0c-a68d-bf1d6cc0f943>
//! - libyal `liblnk`, *Windows Shortcut File (LNK) format* (J. Metz) — the
//! reverse-engineered reference; documents every ExtraData block signature
//! and size:
//! <https://github.com/libyal/liblnk/blob/main/documentation/Windows%20Shortcut%20File%20(LNK)%20format.asciidoc>
//! - Jones, N. (2020), *LNK Files and the Windows 10 shell* — DFIR Review
//! (open peer review), the behavioural source for the Win10/11 create-on-save
//! triggers (single study, Windows 10 Pro build 1903):
//! <https://dfir.pubpub.org/pub/lhaf5ohxg> (DOI 10.21428/b0ac9c28.92ca3973)
/// `ShellLinkHeader.HeaderSize` — MUST be `0x0000004C` (`[MS-SHLLINK]` §2.1).
pub const HEADER_SIZE: u32 = 0x0000_004C;
/// `ShellLinkHeader.LinkCLSID` — MUST be this class identifier
/// (`[MS-SHLLINK]` §2.1).
pub const LINK_CLSID: &str = "00021401-0000-0000-C000-000000000046";
/// Byte width of each `ShellLinkHeader` FILETIME field (`[MS-DTYP]` §2.3.3).
pub const FILETIME_FIELD_SIZE: usize = 8;
/// Offset of `ShellLinkHeader.CreationTime` — an 8-byte FILETIME
/// (`[MS-DTYP]` §2.3.3) recording the link *target's* creation time
/// (`[MS-SHLLINK]` §2.1). Zero means no creation time was set on the target.
/// Derived: HeaderSize(4)@0x00 + LinkCLSID(16)@0x04 + LinkFlags(4)@0x14 + FileAttributes(4)@0x18.
pub const OFFSET_CREATION_TIME: usize = 0x1C;
/// Offset of `ShellLinkHeader.AccessTime` — an 8-byte FILETIME
/// (`[MS-DTYP]` §2.3.3) recording the target's last-access time
/// (`[MS-SHLLINK]` §2.1). Zero means no access time was set on the target.
pub const OFFSET_ACCESS_TIME: usize = 0x24;
/// Offset of `ShellLinkHeader.WriteTime` — an 8-byte FILETIME
/// (`[MS-DTYP]` §2.3.3) recording the target's last-write time
/// (`[MS-SHLLINK]` §2.1). Zero means no write time was set on the target.
pub const OFFSET_WRITE_TIME: usize = 0x2C;
// ── LinkFlags (`[MS-SHLLINK]` §2.1.1) ────────────────────────────────────────
// Bit A is the least-significant bit (1 << 0); bits are listed MSB-first in the
// spec table but assigned A→least-significant.
/// A — a `LinkTargetIDList` follows the header.
pub const LINK_FLAG_HAS_LINK_TARGET_ID_LIST: u32 = 1 << 0;
/// B — a `LinkInfo` structure is present.
pub const LINK_FLAG_HAS_LINK_INFO: u32 = 1 << 1;
/// C — the `NAME_STRING` (description) is present.
pub const LINK_FLAG_HAS_NAME: u32 = 1 << 2;
/// D — the `RELATIVE_PATH` string is present.
pub const LINK_FLAG_HAS_RELATIVE_PATH: u32 = 1 << 3;
/// E — the `WORKING_DIR` string is present.
pub const LINK_FLAG_HAS_WORKING_DIR: u32 = 1 << 4;
/// F — the `COMMAND_LINE_ARGUMENTS` string is present.
pub const LINK_FLAG_HAS_ARGUMENTS: u32 = 1 << 5;
/// G — the `ICON_LOCATION` string is present.
pub const LINK_FLAG_HAS_ICON_LOCATION: u32 = 1 << 6;
/// H — string data are UTF-16 (`IsUnicode`); otherwise system code page.
pub const LINK_FLAG_IS_UNICODE: u32 = 1 << 7;
/// I — `LinkInfo` is ignored (`ForceNoLinkInfo`).
pub const LINK_FLAG_FORCE_NO_LINK_INFO: u32 = 1 << 8;
/// J — an `EnvironmentVariableDataBlock` is present (`HasExpString`).
pub const LINK_FLAG_HAS_EXP_STRING: u32 = 1 << 9;
/// K — the target runs in a separate VM (`RunInSeparateProcess`).
pub const LINK_FLAG_RUN_IN_SEPARATE_PROCESS: u32 = 1 << 10;
// L (1 << 11) is Unused1 — reserved, no constant.
/// M — a `DarwinDataBlock` is present (`HasDarwinID`).
pub const LINK_FLAG_HAS_DARWIN_ID: u32 = 1 << 12;
/// N — the target runs as a different user (`RunAsUser`).
pub const LINK_FLAG_RUN_AS_USER: u32 = 1 << 13;
/// O — an `IconEnvironmentDataBlock` is present (`HasExpIcon`).
pub const LINK_FLAG_HAS_EXP_ICON: u32 = 1 << 14;
/// P — the file system location is represented in the shell namespace
/// (`NoPidlAlias`).
pub const LINK_FLAG_NO_PIDL_ALIAS: u32 = 1 << 15;
// Q (1 << 16) is Unused2 — reserved, no constant.
/// R — a `ShimDataBlock` is present (`RunWithShimLayer`).
pub const LINK_FLAG_RUN_WITH_SHIM_LAYER: u32 = 1 << 17;
/// S — the `TrackerDataBlock` is omitted (`ForceNoLinkTrack`).
pub const LINK_FLAG_FORCE_NO_LINK_TRACK: u32 = 1 << 18;
/// T — shell-link target metadata collection is enabled
/// (`EnableTargetMetadata`).
pub const LINK_FLAG_ENABLE_TARGET_METADATA: u32 = 1 << 19;
/// U — the `EnvironmentVariableDataBlock` path is not stored
/// (`DisableLinkPathTracking`).
pub const LINK_FLAG_DISABLE_LINK_PATH_TRACKING: u32 = 1 << 20;
/// V — `SpecialFolderDataBlock`/`KnownFolderDataBlock` tracking is disabled
/// (`DisableKnownFolderTracking`).
pub const LINK_FLAG_DISABLE_KNOWN_FOLDER_TRACKING: u32 = 1 << 21;
/// W — the known-folder alias is not used (`DisableKnownFolderAlias`).
pub const LINK_FLAG_DISABLE_KNOWN_FOLDER_ALIAS: u32 = 1 << 22;
/// X — a link to another link is permitted (`AllowLinkToLink`).
pub const LINK_FLAG_ALLOW_LINK_TO_LINK: u32 = 1 << 23;
/// Y — drop the alias on save (`UnaliasOnSave`).
pub const LINK_FLAG_UNALIAS_ON_SAVE: u32 = 1 << 24;
/// Z — prefer the environment-variable path (`PreferEnvironmentPath`).
pub const LINK_FLAG_PREFER_ENVIRONMENT_PATH: u32 = 1 << 25;
/// AA — keep the local `IDList` for a UNC target
/// (`KeepLocalIDListForUNCTarget`).
pub const LINK_FLAG_KEEP_LOCAL_ID_LIST_FOR_UNC_TARGET: u32 = 1 << 26;
// ── FileAttributesFlags (`[MS-SHLLINK]` §2.1.2) ──────────────────────────────
/// A — `FILE_ATTRIBUTE_READONLY`.
pub const FILE_ATTRIBUTE_READONLY: u32 = 1 << 0;
/// B — `FILE_ATTRIBUTE_HIDDEN`.
pub const FILE_ATTRIBUTE_HIDDEN: u32 = 1 << 1;
/// C — `FILE_ATTRIBUTE_SYSTEM`.
pub const FILE_ATTRIBUTE_SYSTEM: u32 = 1 << 2;
// D (1 << 3) is Reserved1 (MUST be zero) — no constant.
/// E — `FILE_ATTRIBUTE_DIRECTORY`.
pub const FILE_ATTRIBUTE_DIRECTORY: u32 = 1 << 4;
/// F — `FILE_ATTRIBUTE_ARCHIVE`.
pub const FILE_ATTRIBUTE_ARCHIVE: u32 = 1 << 5;
// G (1 << 6) is Reserved2 (MUST be zero) — no constant.
/// H — `FILE_ATTRIBUTE_NORMAL`.
pub const FILE_ATTRIBUTE_NORMAL: u32 = 1 << 7;
/// I — `FILE_ATTRIBUTE_TEMPORARY`.
pub const FILE_ATTRIBUTE_TEMPORARY: u32 = 1 << 8;
/// J — `FILE_ATTRIBUTE_SPARSE_FILE`.
pub const FILE_ATTRIBUTE_SPARSE_FILE: u32 = 1 << 9;
/// K — `FILE_ATTRIBUTE_REPARSE_POINT`.
pub const FILE_ATTRIBUTE_REPARSE_POINT: u32 = 1 << 10;
/// L — `FILE_ATTRIBUTE_COMPRESSED`.
pub const FILE_ATTRIBUTE_COMPRESSED: u32 = 1 << 11;
/// M — `FILE_ATTRIBUTE_OFFLINE`.
pub const FILE_ATTRIBUTE_OFFLINE: u32 = 1 << 12;
/// N — `FILE_ATTRIBUTE_NOT_CONTENT_INDEXED`.
pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: u32 = 1 << 13;
/// O — `FILE_ATTRIBUTE_ENCRYPTED`.
pub const FILE_ATTRIBUTE_ENCRYPTED: u32 = 1 << 14;
// ── ExtraData block signatures (`[MS-SHLLINK]` §2.5) ─────────────────────────
/// `EnvironmentVariableDataBlock` signature.
pub const EXTRA_ENVIRONMENT_VARIABLE_DATA_BLOCK: u32 = 0xA000_0001;
/// `ConsoleDataBlock` signature.
pub const EXTRA_CONSOLE_DATA_BLOCK: u32 = 0xA000_0002;
/// `TrackerDataBlock` signature — carries the machine NetBIOS name and the
/// distributed-link-tracking droid/birth GUIDs (key attribution evidence).
pub const EXTRA_TRACKER_DATA_BLOCK: u32 = 0xA000_0003;
/// `ConsoleFEDataBlock` signature (console code page).
pub const EXTRA_CONSOLE_FE_DATA_BLOCK: u32 = 0xA000_0004;
/// `SpecialFolderDataBlock` signature.
pub const EXTRA_SPECIAL_FOLDER_DATA_BLOCK: u32 = 0xA000_0005;
/// `DarwinDataBlock` signature (Windows Installer / Darwin descriptor).
pub const EXTRA_DARWIN_DATA_BLOCK: u32 = 0xA000_0006;
/// `IconEnvironmentDataBlock` signature.
pub const EXTRA_ICON_ENVIRONMENT_DATA_BLOCK: u32 = 0xA000_0007;
/// `ShimDataBlock` signature (application-compatibility shim layer name).
pub const EXTRA_SHIM_DATA_BLOCK: u32 = 0xA000_0008;
/// `PropertyStoreDataBlock` signature (serialized property store).
pub const EXTRA_PROPERTY_STORE_DATA_BLOCK: u32 = 0xA000_0009;
/// `VistaAndAboveIDListDataBlock` signature.
pub const EXTRA_VISTA_AND_ABOVE_ID_LIST_DATA_BLOCK: u32 = 0xA000_000A;
/// `KnownFolderDataBlock` signature.
pub const EXTRA_KNOWN_FOLDER_DATA_BLOCK: u32 = 0xA000_000B;
/// The ExtraData section is terminated by a `BlockSize` strictly less than
/// `0x00000004` (`[MS-SHLLINK]` §2.5); the canonical terminal block is a 4-byte
/// `0x00000000`. This is the smallest size still treated as a TerminalBlock.
pub const EXTRA_DATA_TERMINAL_BLOCK_SIZE: u32 = 0x0000_0004;