saadtahir-dev/FIMountKit

GitHub: saadtahir-dev/FIMountKit

FIMountKit 是一个 macOS Swift 库,为应用提供挂载和卸载多种取证及通用磁盘映像的统一接口。

Stars: 0 | Forks: 0

# FIMountKit 一个用于在 macOS 上挂载取证和通用磁盘映像的 Swift Package。 | | | |---|---| | **SPM package name** | `FIMountKit` | | **Library product** | `FIMountKit` — 在应用代码中 `import FIMountKit` | | **Platform** | macOS 13+ | | **Swift** | 5.9+ | 专为取证工作流和系统级分析设计:在单一的 `ImageMountingService` API 背后支持 DMG、RAW/DD、EWF、AFF4、VMDK、VHD 以及分卷 RAW 映像。 ## ⚠️ 重要提示:您必须使用本地 Package — 而非 Xcode 的 URL 流程 **请勿通过 Xcode 的“Add Package Dependencies”对话框或 `Package.swift` 中的 `url:` 引用来添加 FIMountKit。** FIMountKit 的子模块(`libewf-spm`、`libvmdk-spm`、`libvhdi-spm`)在其 `Package.swift` 中使用了 `unsafeFlags` 来链接预构建的静态库。 Swift Package Manager **会静默阻止远程 package 使用 `unsafeFlags`**, 这将导致构建失败并出现晦涩的 linker 错误。 使用 FIMountKit 唯一受支持的方法是将其在本地 **clone**,并作为**本地 package** 添加到 Xcode 中。这是一个一次性的设置步骤。 ## 将 FIMountKit 添加到您的应用 ### 步骤 1 — 使用子模块 Clone 务必使用 `--recurse-submodules` 进行 clone。内置的取证库 (`libewf`、`libvmdk`、`libvhdi`、`libcaff4`)是 git submodules,如果不加此标志将无法 获取。 ``` git clone --recurse-submodules https://github.com/saadtahir-dev/FIMountKit.git ``` 如果您已经未加该标志进行了 clone: ``` git submodule update --init --recursive ``` ### 步骤 2 — 在 Xcode 中作为本地 package 添加 1. 在 Xcode 中打开您的应用项目 2. 前往 **File → Add Package Dependencies** 3. 点击 **Add Local...**(对话框左下角) 4. 导航到您 clone FIMountKit 的文件夹并选中它 5. 点击 **Add Package** 6. 在 target dependency 表格中,选择 **FIMountKit** 并点击 **Add Package** ### 步骤 3 — 导入并使用 ``` import FIMountKit ``` ## 保持 FIMountKit 最新 由于 FIMountKit 是本地 package,更新通过 git 进行管理: ``` cd /path/to/FIMountKit git pull git submodule update --recursive ``` 然后在 Xcode 中:**File → Packages → Reset Package Caches** 以应用更改。 ## 功能特性 - 开箱即用的 SwiftPM 库(`FIMountKit` product) - 基于扩展名的格式检测(`ImageFormatDetector`) - 通过 `hdiutil` 原生附加 macOS 映像以呈现块设备 - 通过内置的 FUSE 工具(`ewfmount`、`vmdkmount`、`vhdimount`)支持 EWF / VMDK / VHD — 无需安装 Homebrew 工具 - 通过进程内的 **Libcaff4** 读取 AFF4(无需 CLI,无需 FUSE) - 在附加前进行分卷 RAW 合并(分块、内存安全) - 结构化日志记录,带有针对每次挂载的 correlation IDs - `TemporaryResource` 跟踪以及在卸载时执行 LIFO 清理 - 可安全用于并发场景(`async`/`await`,对 TaskGroup 友好的 mounter) - 可注入的 mounter 列表,便于测试或提供部分格式支持 ## 支持的格式 | 类别 | 扩展名 | 流水线 | |---|---|---| | Apple 磁盘映像 | `.dmg`, `.sparseimage`, `.sparsebundle` | `hdiutil attach` | | 原始映像 | `.raw`, `.dd` | `hdiutil attach` (`CRawDiskImage`) | | EWF (EnCase) | `.e01`, `.ex01`, `.s01` | `ewfmount` (FUSE) → `ewf1` → `hdiutil` | | AFF4 | `.aff4` | **Libcaff4** 完整提取 → 临时 `.img` → `hdiutil` | | VMware VMDK | `.vmdk` | `vmdkmount` (FUSE) → `vmdk1` → `hdiutil` | | Microsoft VHD | `.vhd` | `vhdimount` (FUSE) → `vhdi1` → `hdiutil` | | 分卷 RAW | `.001`, `.002`, … | 合并分段 → `hdiutil` | **检测与合并说明:** `ImageFormatDetector` 也会将 `.000` 和 `.00001` 映射到分卷 RAW,但 `SplitRawMerger` 仅合并**以 `.001` 开始**的集合。请使用 `.001` 作为第一分段以实现可靠的分卷挂载。 **不支持:** `.vhdx`、`.iso`、`.img`(未映射的别名)以及上表之外的格式。 ## 工作原理 ``` Input URL ↓ ImageFormatDetector (file extension → ImageType) ↓ ImageMountingService (path validation, logging, mounter selection) ↓ ImageMounter (per format) ↓ ├─ DMG / RAW / sparse → ProcessExecutor → hdiutil ├─ EWF / VMDK / VHD → bundled *mount (FUSE) → RawImageMounter → hdiutil ├─ AFF4 → Libcaff4 AFF4Image → temp file → RawImageMounter → hdiutil └─ Split RAW → SplitRawMerger → RawImageMounter → hdiutil ↓ MountResult (mount points, devices, temporaryResources) ``` 大多数非原生格式采用**两阶段**处理:生成或暴露一个扁平的 raw 映像,然后复用 `RawImageMounter`。 ## 系统要求 | 要求 | 用途 | |---|---| | macOS 13+ | Package 平台(`Package.swift`) | | Swift 5.9+ / Xcode 15+ | 构建 | | `hdiutil` (系统) | 所有用于附加卷的挂载 | | [macFUSE](https://osxfuse.github.io/) 4.x 或 5.x | **仅限 EWF、VMDK、VHD**(FUSE 工具) | AFF4、DMG、RAW 和分卷 RAW **不**需要 macFUSE。但 AFF4 **确实**需要足够的磁盘空间来容纳映像的完整提取副本。 ## 依赖项 FIMountKit 将四个取证库作为 **git submodules** 打包在 `Dependencies/` 下。使用 `--recurse-submodules` 进行 clone 时会自动解析它们。 | Submodule | 路径 | Repo | |---|---|---| | `libewf-spm` | `Dependencies/libewf-spm` | [github.com/saadtahir-dev/libewf-spm](https://github.com/saadtahir-dev/libewf-spm) | | `libvmdk-spm` | `Dependencies/libvmdk-spm` | [github.com/saadtahir-dev/libvmdk-spm](https://github.com/saadtahir-dev/libvmdk-spm) | | `libvhdi-spm` | `Dependencies/libvhdi-spm` | [github.com/saadtahir-dev/libvhdi-spm](https://github.com/saadtahir-dev/libvhdi-spm) | | `libcaff4-spm` | `Dependencies/libcaff4-spm` | [github.com/saadtahir-dev/libcaff4-spm](https://github.com/saadtahir-dev/libcaff4-spm) | 每个 submodule 都提供了**通用 fat 静态归档**(arm64 + x86_64)以及 SPM 资源包中的**内置 CLI 工具**。在适用的情况下,OpenSSL/zlib 依赖项会被静态链接或通过系统链接。 **依赖关系图:** ``` FIMountKit ├── libewf-spm │ ├── CLibEWF / CLibEWFFuse (static libs) │ ├── CLibEWFResources (bin: ewfmount, …) │ └── libewf (Swift: EWFToolLocator) ├── libcaff4-spm │ ├── Ccaff4 (static libaff4 + headers) │ └── Libcaff4 (Swift: AFF4Image) ├── libvmdk-spm │ ├── CLibVMDK (static libs) │ ├── CLibVMDKResources (bin: vmdkmount, vmdkinfo) │ └── LibVMDK (Swift: VMDKToolLocator) └── libvhdi-spm ├── CLibVHDI (static libs) ├── CLibVHDIResources (bin: vhdimount, vhdiinfo) └── LibVHDI (Swift: VHDIToolLocator) ``` ## 用法 ### 默认服务 ``` import FIMountKit let service = ImageMountingService( log: { message, level, component in print("[\(component.rawValue)] [\(level.rawValue)] \(message)") } ) let result = try await service.mount( url: URL(fileURLWithPath: "/path/to/image.vmdk") ) for mountPoint in result.mountPointURLs { print(mountPoint.path) } try await service.unmount(result) ``` ### 挂载选项 ``` let options = MountOptions( workspaceDirectory: URL(fileURLWithPath: "/tmp/fimountkit-workspace"), volumeMountPoint: URL(fileURLWithPath: "/Volumes/CaseImage") ) let result = try await service.mount( url: URL(fileURLWithPath: "/path/to/image.e01"), options: options ) ``` | 选项 | 用途 | |---|---| | `workspaceDirectory` | FUSE 挂载目录(EWF/VMDK/VHD),可选的分段合并输出父目录 | | `volumeMountPoint` | 传递给 `hdiutil -mountpoint`(必须为空或可创建) | ### 自定义 mounter 集合 ``` let service = ImageMountingService( mounters: [ DMGImageMounter(), RawImageMounter(), EWFImageMounter(), ] ) ``` 默认工厂(`ImageMounterFactory.makeDefaultMounters()`):DMG、Raw、AFF4、EWF、VMDK、VHDI、SplitRaw — 依次执行。服务会选择其 `supportedTypes` 包含已检测类型的**第一个** mounter。 ## 工具解析 `ProcessExecutor` 始终接收一个**绝对可执行路径**;它不会搜索 `PATH`。 | 组件 | 工具解析 | |---|---| | `DMGImageMounter` | `SystemToolLocator` → `hdiutil` | | `RawImageMounter` | `SystemToolLocator` → `hdiutil` | | `EWFMountManager` | `EWFToolLocator.bundledToolPath("ewfmount")` 或系统回退 | | `VMDKMountManager` | `VMDKToolLocator.vmdkmount` 或系统回退 | | `VHDIMountManager` | `VHDIToolLocator.vhdimount` 或系统回退 | | `AFF4ImageMounter` | 进程内 **Libcaff4**(`AFF4Image`) — 无内置 CLI | | `SplitRawMerger` | 纯 Swift / Foundation I/O | ## 公共 API 接口 | 类型 | 角色 | |---|---| | `ImageMountingService` | `mount(url:options:)`、`unmount(_:)` | | `ImageFormatDetector` | 扩展名 → `ImageType` | | `ImageMounter` | 每种格式的挂载/卸载协议 | | `MountResult` | `sourceURL`、`type`、`deviceIdentifiers`、`mountPointURLs`、`temporaryResources`、`metadata` | | `MountOptions` | 工作区和卷挂载点 | | `MountError` | 类型化失败(`unsupportedType`、`detectionFailed`、…) | | `ImageMounterFactory` | 默认 mounter 列表 | | `*ImageMounter` | `DMG`、`Raw`、`AFF4`、`EWF`、`VMDK`、`VHDI`、`SplitRaw` | ## 资源管理 - FUSE 挂载目录、合并的分卷 RAW 文件以及 AFF4 临时提取内容都会记录在 `MountResult.temporaryResources` 中。 - 卸载时会执行特定于格式的分离操作,然后按**相反顺序**删除临时工件。 - 如果在部分设置后发生挂载失败,mounter 会尝试进行清理(例如,如果 `hdiutil` 失败,则关闭 FUSE)。 ## 源码结构 ``` Sources/ImageMounter/ ├── ImageMountingService.swift ├── Detection/ImageFormatDetector.swift ├── Core/ ImageType, MountResult, MountError, MountOptions ├── Mounters/ │ ├── DMG/ DMGImageMounter │ ├── RAW/ RawImageMounter │ ├── EWF/ EWFImageMounter, EWFMountManager │ ├── AFF4/ AFF4ImageMounter │ ├── VMDK/ VMDKImageMounter, VMDKMountManager │ ├── VHD/ VHDIImageMounter, VHDIMountManager │ ├── SplitRAW/ SplitRawImageMounter, SplitRawMerger │ └── ImageMounterFactory.swift ├── Infrastructure/ ProcessExecutor, HDIUtil helpers, SystemToolLocator, MountPathValidator └── Logging/ ImageMounterLogHandler, Logger Dependencies/ ├── libewf-spm/ (git submodule) ├── libvmdk-spm/ (git submodule) ├── libvhdi-spm/ (git submodule) └── libcaff4-spm/ (git submodule) ``` ## 构建与测试 ``` git clone --recurse-submodules https://github.com/saadtahir-dev/FIMountKit.git cd FIMountKit swift package resolve swift build swift test ``` ## 注意事项 - 必须安装并加载 **macFUSE** 才能挂载 EWF、VMDK 和 VHD。 - **AFF4** 挂载会在附加前将整个逻辑映像读取到临时文件中 — 大型映像需要按比例分配空闲磁盘空间和时间。 - **多分段 EWF**(`.e01` + `.e02` + …):打开第一分段;libewf / `ewfmount` 会解析整个集合。 - 只要 `hdiutil` 暴露了**多个分区**,系统即支持每个映像包含多个分区。 - 未使用 App Sandbox 时,嵌入内置二进制文件的主机应用可能需要 **Hardened Runtime** 例外(例如禁用库验证)。 ## 状态 - 已为列出的所有格式实现核心挂载路径 - 可扩展的 `ImageMounter` 协议和可注入的服务 - 已在 Apple Silicon macOS 上通过 `image-mounter-poc` 批量回归 UI 完成验证
标签:Swift, 开源库, 搜索引擎爬虫, 磁盘镜像挂载