Skip to content
← Back to the blog

How to open a .lnk file (and read what's inside)

· 4 min read

Double-clicking a .lnk runs whatever it points at. That is fine when the shortcut is yours and you trust the target. It is the opposite of what you want when the shortcut came out of a phishing ZIP, a USB stick, or an email attachment. The four options below open the .lnk itself, not the target.

Option 1: paste it into the parser on this site

The dropzone on the home page accepts any .lnk. The file is parsed by a Rust crate compiled to WebAssembly, in your browser. Nothing is uploaded. You get a structured view of every field: ShellLinkHeader bits, LinkFlags, LinkTargetIDList, the LinkInfo (with VolumeID and LocalBasePath), the StringData strings (NAME_STRING, RELATIVE_PATH, WORKING_DIR, COMMAND_LINE_ARGUMENTS, ICON_LOCATION), and any ExtraData blocks. The TrackerDataBlock, if present, exposes the originating machine's NetBIOS name and the MAC-derived droid GUID — fields that are gold for triage but PII you do not want crossing a vendor boundary.

Option 2: PowerShell, for a quick local check

PowerShell uses the same shell COM resolver Explorer uses, so its view matches what double-clicking would show — but it stops before launching.

$ws = New-Object -ComObject WScript.Shell
$lnk = $ws.CreateShortcut("C:\path\to\file.lnk")
$lnk | Format-List TargetPath, Arguments, WorkingDirectory, IconLocation, WindowStyle, Description, Hotkey

What this gets you is fast and matches the resolver. What it does not get you is the LinkFlags, the FILETIME timestamps in the header, the LinkTargetIDList shell item walk, or the ExtraData blocks. For a real DFIR look, use one of the dedicated tools below.

Option 3: a hex viewer for the sniff test

If you just want to confirm a file is a Shell Link, look at the first 20 bytes. Every conforming .lnk opens with a HeaderSize of 4C 00 00 00 (76 little-endian) followed by the LinkCLSID 00021401-0000-0000-C000-000000000046. Anything else and it is not a real .lnk, whatever its extension claims. Useful when you suspect a file has been renamed .lnk to look like one, or when a parser refuses to load and you need to know why.

Option 4: dedicated forensics tools

The ones I actually use:

  • Eric Zimmerman's LECmd — the de-facto standard in DFIR. Command-line, .NET, fast, CSV/JSON output that timeline tools expect. The output schema is essentially the community standard.
  • libyal's liblnk / lnkinfo — the Linux equivalent. Same MS-SHLLINK spec, different language. Slots into shell pipelines.
  • lnkparse3 — pure-Python Shell Link parser. Convenient when you are already in a Python notebook and want to programmatically pull fields.
  • Windows-LNK-Parsing-Library (lcorbasson and friends) — useful for code-level integration with custom tooling.

All four implement MS-SHLLINK. They agree on the field set; they disagree on output formatting and on how strict they are about reserved-must-be-zero bytes. For deep dives where you suspect crafted bytes, run two of them and diff the results.

What you should not do

  • Do not double-click suspicious .lnk files. That is the attack vector. See LNK file malware for what tends to be on the other end.
  • Do not trust the icon. A .lnk can render any icon via IconLocation regardless of what it actually launches. Classic phishing trick: a PDF icon over a cmd.exe target.
  • Do not assume the extension matches. Windows hides .lnk by default in Explorer, so Invoice.pdf.lnk looks like Invoice.pdf. Inspect first.
  • Do not upload to random online parsers. A .lnk leaks your NetBIOS name and MAC. A browser-local parser does not.

If you already know what the bytes mean and want a tour of every field, What is a Windows .lnk file? is the next read. For DFIR-specific extraction, see forensic analysis of .lnk files.

Further reading

  • Microsoft's [MS-SHLLINK] specification on Microsoft Learn — the authoritative reference.
  • Eric Zimmerman, LECmd — the offline tool.
  • libyal, liblnk — the Linux equivalent.
  • For corroborating artifacts when a .lnk is part of a larger case: Jumplist parser, Prefetch parser, registry parser.