Skip to content

Repository files navigation

LNKsmith

PyPI

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+.

Install

pip install lnksmith

Or from source:

git clone https://github.com/EuanKerr/lnksmith.git
cd lnksmith
pip install .

Usage

Build a shortcut

lnksmith build "C:\Windows\notepad.exe" \
-o notepad.lnk \
--description "Notepad" \
--icon "C:\Windows\notepad.exe" \
--show normal

The 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):

FlagDescription
(positional)Full Windows target path (required)
-o, --outputOutput file path (default: output.lnk)
-j, --from-jsonJSON config file (keys match build_lnk() kwargs)
--iconIcon source path (StringData)
--icon-envIcon path with %env% variables
--env-targetTarget path with %env% variables
--icon-indexIcon resource index (default: 0)
--descriptionTooltip / comment text
--relative-pathRelative path to target
--working-dirStart-in directory (auto-derived from target if omitted)
--argumentsCommand-line arguments
--showWindow state: normal, maximized, minimized
--file-sizeTarget file size in bytes
--hotkeyHotkey combo (e.g. CTRL+C, ALT+SHIFT+F5)
--creation-timeCreationTime (ISO 8601 or FILETIME ticks)
--access-timeAccessTime (ISO 8601 or FILETIME ticks)
--write-timeWriteTime (ISO 8601 or FILETIME ticks)
--known-folderKnown folder GUID or name (e.g. Desktop)
--pad-argsPrepend N whitespace chars to arguments (ZDI-CAN-25373)
--pad-sizeAppend null bytes to inflate file size (e.g. 100MB)
--appendAppend file content after terminal block (polyglot)
--stomp-motwMotW 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.

More build examples

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.lnk

UNC 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.lnk

Custom 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.lnk

Hotkey binding (Ctrl+Shift+T) with a known folder:

lnksmith build "C:\Tools\terminal.exe" \
--hotkey CTRL+SHIFT+T \
--known-folder "Desktop" \
-o terminal.lnk

Supported 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

Parse a shortcut

# Human-readable output
lnksmith parse shortcut.lnk
# JSON output
lnksmith parse shortcut.lnk --json
# Multiple files
lnksmith parse *.lnk

Python API

fromlnksmithimportbuild_lnk, write_lnk, parse_lnk, format_lnk# Build and write a .lnk filewrite_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 bytesinfo=parse_lnk("notepad.lnk")
print(info.target_path) # C:\Windows\notepad.exeprint(info.description) # Notepadprint(info.working_dir) # C:\Windows# Human-readable dumpprint(format_lnk(info))
# JSON-friendly dictfromdataclassesimportasdictprint(asdict(info))

Red Team Usage

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.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages