Skip to main content

Build and parse Windows .lnk files (MS-SHLLINK) in Python.

Project description

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

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.

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

from 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))

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lnksmith-1.0.2.tar.gz (84.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lnksmith-1.0.2-py3-none-any.whl (39.8 kB view details)

Uploaded Python 3

File details

Details for the file lnksmith-1.0.2.tar.gz.

File metadata

  • Download URL: lnksmith-1.0.2.tar.gz
  • Upload date:
  • Size: 84.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for lnksmith-1.0.2.tar.gz
Algorithm Hash digest
SHA256 e55343d7b2b5f3894768adfd8fc171f5ff4bd3d8ad970a512e277a58033d84c2
MD5 da56b881e3ebad3dda39ed7faf132537
BLAKE2b-256 cdf2c791b7a35ba00a9fb5b3c1677a40472609899e0de5c8c5228972eec6ff29

See more details on using hashes here.

Provenance

The following attestation bundles were made for lnksmith-1.0.2.tar.gz:

Publisher: release.yml on EuanKerr/LNKsmith

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lnksmith-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: lnksmith-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 39.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for lnksmith-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 4c295d651367101c270839981e39a9ba0e382b9f66f92da663d3d0397c884ec0
MD5 3e1b1953fe46ac1d9fd8aae4c39af809
BLAKE2b-256 94ed24269e0684b988d34f6806b0e6cc1d688ca50c681a56afdb3ea73614a9de

See more details on using hashes here.

Provenance

The following attestation bundles were made for lnksmith-1.0.2-py3-none-any.whl:

Publisher: release.yml on EuanKerr/LNKsmith

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page