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.0.tar.gz (84.1 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.0-py3-none-any.whl (39.8 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for lnksmith-1.0.0.tar.gz
Algorithm Hash digest
SHA256 56feebce5af1fda1f607808c3bbde2a663249aae886f19f8af158f669f7f0806
MD5 bb2f8492ec1d6fd37a377fe4098210cb
BLAKE2b-256 a927727f8ed79eac988dac40bc2ec17220c139a17ba10db49657ae089fa0754a

See more details on using hashes here.

Provenance

The following attestation bundles were made for lnksmith-1.0.0.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.0-py3-none-any.whl.

File metadata

  • Download URL: lnksmith-1.0.0-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.7

File hashes

Hashes for lnksmith-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5100e29d29305cd4bb09622332c57bbe16c3dbe7c8dac3bd5f6ba3ebd875e49d
MD5 fcb672d07604fd096cec909a9ec645a8
BLAKE2b-256 162096f28c0769f9c661fbb2db3acaa91f298879801d9071e26e8b6ce5fc0635

See more details on using hashes here.

Provenance

The following attestation bundles were made for lnksmith-1.0.0-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