Build and parse Windows .lnk shortcut files in Python.
Implements the MS-SHLLINK specification using the
standard library struct module. Runs on any platform; the resulting .lnk
files are valid on Windows.
Requires Python 3.12+.
pip install lnksmithOr from source:
git clone https://github.com/EuanKerr/lnksmith.git
cd lnksmith
pip install .lnksmith build "C:\Windows\notepad.exe" \
-o notepad.lnk \
--description "Notepad" \
--icon "C:\Windows\notepad.exe" \
--show normalThe target path is positional - no --target flag needed. The working
directory is auto-derived from the target's parent (here C:\Windows) unless
you override it with --working-dir.
CLI flags (common options):
| Flag | Description |
|---|---|
| (positional) | Full Windows target path (required) |
-o, --output |
Output file path (default: output.lnk) |
-j, --from-json |
JSON config file (keys match build_lnk() kwargs) |
--icon |
Icon source path (StringData) |
--icon-env |
Icon path with %env% variables |
--env-target |
Target path with %env% variables |
--icon-index |
Icon resource index (default: 0) |
--description |
Tooltip / comment text |
--relative-path |
Relative path to target |
--working-dir |
Start-in directory (auto-derived from target if omitted) |
--arguments |
Command-line arguments |
--show |
Window state: normal, maximized, minimized |
--file-size |
Target file size in bytes |
--hotkey |
Hotkey combo (e.g. CTRL+C, ALT+SHIFT+F5) |
--creation-time |
CreationTime (ISO 8601 or FILETIME ticks) |
--access-time |
AccessTime (ISO 8601 or FILETIME ticks) |
--write-time |
WriteTime (ISO 8601 or FILETIME ticks) |
--known-folder |
Known folder GUID or name (e.g. Desktop) |
--pad-args |
Prepend N whitespace chars to arguments (ZDI-CAN-25373) |
--pad-size |
Append null bytes to inflate file size (e.g. 100MB) |
--append |
Append file content after terminal block (polyglot) |
--stomp-motw |
MotW bypass: dot or relative (CVE-2024-38217) |
JSON-only fields (via --from-json):
Advanced MS-SHLLINK fields like tracker metadata, volume info, darwin/shim
blocks, special folders, network provider details, and property stores are
set through a JSON config file. JSON keys match build_lnk() kwargs
directly. CLI flags override JSON values when both are provided.
Environment-variable target (resolved by Windows at launch):
lnksmith build "C:\Windows\System32\cmd.exe" \
--env-target "%COMSPEC%" \
--arguments "/k echo hello" \
--show minimized \
-o cmd.lnkUNC network path with a mapped drive letter (via JSON config):
echo '{"network_device_name": "Z:"}' > config.json
lnksmith build "\\\\fileserver\shared\report.xlsx" \
-j config.json \
-o report.lnkCustom timestamps and volume metadata (via JSON config):
{
"volume_label": "DATA",
"drive_serial": 3735928559,
"tracker_machine_id": "WORKSTATION01"
}lnksmith build "C:\Tools\app.exe" \
--creation-time "2025-06-15T08:30:00Z" \
--write-time "2025-06-15T09:00:00Z" \
-j config.json \
-o app.lnkHotkey binding (Ctrl+Shift+T) with a known folder:
lnksmith build "C:\Tools\terminal.exe" \
--hotkey CTRL+SHIFT+T \
--known-folder "Desktop" \
-o terminal.lnkSupported modifier names: SHIFT, CTRL, ALT. Key names: A-Z,
0-9, F1-F24, NUM LOCK, SCROLL LOCK (per MS-SHLLINK section 2.1.3).
The Python API (build_lnk) accepts any VK code with a warning for non-spec values.
Icon from an environment-variable path with a custom index:
lnksmith build "C:\Program Files\MyApp\app.exe" \
--icon-env "%ProgramFiles%\MyApp\app.exe" \
--icon-index 1 \
--description "My Application" \
-o myapp.lnk# Human-readable output
lnksmith parse shortcut.lnk
# JSON output
lnksmith parse shortcut.lnk --json
# Multiple files
lnksmith parse *.lnkfrom lnksmith import build_lnk, write_lnk, parse_lnk, format_lnk
# Build and write a .lnk file
write_lnk("notepad.lnk", target=r"C:\Windows\notepad.exe",
description="Notepad", working_dir=r"C:\Windows")
# Build to bytes (useful for sending over a network, embedding, etc.)
data = build_lnk(target=r"C:\Windows\System32\cmd.exe",
arguments="/k whoami", show_command=7)
# Parse from a file path or raw bytes
info = parse_lnk("notepad.lnk")
print(info.target_path) # C:\Windows\notepad.exe
print(info.description) # Notepad
print(info.working_dir) # C:\Windows
# Human-readable dump
print(format_lnk(info))
# JSON-friendly dict
from dataclasses import asdict
print(asdict(info))See docs/redteam.md for offensive tradecraft patterns including argument padding (ZDI-CAN-25373 / CVE-2025-9491), LOLBin proxy execution, LNK/HTA polyglots, binary padding, MotW bypass (CVE-2024-38217), NTLM hash theft, target path spoofing (Beukema Variants 0/1/4), icon masquerading, tracker spoofing, and persistence techniques.
Target path spoofing techniques are based on Wietze Beukema's "Trust Me, I'm A Shortcut" research and the lnk-it-up tool.
MIT