Parses Windows LNK shortcut files to extract target paths, timestamps, volume info, machine IDs, and artifacts for digital forensics timeline reconstruction.
npx claudepluginhub killvxk/cybersecurity-skills-zhThis skill uses the workspace's default tool permissions.
- 从 Windows 快捷方式文件重建用户文件访问历史时
Parse Windows LNK shortcut files to extract target paths, timestamps, volume information, and machine identifiers for forensic timeline reconstruction.
Parse Windows LNK shortcut files to extract target paths, timestamps, volume information, and machine identifiers for forensic timeline reconstruction.
Analyzes Windows LNK files and Jump Lists using LECmd, JLECmd, and Shell Link binary parsing to extract evidence of file access, program execution, and user activity in digital forensics.
Share bugs, ideas, or general feedback.
# 以只读方式挂载取证镜像
mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence
mkdir -p /cases/case-2024-001/lnk/{recent,desktop,startup,custom}
# 复制 Recent 目录下的 LNK 文件(主要来源)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/*.lnk \
/cases/case-2024-001/lnk/recent/ 2>/dev/null
# 复制自动目标文件(Jump Lists)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/AutomaticDestinations/*.automaticDestinations-ms \
/cases/case-2024-001/lnk/recent/ 2>/dev/null
# 复制自定义目标文件(固定的 Jump List 项目)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/CustomDestinations/*.customDestinations-ms \
/cases/case-2024-001/lnk/custom/ 2>/dev/null
# 复制桌面快捷方式
cp /mnt/evidence/Users/*/Desktop/*.lnk /cases/case-2024-001/lnk/desktop/ 2>/dev/null
# 复制 Startup 文件夹快捷方式(持久化)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Start\ Menu/Programs/Startup/*.lnk \
/cases/case-2024-001/lnk/startup/ 2>/dev/null
cp "/mnt/evidence/ProgramData/Microsoft/Windows/Start Menu/Programs/Startup"/*.lnk \
/cases/case-2024-001/lnk/startup/ 2>/dev/null
# 查找系统中所有 LNK 文件
find /mnt/evidence/ -name "*.lnk" -type f 2>/dev/null > /cases/case-2024-001/lnk/all_lnk_locations.txt
# 统计并哈希
ls /cases/case-2024-001/lnk/recent/ | wc -l
sha256sum /cases/case-2024-001/lnk/recent/*.lnk > /cases/case-2024-001/lnk/lnk_hashes.txt 2>/dev/null
# 使用 Eric Zimmerman 的 LECmd(Windows 或通过 Mono)
# 处理目录中所有 LNK 文件
LECmd.exe -d "C:\cases\lnk\recent\" --csv "C:\cases\analysis\" --csvf lnk_analysis.csv
# 以详细输出模式处理单个 LNK 文件
LECmd.exe -f "C:\cases\lnk\recent\document.pdf.lnk"
# 处理 Jump List 文件
JLECmd.exe -d "C:\cases\lnk\recent\" --csv "C:\cases\analysis\" --csvf jumplist_analysis.csv
# 输出包含:
# - 源文件路径
# - 目标路径(被访问的文件)
# - 目标创建、修改、访问时间戳
# - LNK 创建和修改时间戳
# - 工作目录
# - 命令行参数
# - 卷序列号和标签
# - 驱动器类型(Fixed、Removable、Network)
# - 机器 ID(NetBIOS 名称)
# - MAC 地址(来自 tracker 数据库)
# - 目标文件大小
pip install LnkParse3
python3 << 'PYEOF'
import LnkParse3
import os, json, csv
from datetime import datetime
lnk_dir = '/cases/case-2024-001/lnk/recent/'
results = []
for filename in sorted(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)
info = lnk.get_json()
parsed = {
'lnk_file': filename,
'target_path': '',
'working_dir': '',
'arguments': '',
'target_created': '',
'target_modified': '',
'target_accessed': '',
'file_size': '',
'drive_type': '',
'volume_serial': '',
'volume_label': '',
'machine_id': '',
'mac_address': '',
}
# 提取头部时间戳
header = info.get('header', {})
parsed['target_created'] = str(header.get('creation_time', ''))
parsed['target_modified'] = str(header.get('modified_time', ''))
parsed['target_accessed'] = str(header.get('accessed_time', ''))
parsed['file_size'] = str(header.get('file_size', ''))
# 提取链接信息
link_info = info.get('link_info', {})
if link_info:
local_path = link_info.get('local_base_path', '')
network_path = link_info.get('common_network_relative_link', {}).get('net_name', '')
parsed['target_path'] = local_path or network_path
vol_info = link_info.get('volume_id', {})
if vol_info:
parsed['drive_type'] = str(vol_info.get('drive_type', ''))
parsed['volume_serial'] = str(vol_info.get('drive_serial_number', ''))
parsed['volume_label'] = str(vol_info.get('volume_label', ''))
# 提取字符串数据
string_data = info.get('string_data', {})
parsed['working_dir'] = str(string_data.get('working_dir', ''))
parsed['arguments'] = str(string_data.get('command_line_arguments', ''))
# 提取 tracker 数据(机器 ID 和 MAC)
extra = info.get('extra', {})
tracker = extra.get('DISTRIBUTED_LINK_TRACKER_BLOCK', {})
if tracker:
parsed['machine_id'] = str(tracker.get('machine_id', ''))
parsed['mac_address'] = str(tracker.get('mac_address', ''))
results.append(parsed)
# 打印摘要
print(f"\n{filename}")
print(f" Target: {parsed['target_path']}")
print(f" Modified: {parsed['target_modified']}")
print(f" Drive: {parsed['drive_type']} (Serial: {parsed['volume_serial']})")
if parsed['machine_id']:
print(f" Machine: {parsed['machine_id']}")
except Exception as e:
print(f" Error parsing {filename}: {e}")
# 将结果写入 CSV
with open('/cases/case-2024-001/analysis/lnk_analysis.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=results[0].keys() if results else [])
writer.writeheader()
writer.writerows(results)
print(f"\n\nTotal LNK files parsed: {len(results)}")
PYEOF
# 识别从可移动介质访问的文件
python3 << 'PYEOF'
import csv
with open('/cases/case-2024-001/analysis/lnk_analysis.csv') as f:
reader = csv.DictReader(f)
print("=== FILES ACCESSED FROM REMOVABLE MEDIA ===\n")
removable = []
network = []
for row in reader:
if 'DRIVE_REMOVABLE' in row.get('drive_type', '').upper() or \
'removable' in row.get('drive_type', '').lower():
removable.append(row)
print(f" {row['target_modified']} | {row['target_path']} | Vol: {row['volume_serial']}")
if 'network' in row.get('drive_type', '').lower() or \
row.get('target_path', '').startswith('\\\\'):
network.append(row)
print(f"\n=== FILES ACCESSED FROM NETWORK SHARES ===\n")
for row in network:
print(f" {row['target_modified']} | {row['target_path']}")
print(f"\nRemovable media files: {len(removable)}")
print(f"Network share files: {len(network)}")
# 检查唯一机器(tracker 数据)
machines = set()
for row in [*removable, *network]:
if row.get('machine_id'):
machines.add(row['machine_id'])
if machines:
print(f"\nMachine IDs found: {machines}")
PYEOF
# 检查 Startup 文件夹 LNK 文件以发现持久化
echo "=== STARTUP FOLDER SHORTCUTS (PERSISTENCE) ===" > /cases/case-2024-001/analysis/startup_persistence.txt
for lnk in /cases/case-2024-001/lnk/startup/*.lnk; do
python3 -c "
import LnkParse3
with open('$lnk', 'rb') as f:
lnk = LnkParse3.lnk_file(f)
info = lnk.get_json()
target = info.get('link_info', {}).get('local_base_path', 'Unknown')
args = info.get('string_data', {}).get('command_line_arguments', '')
print(f' $(basename $lnk): {target} {args}')
" >> /cases/case-2024-001/analysis/startup_persistence.txt 2>/dev/null
done
| 概念 | 描述 |
|---|---|
| Shell Link(.lnk) | Windows 快捷方式文件格式,包含目标路径、时间戳和元数据 |
| 目标时间戳 | 快捷方式所指文件的创建、修改和访问时间 |
| 卷序列号 | 目标文件所在驱动器卷的唯一标识符 |
| 机器 ID | 由分布式链接跟踪(Distributed Link Tracking)服务嵌入的 NetBIOS 名称 |
| MAC 地址 | 创建 LNK 文件的机器上的网络适配器 MAC |
| Jump Lists | 每个应用程序的最近和固定文件列表(包含嵌入的 LNK 数据) |
| 自动目标(Automatic Destinations) | 系统管理的最近打开文件 Jump List 条目 |
| 自定义目标(Custom Destinations) | 用户固定的 Jump List 项目,手动删除前一直保留 |
| 工具 | 用途 |
|---|---|
| LECmd | Eric Zimmerman 命令行 LNK 文件解析器,支持 CSV/JSON 输出 |
| JLECmd | Eric Zimmerman Jump List 解析器 |
| LnkParse3 | 用于编程化 LNK 文件分析的 Python 库 |
| lnk_parser | 备用 Python LNK 解析工具 |
| Autopsy | 带 LNK 文件分析模块的取证平台 |
| KAPE | 自动化 LNK 和 Jump List 取证痕迹采集 |
| Plaso | 带 LNK 文件解析器的时间线工具,用于创建超级时间线 |
| LNK Explorer | 用于交互式 LNK 文件检查的 GUI 工具 |
场景 1:通过 USB 驱动器数据外泄(Data Exfiltration) 分析 Recent 文件夹 LNK 文件中指向可移动驱动器的目标,将卷序列号与 USBSTOR 注册表条目关联,建立从 USB 设备访问的文件列表,确认哪些文档是从可移动驱动器打开的,与文件复制时间戳关联。
场景 2:通过 Startup 快捷方式恶意软件持久化 检查 Startup 文件夹 LNK 文件的恶意目标,检查目标路径和参数中是否有编码命令或可疑可执行文件,验证目标文件是否存在并检查它,将创建时间戳与初始入侵时间关联。
场景 3:网络共享访问调查 筛选具有网络路径(UNC 目标)的 LNK 文件,识别哪些网络共享被访问及访问时间,将机器 ID 与已知企业系统关联,检查是否在正常职责范围外访问了敏感文件服务器,为合规调查构建访问时间线。
场景 4:法律诉讼的文档访问时间线 提取所有 Recent 文件夹 LNK 文件,构建用户访问文档的时间顺序列表,识别与案件相关的特定文件,展示目标时间戳说明文件被打开的时间,与邮件和通信时间线关联。
LNK File Analysis Summary:
User Profile: suspect_user
Total LNK Files: 234 (Recent: 198, Desktop: 23, Startup: 5, Other: 8)
File Access Statistics:
Local drive (C:): 156 files
Removable media: 23 files (3 unique volume serials)
Network shares: 15 files (\\server01, \\fileserver)
Other drives: 4 files
Machine IDs Found: DESKTOP-ABC123, LAPTOP-XYZ789
MAC Addresses: AA:BB:CC:DD:EE:FF, 11:22:33:44:55:66
Removable Media Access:
Volume Serial 1234-ABCD:
2024-01-15 14:32 - E:\Confidential\financial_report.xlsx
2024-01-15 14:45 - E:\Confidential\customer_database.csv
2024-01-15 15:00 - E:\Projects\source_code.zip
Startup Persistence:
updater.lnk -> C:\ProgramData\svc\updater.exe (SUSPICIOUS)
OneDrive.lnk -> C:\Users\...\OneDrive.exe (Legitimate)
Timeline: /cases/case-2024-001/analysis/lnk_analysis.csv