$npx -y skills add killvxk/cybersecurity-skills-zh --skill analyzing-lnk-file-and-jump-list-artifacts分析 Windows LNK 快捷方式文件和 Jump List 制品,使用 LECmd、JLECmd 以及对 Shell Link 二进制格式的手动解析,以建立文件访问、程序执行和用户活动的证据。
| 1 | # 分析 LNK 文件和 Jump List 制品 |
| 2 | |
| 3 | ## 概述 |
| 4 | |
| 5 | Windows LNK(快捷方式)文件和 Jump List 是关键的取证制品(forensic artifact),提供文件访问、程序执行和用户行为的证据。当用户通过 Windows 资源管理器或"打开/保存"对话框打开文件时,会自动创建 LNK 文件,其中存储了目标文件的元数据,包括原始路径、时间戳、卷序列号、NetBIOS 名称以及主机系统的 MAC 地址。Windows 7 引入的 Jump List 通过维护每个应用程序最近和频繁访问文件的列表来扩展这一功能。即使目标文件被删除,这些制品仍然存在,使其成为证明用户在特定时间访问特定文件的宝贵手段。 |
| 6 | |
| 7 | ## 前置条件 |
| 8 | |
| 9 | - LECmd(Eric Zimmerman)用于 LNK 文件解析 |
| 10 | - JLECmd(Eric Zimmerman)用于 Jump List 解析 |
| 11 | - Python 3.8+ 及 pylnk3 或 LnkParse3 库 |
| 12 | - 来自 Windows 系统的取证镜像或分诊(triage)收集 |
| 13 | - Timeline Explorer 用于 CSV 分析 |
| 14 | |
| 15 | ## LNK 文件位置 |
| 16 | |
| 17 | | 位置 | 描述 | |
| 18 | |----------|-------------| |
| 19 | | `%USERPROFILE%\AppData\Roaming\Microsoft\Windows\Recent\` | 最近访问的文件 | |
| 20 | | `%USERPROFILE%\Desktop\` | 用户创建的快捷方式 | |
| 21 | | `%USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\` | 开始菜单快捷方式 | |
| 22 | | `%USERPROFILE%\AppData\Roaming\Microsoft\Office\Recent\` | Office 最近文档 | |
| 23 | |
| 24 | ## LNK 文件结构 |
| 25 | |
| 26 | ### Shell Link 头部(76 字节) |
| 27 | |
| 28 | | 偏移 | 大小 | 字段 | |
| 29 | |--------|------|-------| |
| 30 | | 0x00 | 4 | HeaderSize(始终为 0x0000004C) | |
| 31 | | 0x04 | 16 | LinkCLSID(始终为 00021401-0000-0000-C000-000000000046) | |
| 32 | | 0x14 | 4 | LinkFlags | |
| 33 | | 0x18 | 4 | FileAttributes | |
| 34 | | 0x1C | 8 | CreationTime(FILETIME) | |
| 35 | | 0x24 | 8 | AccessTime(FILETIME) | |
| 36 | | 0x2C | 8 | WriteTime(FILETIME) | |
| 37 | | 0x34 | 4 | 目标文件大小 | |
| 38 | | 0x38 | 4 | IconIndex | |
| 39 | | 0x3C | 4 | ShowCommand | |
| 40 | | 0x40 | 2 | HotKey | |
| 41 | |
| 42 | ### LNK 文件中的关键取证字段 |
| 43 | |
| 44 | - **目标文件时间戳**:被引用文件的创建、访问、修改时间 |
| 45 | - **卷信息**:序列号、驱动器类型、卷标 |
| 46 | - **网络共享信息**:UNC 路径、共享名称 |
| 47 | - **机器标识符**:NetBIOS 名称、MAC 地址(来自 TrackerDataBlock) |
| 48 | - **分布式链接跟踪**:机器 ID 和对象 GUID |
| 49 | |
| 50 | ## 使用 EZ Tools 分析 |
| 51 | |
| 52 | ### LECmd——LNK 文件解析器 |
| 53 | |
| 54 | ```powershell |
| 55 | # 解析 Recent 文件夹中的所有 LNK 文件 |
| 56 | LECmd.exe -d "C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent" --csv C:\Output --csvf lnk_analysis.csv |
| 57 | |
| 58 | # 解析单个 LNK 文件并输出完整详情 |
| 59 | LECmd.exe -f "C:\Evidence\Users\suspect\Desktop\Confidential.docx.lnk" --json C:\Output |
| 60 | |
| 61 | # 解析 LNK 文件并附加详细级别 |
| 62 | LECmd.exe -d "C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent" --csv C:\Output --csvf lnk_all.csv --all |
| 63 | ``` |
| 64 | |
| 65 | ### JLECmd——Jump List 解析器 |
| 66 | |
| 67 | ```powershell |
| 68 | # 解析自动 Jump List |
| 69 | JLECmd.exe -d "C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent\AutomaticDestinations" --csv C:\Output --csvf jumplists_auto.csv |
| 70 | |
| 71 | # 解析自定义 Jump List |
| 72 | JLECmd.exe -d "C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent\CustomDestinations" --csv C:\Output --csvf jumplists_custom.csv |
| 73 | |
| 74 | # 解析所有 Jump List 并输出详细信息 |
| 75 | JLECmd.exe -d "C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent\AutomaticDestinations" --csv C:\Output --csvf jumplists_auto.csv --ld |
| 76 | ``` |
| 77 | |
| 78 | ## Jump List 结构 |
| 79 | |
| 80 | ### 自动目标(automaticDestinations-ms) |
| 81 | |
| 82 | 这些是 OLE 复合文件(结构化存储),由文件名中的 AppID 哈希标识: |
| 83 | |
| 84 | | AppID 哈希 | 应用程序 | |
| 85 | |-----------|-------------| |
| 86 | | 5f7b5f1e01b83767 | Windows 资源管理器固定/频繁 | |
| 87 | | 1b4dd67f29cb1962 | Windows 资源管理器最近 | |
| 88 | | 9b9cdc69c1c24e2b | Notepad | |
| 89 | | a7bd71699cd38d1c | Notepad++ | |
| 90 | | 12dc1ea8e34b5a6 | Microsoft Paint | |
| 91 | | 7e4dca80246863e3 | 控制面板 | |
| 92 | | 1cf97c38a5881255 | Microsoft Edge | |
| 93 | | f01b4d95cf55d32a | Windows 资源管理器 | |
| 94 | | 9d1f905ce5044aee | Microsoft Excel | |
| 95 | | a4a5324453625195 | Microsoft Word | |
| 96 | | d00655d2aa12ff6d | Microsoft PowerPoint | |
| 97 | | bc03160ee1a59fc1 | Outlook | |
| 98 | |
| 99 | ### 自定义目标(customDestinations-ms) |
| 100 | |
| 101 | 当用户将条目固定到应用程序 Jump List 时创建。这些文件包含连续的 LNK 条目。 |
| 102 | |
| 103 | ## Python 分析脚本 |
| 104 | |
| 105 | ```python |
| 106 | import struct |
| 107 | import os |
| 108 | from datetime import datetime, timedelta |
| 109 | |
| 110 | FILETIME_EPOCH = datetime(1601, 1, 1) |
| 111 | |
| 112 | def filetime_to_datetime(filetime_bytes: bytes) -> datetime: |
| 113 | """将 Windows FILETIME(自 1601 年起的 100 纳秒间隔)转换为 datetime。""" |
| 114 | ft = struct.unpack("<Q", filetime_bytes)[0] |
| 115 | if ft == 0: |
| 116 | return None |
| 117 | return FILETIME_EPOCH + timedelta(microseconds=ft // 10) |
| 118 | |
| 119 | def parse_lnk_header(lnk_path: str) -> dict: |
| 120 | """解析 LNK 文件的 Shell Link 头部。""" |
| 121 | with open(lnk_path, "rb") as f: |
| 122 | header = f.read(76) |
| 123 | |
| 124 | header_size = struct.unpack("<I", header[0:4])[0] |
| 125 | if header_size != 0x4C: |
| 126 | return {"error": "无效的 LNK 头部"} |
| 127 | |
| 128 | link_flags = struct.unpack("<I", header[0x14:0x18])[0] |
| 129 | file_attrs = struct.unpack("<I", header[0x18:0x1C])[0] |
| 130 | |
| 131 | result = { |
| 132 | "header_size": header_size, |
| 133 | "link_flags": hex(link_flags), |
| 134 | "file_attributes": hex(file_attrs), |
| 135 | "creation_time": filetime_to_datetime(header[0x1C:0x24]), |
| 136 | "access_time": filetime_to_datetime(header[0x24:0x2C]), |
| 137 | "write_time": filetime_to_datetime(header[0x2C:0x34]), |
| 138 | "file_size": struct.unpack("<I", header[0x34:0x38])[0], |
| 139 | "has_target_id_list": bool(link_flags & 0x01), |
| 140 | "has_link_info": bool(link_flags & 0x02), |
| 141 | "has_name": bool(link_flags & 0x04), |
| 142 | "has_relative_path": bool(link_flags & 0x08), |
| 143 | "has_working_dir": bool(link_flags & 0x10), |
| 144 | "has_arguments": |