Build and parse Windows .lnk files (MS-SHLLINK) in Python.
Project description
LNKsmith
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), LOLBin proxy execution, LNK/HTA polyglots, binary padding, MotW bypass (CVE-2024-38217), NTLM hash theft, icon masquerading, tracker spoofing, and persistence techniques.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lnksmith-0.0.3.tar.gz.
File metadata
- Download URL: lnksmith-0.0.3.tar.gz
- Upload date:
- Size: 80.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7faef9a201c5c81348a9be4ffcdf478dd236c449474476134089230b24da734b
|
|
| MD5 |
ed609bef5863737cf802854dbf3cf1e8
|
|
| BLAKE2b-256 |
40e6ba344c2bb62cb00bd6a6799b73e43c9956457374e9386cf0e3420eaf7c3e
|
Provenance
The following attestation bundles were made for lnksmith-0.0.3.tar.gz:
Publisher:
release.yml on EuanKerr/LNKsmith
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lnksmith-0.0.3.tar.gz -
Subject digest:
7faef9a201c5c81348a9be4ffcdf478dd236c449474476134089230b24da734b - Sigstore transparency entry: 1000404170
- Sigstore integration time:
-
Permalink:
EuanKerr/LNKsmith@6249b2c63b293d99decda4b39e761f90a3a08d78 -
Branch / Tag:
refs/tags/v0.0.3 - Owner: https://github.com/EuanKerr
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6249b2c63b293d99decda4b39e761f90a3a08d78 -
Trigger Event:
push
-
Statement type:
File details
Details for the file lnksmith-0.0.3-py3-none-any.whl.
File metadata
- Download URL: lnksmith-0.0.3-py3-none-any.whl
- Upload date:
- Size: 37.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90ff2e5eb80b932b71a137a6d80041e243186cf0a864a2f4d8326357d7f4cfe7
|
|
| MD5 |
5e2b956475531fbbc9ff5d48924b2d9d
|
|
| BLAKE2b-256 |
829af48861be8b0ae2c2cbad9986d6c2b2a45c58d49261b24d7b4b943c0db641
|
Provenance
The following attestation bundles were made for lnksmith-0.0.3-py3-none-any.whl:
Publisher:
release.yml on EuanKerr/LNKsmith
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lnksmith-0.0.3-py3-none-any.whl -
Subject digest:
90ff2e5eb80b932b71a137a6d80041e243186cf0a864a2f4d8326357d7f4cfe7 - Sigstore transparency entry: 1000404253
- Sigstore integration time:
-
Permalink:
EuanKerr/LNKsmith@6249b2c63b293d99decda4b39e761f90a3a08d78 -
Branch / Tag:
refs/tags/v0.0.3 - Owner: https://github.com/EuanKerr
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6249b2c63b293d99decda4b39e761f90a3a08d78 -
Trigger Event:
push
-
Statement type: