Files
2026-08-01 18:18:53 +08:00

170 lines
7.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# sega-mount
SEGA 游戏容器挂载工具。解析 ICF 配置文件,通过 fscrypt 驱动解密挂载 APP/OPT 容器,创建 overlay 差分盘实现可写层,并通过 NTFS 重解析点将卷设备链接到指定目录。提供命令行和 GUI 两种使用方式。
## 功能
- 解析 ICF 文件,筛选 Active 状态的 APP/OPT 条目
- 通过 `sgfscrypt` 驱动解密挂载 APP/OPT 容器
- 创建 overlay.vhd 差分盘作为可写层,挂载到指定盘符
- 递归拷贝 overlay 目录文件到差分盘(首次创建时)
- 通过 NTFS 重解析点(Mount Point)将卷设备链接到目录
- 支持 config.ini 覆盖密钥,空则用内置密钥表
- **GUI 模式**:ImGui + DirectX11 图形界面,可视化配置编辑
## 构建
### 环境要求
- C++20(MSVC 编译器)
- CMake 3.18+
- Windows SDK 10.0
- CLion(推荐)或命令行构建
### 生成密钥头文件
内置密钥表由 `res/gen_keys.py` 从 `res/keys.json` 生成:
```bash
python res/gen_keys.py
```
输出 `src/utils/game_keys.h`,包含 76 条游戏的 AES 密钥(编译期 `constexpr` 数组,无需运行时解析)。`keys.json` 更新后重新运行此脚本即可。
## 使用
### GUI 模式
直接运行 `sega_mount_gui.exe`,界面包含:
- **配置编辑区**:所有 config.ini 字段可直接编辑
- **驱动状态**:启动时自动检测 `sgfscrypt` 驱动服务,无需手动操作
- **挂载/卸载**:一键操作,结果实时显示在日志面板
- **日志面板**:彩色分级显示(INFO/WARN/ERROR),支持自动滚动和清空
- **暗色主题**:CinderImGui 风格,红色强调配色
### 命令行模式
```
sega_mount_cmd -m [config.ini] 挂载
sega_mount_cmd -u [config.ini] 卸载
```
不指定 config.ini 路径时,默认读取当前运行目录(CWD)的 `config.ini`。
> 需要管理员权限运行(驱动服务安装需要)。
### config.ini 格式
```ini
[CONFIG]
ICF_PATH = D:\SDGB_1.55.01\amfs\ICF1
IMAGE_DIR = D:\SDGB_1.55.01
OVERLAY_DIR = D:\SDGB_1.55.01\overlay
MOUNT_LETTER = X
APP_LINK = C:\Mount\App
OPT_LINK = C:\Mount\Option
[KEYS]
APP_KEY = 7CA4E6B6F3D6E8B26472973887D7FA3A
APP_IV = 53FE7135762DE3F97E7FE76B0FEF3F27
OPT_KEY = 5C84A9E726EAA5DD351F2B0750C23697
OPT_IV = C063BF6F562D084D7963C987F5281761
```
| 字段 | 说明 |
|------|------|
| `ICF_PATH` | ICF 文件路径(必填) |
| `IMAGE_DIR` | APP/OPT 镜像文件所在目录,空则用 CWD |
| `OVERLAY_DIR` | overlay 源目录,空或不存在则跳过拷贝 |
| `MOUNT_LETTER` | overlay 卷盘符,默认 X |
| `APP_LINK` | APP 链接基础路径,空则不创建链接 |
| `OPT_LINK` | OPT 链接基础路径,空则不创建链接 |
| `APP_KEY` / `APP_IV` | APP 容器密钥覆盖(hex),空则用内置密钥表 |
| `OPT_KEY` / `OPT_IV` | OPT 容器密钥覆盖(hex),空则用内置密钥表 |
### LINK 输出
挂载成功后,链接目录结构:
```
C:\Mount\App\0\ → FscryptDisk_APP_0 (part 0)
C:\Mount\App\1\ → FscryptDisk_APP_1 (part 1)
C:\Mount\Option\A005\ → FscryptDisk_OPT_A005
C:\Mount\Option\A011\ → FscryptDisk_OPT_A011
```
## 挂载/卸载流程
### 挂载
1. 读取并解析 ICF 文件(AES 解密 → 结构体解析)
2. 筛选 Active APP 条目,按 part_index 排序,验证 base version 依赖链
3. 依次挂载 APP 容器(向 fscrypt 驱动发送 MOUNT IOCTL)
4. 创建/复用 overlay.vhd 差分盘,挂载到指定盘符
- overlay.vhd 不存在 → 创建差分盘 + 拷贝 overlay 目录文件
- overlay.vhd 已存在 → 直接挂载(沿用数据)
5. 挂载 OPT 容器
6. 创建 APP/OPT 链接(NTFS 重解析点)
### 卸载
1. 移除 APP/OPT 链接(RemoveDirectory 移除 junction)
2. 移除 overlay 盘符 + detach overlay.vhd(保留文件)
3. 倒序卸载 APP 容器(向驱动发送 UNMOUNT IOCTL)
4. 卸载 OPT 容器
## 项目结构
```
sega-mount/
├── CMakeLists.txt
├── config.ini # 配置文件示例
├── res/
│ ├── keys.json # 游戏密钥表(源数据)
│ └── gen_keys.py # 密钥表头文件生成脚本
├── src/
│ ├── config.h / config.cpp # Config 结构体 + 全局实例 + INI 读写
│ ├── driver_service.cpp # sgfscrypt 驱动服务管理
│ ├── fscrypt.cpp # 容器挂载/卸载/链接(fscrypt IOCTL)
│ ├── icf_parser.cpp # ICF 文件解析(解密 + 结构体)
│ ├── icf_mount.cpp # ICF 挂载编排(APP + overlay + OPT + LINK)
│ ├── vhd_mount.cpp # VHD 创建/挂载/卸载(virtdisk API)
│ ├── cmd/
│ │ └── main.cpp # 命令行入口
│ ├── gui/
│ │ ├── main.cpp # GUI 入口(WinMain + 主循环)
│ │ ├── ui.cpp # ImGui 界面绘制
│ │ ├── theme.cpp # CinderImGui 暗色主题
│ │ ├── dx11_backend.cpp # DX11 + Win32 后端
│ │ ├── gui_utils.cpp # 配置加载 + 文件/目录对话框
│ │ └── gui_common.h # GUI 全局状态
│ └── utils/
│ ├── aes.cpp # AES-128-CBC 加解密(BCrypt)
│ ├── bcrypt_util.cpp # BCrypt 辅助函数
│ ├── crc32.cpp # CRC32 校验
│ ├── files.cpp # 文件读取/目录拷贝/路径工具
│ ├── log.cpp # 日志库(彩色输出 + 等级)
│ ├── strings.cpp # 字符串/路径转换 + 错误码格式化
│ ├── crypto_constants.h # BootId/ICF 通用密钥常量
│ └── game_keys.h # 自动生成的游戏密钥表
└── tests/
└── test_mount_opt.cpp # 容器挂载/卸载/链接测试工具
```
## 技术细节
- **ICF 解析**:ICF 文件经 AES-128-CBC 解密后,按 0x40 字节 section 依次解析 Header 和 Entry,支持 Pack/App/Opt 三种类型
- **容器挂载**:读取容器 BootId(0x60 字节)→ AES 解密 → 解析容器元数据 → 构造 IOCTL 输入缓冲 → 发送 MOUNT IOCTL(0x22E008),驱动返回 NT 路径用于后续链接
- **容器卸载**:发送 UNMOUNT IOCTL(0x22E00C),按 tag 匹配卸载指定容器
- **overlay 差分盘**:使用 `CreateVirtualDisk` 创建差分 VHD,父盘指向最后一个 APP 容器内的 `internal_N.vhd`;差分盘保留不删除,仅首次创建时拷贝 overlay 目录文件
- **驱动安装**:自动将 `sgfscrypt.sys` 拷贝到 `C:\Windows\System32\drivers\` 并创建服务,避免 exe 目录文件锁定问题
- **密钥查找优先级**:config.ini `[KEYS]` section 覆盖 → 内置 `game_keys::ENTRIES` 密钥表按 GameID 查找
## 依赖
- `sgfscrypt.sys` 驱动(需放在 exe 同目录,安装时自动拷贝到系统目录)
- Windows API:`virtdisk.h`(VHD)、`winioctl.h`(重解析点)、`bcrypt.h`(AES)、`commdlg.h`/`shlobj.h`(文件对话框)
- ImGui(通过 CMake FetchContent 自动拉取,无手动安装)
- DirectX 11(GUI 版渲染后端)