SecurityRonin/lnk-forensic

GitHub: SecurityRonin/lnk-forensic

一款纯 Rust 编写的 Windows .lnk 快捷方式和 Jump List 取证分析器,能将快捷方式元数据转化为分级取证发现,揭示可移动媒体、网络共享和跨机器使用痕迹。

Stars: 0 | Forks: 0

# lnk-forensic [![Crates.io lnk-core](https://img.shields.io/crates/v/lnk-core?label=lnk-core)](https://crates.io/crates/lnk-core) [![Crates.io lnk-forensic](https://img.shields.io/crates/v/lnk-forensic?label=lnk-forensic)](https://crates.io/crates/lnk-forensic) [![Docs.rs](https://img.shields.io/docsrs/lnk-core?label=docs.rs)](https://docs.rs/lnk-core) [![Rust 1.81+](https://img.shields.io/badge/rust-1.81%2B-blue.svg)](https://www.rust-lang.org) [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE) [![Sponsor](https://img.shields.io/badge/sponsor-h4x0r-ea4aaa?logo=github-sponsors)](https://github.com/sponsors/h4x0r) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/58c076272b041109.svg)](https://github.com/SecurityRonin/lnk-forensic/actions/workflows/ci.yml) [![Coverage](https://img.shields.io/badge/coverage-100%25%20lib-brightgreen.svg)](https://github.com/SecurityRonin/lnk-forensic/actions/workflows/ci.yml) [![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/) [![Security advisories](https://img.shields.io/badge/security-advisories%20clean-brightgreen.svg)](deny.toml) **将一个 Windows `.lnk` 快捷方式 —— 或整个 Jump List —— 转化为分级取证发现 —— 揭示从 USB 闪存盘打开的文件、其来源的共享位置,以及创作该文件的机器,并附带将其关联回物理设备的卷序列号。** `.lnk` 是一种内容丰富的 `[MS-SHLLINK]` 取证产物:它记录了目标路径、卷 序列号和 MAC 时间戳、来源机器的 NetBIOS 名称,以及一个分布式 链接跟踪 droid GUID —— 通常是已不存在的文件的证据。 `lnk-forensic` 从**任何** Windows 主机上创建的链接中读取这些信息,并对 对分诊至关重要的内容进行分级。它还解析 **Jump Lists** —— 任务栏/“开始”菜单的 MRU 产物 —— 包括 `*.automaticDestinations-ms`(一个 OLE/CFB 复合文件,包含一个 `DestList` MRU 流 + 每个条目嵌入一个 `.lnk`)和 `*.customDestinations-ms`(一段连续的嵌入式 `.lnk`),在每个嵌入式链接上复用相同的 shell-link 审计。 ## 在 30 秒内审计 Shell Link ``` [dependencies] lnk-forensic = "0.2" # pulls in lnk-core ``` ``` use lnk_core::parse_shell_link; use lnk_forensic::{audit_findings}; // .lnk bytes off disk; a malformed header yields None, never a panic. if let Some(link) = parse_shell_link(lnk_bytes) { for f in audit_findings(&link, "volume: E:") { println!("[{:?}] {} — {}", f.severity, f.code, f.note); // e.g. [Some(Medium)] LNK-REMOVABLE-MEDIA-TARGET — the link target resolves to a removable … } } ``` 想要原始类型化流而不是分级发现?`audit(&link)` 返回 `Vec`;每个异常通过 `to_finding(source)` 生成一个 `forensicnomicon::report::Finding`。 ## 异常代码 每个异常都是一个**观察结果**(“符合……”);由检查人员得出 结论。这些代码是稳定、公开的契约。 | 代码 | 严重程度 | 类别 | 观察内容 | |---|---|---|---| | `LNK-REMOVABLE-MEDIA-TARGET` | 中 | 威胁 | `VolumeID` 描述了一个 `DRIVE_REMOVABLE` 卷 —— 符合从外部媒体打开的文件的特征 (MITRE T1052.001 / T1091)。**卷序列号**被作为连接外部设备连接的关联键值呈现。 | | `LNK-NETWORK-TARGET` | 低 | 威胁 | 链接携带了一个 `CommonNetworkRelativeLink` —— 符合从网络共享打开的文件的特征 (MITRE T1021)。 | | `LNK-TRACKER-MACHINE` | 信息 | 来源 | `TrackerDataBlock` 记录了来源机器的 NetBIOS 名称 —— 符合链接是在该机器上创建的特征(归属)。 | ## Jump Lists —— 自动 + 自定义目标 `parse_automatic_destinations(bytes, filename)` 将 `*.automaticDestinations-ms` 作为 CFB 复合文件打开,读取 `DestList` MRU 流(Windows 7 v1 和 Windows 10/11 v2+ 布局),并解码每个嵌入的 `.lnk` 子流; `parse_custom_destinations(bytes, filename)` 通过 `[MS-SHLLINK]` CLSID 和 `0xBABFFBAB` 页脚,将扁平的 `*.customDestinations-ms` 拆分为其嵌入的 `.lnk`。`audit_jumplist(&jl, acquisition_host, scope)` 运行 **现有的逐链接审计,覆盖每个嵌入的链接**(因此上面的代码会免费触发), 外加四个 Jump List 级别的代码: | 代码 | 严重程度 | 类别 | 观察内容 | |---|---|---|---| | `JUMPLIST-PINNED-TARGET` | 低 | 来源 | 一个 `DestList` 条目被**固定** —— 符合用户故意将此目标固定到应用程序的 Jump List 的特征。 | | `JUMPLIST-CROSS-MACHINE` | 低 | 来源 | 一个 `DestList` 条目的来源主机名(或 droid 卷 GUID)**与采集主机不匹配** —— 符合目标/产物源自另一台机器的特征。 | | `JUMPLIST-MRU-RECENCY` | 信息 | 历史 | 一个 `DestList` 条目的最后访问时间 + 访问计数 —— 应用程序自身针对该目标的使用历史。 | | `JUMPLIST-APPID-IDENTIFIED` | 信息 | 来源 | Jump List 的 `AppID` 通过 `forensicnomicon::jumplist::appid_name` 解析为已知应用程序。 | DestList 偏移量表、`0xBABFFBAB` 页脚、嵌入式 LNK 的 CLSID 边界,以及 `AppID` 映射均来自 [`forensicnomicon::jumplist`](https://crates.io/crates/forensicnomicon)。 ## 卷序列号是跨产物的关联键 `.lnk` 的 `VolumeID.DriveSerialNumber` 与 USB 大容量存储设备在注册表 / setupapi 日志中记录的 32 位卷序列号相同。`lnk-forensic` 将其在可移动媒体异常中作为一等公民呈现,以便检查人员能够将 从外部媒体打开的文件(此链接)与携带它的**物理 设备**(一个 [`peripheral-forensic`](https://github.com/SecurityRonin/peripheral-forensic) `DeviceConnection`)进行**关联**。该序列号就是关联键 —— 链接提供数值,由 检查人员进行核对。 ## 双 crate 拆分 - **`lnk-core`** —— 读取器。解析 0x4C `ShellLinkHeader`(LinkFlags, FileAttributes,三个目标 FILETIMEs → Unix epoch,文件大小,图标索引, 显示命令,热键),`LinkInfo` 块(`VolumeID` 驱动器类型 + 序列号 + 标签,本地基路径,`CommonNetworkRelativeLink`),ANSI/Unicode `StringData`, 原始 `LinkTargetIDList` PIDL blob(完整的 PIDL 解码是 shellbag 解析器的 工作),`ExtraData` `TrackerDataBlock`,以及 **Jump Lists**(自动 + 自定义 目标)。格式常量来自 [`forensicnomicon::shlink`](https://crates.io/crates/forensicnomicon) 和 [`forensicnomicon::jumplist`](https://crates.io/crates/forensicnomicon); 解析算法存放在这里。无发现。 - **`lnk-forensic`** —— 分析器。将 `ShellLink` 或 `JumpList` 审计为分级的 `forensicnomicon::report::Finding`s。依赖于 `lnk-core`。 ### 第三方依赖说明 `lnk-core` 依赖于成熟的、基于 MIT 许可证的 [`cfb`](https://crates.io/crates/cfb) crate 来读取存储 `*.automaticDestinations-ms` Jump Lists 的 OLE Compound-File 容器 —— 这是“优先使用我们自己的解析器”的一个 记录在案的例外,其地位与 NTFS 的 `lznt1` 相同: 重用一个正确、维护良好、范围更窄的读取器胜过 重新发明一个 OLE/CFB 解析器。我们自己的代码保持 `#![forbid(unsafe_code)]`。 ## 信任,但要验证 专为处理来自可能已受损系统的不可信 `.lnk` 文件而构建: - **`#![forbid(unsafe_code)]`** 覆盖两个 crate —— 无 FFI,无 C 绑定。 - **在恶意输入下不会引发 panic** —— 每个整数/长度/偏移量的读取都进行了 边界检查;工作空间在生产代码中拒绝 `clippy::unwrap_used` 和 `clippy::expect_used`。截断或乱码链接会 导致子结构缺失或返回 `None`,绝不会崩溃。 - **经过模糊测试** —— `cargo-fuzz` 针对 `shelllink`(读取器)、`forensic`(完整的 解析 → 审计管道)和 `jumplist`(CFB/DestList + 自定义 目标解析 → 审计)进行测试;`fuzz.yml` CI 工作流会构建并对 每一个进行冒烟测试。 - **根据精确规格产物进行了验证** —— 管道经过了 端到端的测试,使用了手工编写的测试夹具:`[MS-SHLLINK]` 链接(带有卷序列号的可移动 媒体链接 + 一个网络共享链接; `forensic/tests/real_data.rs`)和 Jump Lists(一个真实的 CFB `*.automaticDestinations-ms`,包含固定的、跨机器的可移动条目 + 一个 扁平的 `*.customDestinations-ms`;`forensic/tests/jumplist.rs`),核对了 呈现出的序列号和发现。 ``` cargo test cargo +nightly fuzz run forensic # requires nightly + cargo-fuzz ``` ## 适用场景 `lnk-forensic` 是 SecurityRonin 取证工具舰队中的一个解析器/分析器:每个 crate 都是某一产物家族的资深专家,发出共享的 `forensicnomicon::report` 词汇,以便发现结果能够在磁盘、 内存、日志和注册表产物中统一聚合。 [隐私政策](https://securityronin.github.io/lnk-forensic/privacy/) · [服务条款](https://securityronin.github.io/lnk-forensic/terms/) · © 2026 Security Ronin Ltd
标签:Rust, 可视化界面, 快捷方式解析, 数字取证, 文件分析, 网络流量审计, 自动化脚本, 通知系统