Analyze Windows LNK shortcut files and Jump List artifacts to establish evidence of file access, program execution, and user activity using LECmd, JLECmd, and manual binary parsing of the Shell Link Binary format.
cybersecurity
digital-forensics
lnk-files
jump-lists
lecmd
jlecmd
windows-forensics
shell-link
user-activity
file-access
program-execution
recent-files
1.0
mahipal
MIT
Analyzing LNK File and Jump List Artifacts
Overview
Windows LNK (shortcut) files and Jump Lists are critical forensic artifacts that provide evidence of file access, program execution, and user behavior. LNK files are created automatically when a user opens a file through Windows Explorer or the Open/Save dialog, storing metadata about the target file including its original path, timestamps, volume serial number, NetBIOS name, and MAC address of the host system. Jump Lists, introduced in Windows 7, extend this by maintaining per-application lists of recently and frequently accessed files. These artifacts persist even after the target files are deleted, making them invaluable for establishing that a user accessed specific files at specific times.
Prerequisites
LECmd (Eric Zimmerman) for LNK file parsing
JLECmd (Eric Zimmerman) for Jump List parsing
Python 3.8+ with pylnk3 or LnkParse3 libraries
Forensic image or triage collection from Windows system
Target file timestamps: Creation, access, modification times of the referenced file
Volume information: Serial number, drive type, volume label
Network share information: UNC path, share name
Machine identifiers: NetBIOS name, MAC address (from TrackerDataBlock)
Distributed Link Tracking: Machine ID and object GUID
Analysis with EZ Tools
LECmd - LNK File Parser
# Parse all LNK files in Recent folderLECmd.exe-d"C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent"--csvC:\Output--csvflnk_analysis.csv# Parse a single LNK file with full detailsLECmd.exe-f"C:\Evidence\Users\suspect\Desktop\Confidential.docx.lnk"--jsonC:\Output# Parse LNK files with additional detail levelsLECmd.exe-d"C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent"--csvC:\Output--csvflnk_all.csv--all
JLECmd - Jump List Parser
# Parse Automatic Jump ListsJLECmd.exe-d"C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent\AutomaticDestinations"--csvC:\Output--csvfjumplists_auto.csv# Parse Custom Jump ListsJLECmd.exe-d"C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent\CustomDestinations"--csvC:\Output--csvfjumplists_custom.csv# Parse all jump lists with detailed outputJLECmd.exe-d"C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent\AutomaticDestinations"--csvC:\Output--csvfjumplists_auto.csv--ld
Jump List Structure
Automatic Destinations (automaticDestinations-ms)
These are OLE Compound files (Structured Storage) identified by AppID hash in the filename:
AppID Hash
Application
5f7b5f1e01b83767
Windows Explorer Pinned/Frequent
1b4dd67f29cb1962
Windows Explorer Recent
9b9cdc69c1c24e2b
Notepad
a7bd71699cd38d1c
Notepad++
12dc1ea8e34b5a6
Microsoft Paint
7e4dca80246863e3
Control Panel
1cf97c38a5881255
Microsoft Edge
f01b4d95cf55d32a
Windows Explorer
9d1f905ce5044aee
Microsoft Excel
a4a5324453625195
Microsoft Word
d00655d2aa12ff6d
Microsoft PowerPoint
bc03160ee1a59fc1
Outlook
Custom Destinations (customDestinations-ms)
Created when users pin items to application jump lists. These files contain sequential LNK entries.
Python Analysis Script
importstructimportosfromdatetimeimportdatetime,timedeltaFILETIME_EPOCH=datetime(1601,1,1)deffiletime_to_datetime(filetime_bytes:bytes)->datetime:"""Convert Windows FILETIME (100-ns intervals since 1601) to datetime."""ft=struct.unpack("<Q",filetime_bytes)[0]ifft==0:returnNonereturnFILETIME_EPOCH+timedelta(microseconds=ft//10)defparse_lnk_header(lnk_path:str)->dict:"""Parse the Shell Link header from an LNK file."""withopen(lnk_path,"rb")asf:header=f.read(76)header_size=struct.unpack("<I",header[0:4])[0]ifheader_size!=0x4C:return{"error":"Invalid LNK header"}link_flags=struct.unpack("<I",header[0x14:0x18])[0]file_attrs=struct.unpack("<I",header[0x18:0x1C])[0]result={"header_size":header_size,"link_flags":hex(link_flags),"file_attributes":hex(file_attrs),"creation_time":filetime_to_datetime(header[0x1C:0x24]),"access_time":filetime_to_datetime(header[0x24:0x2C]),"write_time":filetime_to_datetime(header[0x2C:0x34]),"file_size":struct.unpack("<I",header[0x34:0x38])[0],"has_target_id_list":bool(link_flags&0x01),"has_link_info":bool(link_flags&0x02),"has_name":bool(link_flags&0x04),"has_relative_path":bool(link_flags&0x08),"has_working_dir":bool(link_flags&0x10),"has_arguments":bool(link_flags&0x20),"has_icon_location":bool(link_flags&0x40),}returnresult
Investigation Use Cases
Evidence of File Access
Parse LNK files from Recent folder to identify accessed documents
Cross-reference with MFT timestamps and USN Journal entries
Note that LNK files persist even after target files are deleted