تخطَّ إلى المحتوى

LNK Parser Cheat Sheet

Overview

Windows shortcut files (.lnk) are binary files that contain references to target files, folders, or applications along with rich metadata. LNK parsers are forensic tools that extract this metadata, which includes the target file path, file size, MAC timestamps (Modified, Accessed, Created) of the target at the time the shortcut was created, volume serial numbers, network share paths, machine identifiers, and the MAC address of the system that created the shortcut. LNK files are automatically created by Windows when users open files and are stored in the Recent Items folder, making them valuable artifacts for proving file access.

In digital forensics, LNK files provide evidence of file interaction even after the original files have been deleted. They reveal what files a user accessed, when they accessed them, the original file locations (including removable media and network shares), and sometimes the identity of the computer that created the file. LNK files persist in %APPDATA%\Microsoft\Windows\Recent\, %APPDATA%\Microsoft\Office\Recent\, the Desktop, and other locations. Multiple tools exist for parsing LNK files, including Eric Zimmerman’s LECmd, LnkParse3 (Python), and Exiftool, each offering different output formats and capabilities.

Installation

LECmd (Eric Zimmerman)

# Download LECmd
Invoke-WebRequest -Uri "https://f001.backblazeb2.com/file/EricZimmermanTools/net6/LECmd.zip" -OutFile LECmd.zip
Expand-Archive LECmd.zip -DestinationPath C:\Tools\LECmd

# Verify
C:\Tools\LECmd\LECmd.exe --help

LnkParse3 (Python)

# Install via pip
pip install LnkParse3

# Verify
lnk_parse --help

# Or use as Python library
python3 -c "import LnkParse3; print('LnkParse3 loaded')"

Exiftool

# Linux
sudo apt install libimage-exiftool-perl

# macOS
brew install exiftool

# Windows (Chocolatey)
choco install exiftool

Core Commands

LECmd

CommandDescription
LECmd.exe -f <file>Parse a single LNK file
LECmd.exe -d <directory>Parse all LNK files in directory
LECmd.exe --csv <outdir>Output results as CSV
LECmd.exe --json <outdir>Output results as JSON
LECmd.exe --allShow all available information
LECmd.exe -qQuiet mode (less verbose)
# Parse single LNK file
LECmd.exe -f "C:\Users\analyst\Recent\document.lnk"

# Parse entire Recent directory
LECmd.exe -d "C:\Users\analyst\AppData\Roaming\Microsoft\Windows\Recent" --csv C:\Analysis\

# Parse all LNK files on a drive
LECmd.exe -d "C:\" --csv C:\Analysis\ -q

# Parse with JSON output
LECmd.exe -d "C:\Users\analyst\Recent\" --json C:\Analysis\

# Parse from mounted forensic image
LECmd.exe -d "E:\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent" --csv C:\Evidence\

LnkParse3 (Command Line)

# Parse single file
lnk_parse document.lnk

# Parse with full detail
lnk_parse -a document.lnk

# JSON output
lnk_parse -j document.lnk

# Parse all LNK files in directory
for f in /evidence/Recent/*.lnk; do
    echo "=== $f ==="
    lnk_parse "$f"
done

LnkParse3 (Python API)

import LnkParse3

# Parse a LNK file
with open("document.lnk", "rb") as f:
    lnk = LnkParse3.lnk_file(f)

# Get parsed data as dictionary
data = lnk.get_json()

# Access specific fields
print(f"Target: {lnk.lnk_command}")
print(f"Arguments: {lnk.arguments}")
print(f"Working Dir: {lnk.working_directory}")

# Access header information
header = lnk.header
print(f"Creation Time: {header.creation_time()}")
print(f"Access Time: {header.access_time()}")
print(f"Write Time: {header.write_time()}")
print(f"File Size: {header.file_size()}")

# Access link info
if lnk.link_info:
    print(f"Local Path: {lnk.link_info.local_base_path()}")
    print(f"Volume Serial: {lnk.link_info.volume_serial_number()}")

Exiftool

# Parse LNK file with Exiftool
exiftool document.lnk

# JSON output
exiftool -j document.lnk

# Specific fields
exiftool -TargetFileDOSName -LocalBasePath -VolumeSerialNumber document.lnk

# Batch processing
exiftool -j /evidence/Recent/*.lnk > all_lnk_metadata.json

# Tab-separated output
exiftool -T -FileName -LocalBasePath -FileCreateDate -FileModifyDate /evidence/Recent/*.lnk

Key LNK Metadata Fields

Header Information

FieldDescription
Creation TimeWhen the TARGET file was created (at time of LNK creation)
Access TimeWhen the TARGET file was last accessed
Write TimeWhen the TARGET file was last modified
File SizeSize of the target file
File AttributesArchive, Hidden, System, etc.
Icon IndexIcon associated with the shortcut
Show WindowNormal, Minimized, Maximized
FieldDescription
Local Base PathFull path to target on local volume
Volume LabelVolume label of the drive
Volume Serial NumberSerial number of the volume
Drive TypeFixed, Removable, Network, CD-ROM
Network Share PathUNC path if target is on network
Net NameNetwork share name

Extra Data

FieldDescription
Machine ID (NetBIOS)Computer name where LNK was created
MAC AddressNetwork adapter MAC of creating system
Droid Volume IDNTFS Object ID volume identifier
Droid File IDNTFS Object ID file identifier
Birth Droid Volume IDOriginal volume where file was created
Birth Droid File IDOriginal file ID when first created

Common LNK Locations

# User-specific LNK files
%APPDATA%\Microsoft\Windows\Recent\              # Recent files
%APPDATA%\Microsoft\Windows\Recent\AutomaticDestinations\  # Jump lists
%APPDATA%\Microsoft\Windows\Recent\CustomDestinations\     # Custom jump lists
%APPDATA%\Microsoft\Office\Recent\                # Office recent files
%USERPROFILE%\Desktop\                            # Desktop shortcuts
%APPDATA%\Microsoft\Windows\Start Menu\Programs\  # Start menu

# System-wide
C:\ProgramData\Microsoft\Windows\Start Menu\     # All users start menu

Analysis Techniques

Building File Access Timeline

# Parse all user Recent folders
$users = Get-ChildItem "C:\Users" -Directory
foreach ($user in $users) {
    $recentPath = Join-Path $user.FullName "AppData\Roaming\Microsoft\Windows\Recent"
    if (Test-Path $recentPath) {
        LECmd.exe -d $recentPath --csv "C:\Analysis\LNK\" -q
    }
}

# Analyze CSV output
Import-Csv "C:\Analysis\LNK\*_LECmd_Output.csv" |
    Sort-Object SourceCreated -Descending |
    Select-Object SourceFile, TargetCreated, TargetModified, TargetAccessed, 
                  LocalPath, VolumeSerialNumber, MachineID |
    Format-Table

Detecting Removable Media Access

# Find LNK files pointing to removable media
Import-Csv "C:\Analysis\LNK\*_LECmd_Output.csv" |
    Where-Object { $_.DriveType -eq "Removable" } |
    Select-Object SourceFile, LocalPath, VolumeLabel, VolumeSerialNumber,
                  TargetCreated, TargetModified |
    Format-Table

Network Share Access Evidence

# Find LNK files pointing to network shares
Import-Csv "C:\Analysis\LNK\*_LECmd_Output.csv" |
    Where-Object { $_.NetworkShareName -ne "" } |
    Select-Object SourceFile, NetworkShareName, LocalPath,
                  TargetModified, MachineID |
    Format-Table

Batch Python Analysis

#!/usr/bin/env python3
"""Analyze all LNK files in a directory."""
import os
import json
import LnkParse3
from datetime import datetime

def analyze_lnk_directory(lnk_dir):
    results = []
    for filename in os.listdir(lnk_dir):
        if not filename.lower().endswith('.lnk'):
            continue
        filepath = os.path.join(lnk_dir, filename)
        try:
            with open(filepath, 'rb') as f:
                lnk = LnkParse3.lnk_file(f)
                results.append({
                    'lnk_file': filename,
                    'target': lnk.lnk_command or '',
                    'arguments': lnk.arguments or '',
                    'working_dir': lnk.working_directory or '',
                    'creation_time': str(lnk.header.creation_time()),
                    'access_time': str(lnk.header.access_time()),
                    'write_time': str(lnk.header.write_time()),
                    'file_size': lnk.header.file_size(),
                })
        except Exception as e:
            results.append({'lnk_file': filename, 'error': str(e)})

    return results

results = analyze_lnk_directory('/evidence/Recent/')
print(json.dumps(results, indent=2))

Troubleshooting

IssueSolution
Cannot parse LNK fileVerify file is valid LNK (starts with 4C 00 00 00 magic bytes)
Missing timestamp dataSome LNK files have zeroed timestamps; this is normal for some auto-generated shortcuts
Encoding issuesLNK files may contain Unicode strings; ensure tool supports Unicode output
Corrupted LNK fileTry multiple parsers; some handle corruption better than others
Missing network infoNetwork share info only present if target was on a network path
MAC address not foundExtra data blocks are optional; not all LNK files contain tracker data
Permission deniedRun as Administrator or copy LNK files to writable location first
LECmd CSV emptyVerify the -d path contains actual .lnk files (not just subdirectories)