* fix(windows): leave a shortcut icon comparison unknown across code pages Windows stores the LinkInfo LocalBasePath only as ANSI when the system code page can represent it, while StringData stays UTF-16. The parser projects the ANSI bytes as Latin1, so on a code page 936 host a path such as F:\百度网盘\BaiduNetdisk\BaiduNetdisk.exe never matched the same Unicode IconLocation, and icon_location_differs_from_target reported true for a shortcut whose icon is its own target. Record whether each target path is an ANSI projection. Compare it with the icon only when both use the same encoding or the ANSI text is ASCII. A full target that cannot be compared makes the result null, like a %VAR% target. * fix(windows): keep each LinkInfo part's encoding when joining paths A joined LinkInfo target was marked ANSI when any part was ANSI. An ASCII ANSI share with a UTF-16 suffix such as \\server\share + 工具\app.exe then could not be compared with a Unicode icon, although no byte needs a code page. Record which encoding each part's non-ASCII text came from, and compare two paths when their non-ASCII text shares one encoding.
5.0 KiB
Windows Shell Link shortcuts
inspect_windows_shortcut / inspect-windows-shortcut answers whether one
selected local file is a Windows Shell Link (.lnk), which target path,
arguments, working directory, and icon location it records, which volume and
network names LinkInfo stores, and which ExtraData blocks follow the
strings. It reads the file without resolving or executing the target and does
not require a Windows SDK, COM, or a network.
rea inspect-windows-shortcut /absolute/path/to/shortcut.lnk --json
The CLI resolves relative paths against the caller's working directory. MCP and the advertised input schema require an absolute filesystem path and preserve that exact selection:
{
"name": "inspect_windows_shortcut",
"arguments": { "path": "/artifacts/shortcut.lnk" }
}
Observations
The inline Evidence result contains the artifact path, SHA-256, and byte
length. header is the 76-byte ShellLinkHeader: LinkFlags and
FileAttributes as raw values plus documented names, creation/access/write
FILETIMEs as a raw 64-bit decimal and ISO-8601 UTC when the timestamp is in
range, file size, icon index, ShowCommand (normal, maximized, or
minimized), and hotkey modifiers. Undocumented ShowCommand values are
decoded as normal, as specified.
id_list is present when HasLinkTargetIDList is set. Each item keeps its
file offset, size, and type byte. Root-folder, volume, and file-entry items
are decoded when those layouts match documented shell-item headers, including
the 8.3 short name on a file entry. Every other item is raw with a SHA-256
of its payload. Unknown items are not guessed.
link_info reports volume drive type, serial, label, local base path, and
common network relative link names, with Unicode variants when the header
declares them. ANSI strings use a byte-preserving Latin1 projection; the
original system ANSI code page is unobserved.
string_data reports name, relative path, working directory, command-line
arguments, and icon location according to LinkFlags, each with encoding,
CountCharacters, byte length, and the decoded value. IsUnicode selects
UTF-16LE; otherwise the Latin1 projection is used.
extra_data enumerates every block: signature, size, and offset.
EnvironmentVariableDataBlock and IconEnvironmentDataBlock expose ANSI and
Unicode targets. TrackerDataBlock exposes the NetBIOS machine id and droid /
birth-droid GUIDs. Version-1 UUID MAC and timestamp values are labelled
evidence_kind: "derived". KnownFolderDataBlock and SpecialFolderDataBlock
keep their folder identifiers. ConsoleFEDataBlock keeps the code page.
PropertyStoreDataBlock and unrecognized signatures stay raw with SHA-256.
Unknown signatures are listed and are not dropped.
observations are derived only from those documented fields: whether
arguments are present, argument character length, target extension, whether
ShowCommand is minimized, and whether the icon location differs from the
recorded target path. That comparison is null unless the icon and a recorded
target are both full paths: a stored filename, relative path, or %VAR% form
cannot show that two locations differ. Windows stores the LinkInfo path only
as ANSI when the system code page can represent it. An ANSI path with non-ASCII
bytes is therefore not compared with a Unicode icon location, or the reverse,
because the code page is unobserved. This workflow does not emit verdicts
about intent.
A missing optional section is observed absence of that structure. It is not proof the shortcut never carried that data in another container.
Limits and failures
The selected file is limited to 1 MiB by default (16 MiB maximum). At most 256
IDList items (4096 maximum) and 64 ExtraData blocks (1024 maximum) are
examined by default. Retained string payload bytes across StringData,
LinkInfo, and ExtraData are limited to 64 KiB by default (1 MiB maximum).
Malformed HeaderSize or LinkCLSID, and exhausted budgets, fail without
partial success. Truncation after a valid header, ExtraData size overruns, and
odd Unicode lengths return partial coverage with coverage.failing_offset.
A LinkInfo offset that points outside its structure is reported at the
offset field itself, so every issue offset lies inside the file.
Coverage is never complete when issues are present.
The selected path must be a regular file. Symbolic links are rejected.
UNC paths and other host-prefixed device paths, such as \\server\share\a.lnk
and \\?\UNC\server\share\a.lnk, are rejected before any filesystem call. On
Windows, a path whose parent directory is a symbolic link or junction is
rejected before anything follows that link. The check covers the directories
Windows opens after removing . and .., so C:\alias\..\real\a.lnk is
checked at C:\real only; a \\?\ path is checked as written. A mapped
network drive cannot be told apart from a local drive by its path and is not
rejected.
This workflow does not resolve, open, or execute the link target or call COM,
and it does not contact a network for a path on a local volume.