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
//! `shellitem` — a Windows Shell Item / `ITEMIDLIST` (PIDL) parser primitive.
//!
//! A Windows **`ITEMIDLIST`** (also "PIDL", pointer to an item identifier list)
//! is the binary form of a shell path: a sequence of variable-length **shell
//! items**, each one component of the path, terminated by an empty item. The
//! same structure appears inside a `.lnk` file's `LinkTargetIDList`, inside
//! registry **ShellBags** (`BagMRU`) values, jump lists, and elsewhere. This
//! crate turns those bytes into typed [`ShellItem`]s and, via
//! [`reconstruct_path`], into a human-readable path such as
//! `My Computer\C:\Users\bob\secret.docx`.
//!
//! This is a **reusable parser primitive**, in the same spirit as the
//! `lznt1` / `xpress-huffman` codecs: it decodes the structure and surfaces the
//! fields, but emits **no findings and makes no forensic judgements**. The
//! forensic interpretation (timeline placement, anomaly grading) lives in the
//! consumers — `lnk-core` (LinkTargetIDList) and `winreg-artifacts` (ShellBags).
//!
//! # Robustness
//!
//! Shell-item blobs are attacker-controllable. Parsing is **panic-free and
//! bounds-checked** throughout: the per-item `cb` size field is validated
//! against the remaining buffer and capped, every integer read goes through a
//! bounds-checked helper, FAT-date conversion is overflow-safe, and UTF-16
//! decoding is lossy (unpaired surrogates become U+FFFD). A truncated or
//! corrupt list stops cleanly at the point of damage rather than panicking.
//!
//! # Authoritative source
//!
//! libyal `libfwsi`, *Windows Shell Item format* (Joachim Metz) — the
//! reverse-engineered reference for the `ITEMIDLIST` framing and every
//! shell-item class layout (root `0x1f`, volume `0x2e`/`0x2f`, file entry
//! `0x30`-major and its `0xbeef0004` extension block, network `0xc3`):
//! <https://github.com/libyal/libfwsi/blob/main/documentation/Windows%20Shell%20Item%20format.asciidoc>.
//! Format constants (class-type bytes, the `0x70` major-class mask, the
//! My-Computer GUID, the `beef0004`/`beef0026` signatures) are sourced from
//! [`forensicnomicon::shellbags`].
//!
//! # Example
//!
//! ```
//! use shellitem::{parse_idlist, reconstruct_path};
//!
//! # let pidl_bytes: &[u8] = &[0, 0]; // an empty ITEMIDLIST (terminator only)
//! let items = parse_idlist(pidl_bytes);
//! let path = reconstruct_path(&items);
//! ```
pub use ;
/// The decoded *kind* of a [`ShellItem`], naming the shell-item class family
/// the bytes belong to (libfwsi). Coarser than the raw `class` byte: several
/// raw bytes collapse into one kind (e.g. `0x31`/`0x32`/`0x35`/`0x36`/`0xb1`
/// are all [`ShellItemKind::FileEntry`]).
/// One decoded shell item — a single component of an `ITEMIDLIST`.
///
/// Fields are populated on a best-effort, per-class basis; a field that does
/// not apply to the item's class, or that was absent/truncated in the bytes,
/// is `None`. The raw item bytes (including the `cb` size prefix) are always
/// retained in [`ShellItem::raw`] so a consumer can re-inspect or surface the
/// class byte for an [`ShellItemKind::Unknown`] item.