mirror of
https://gitea.tendokyu.moe/moegrid/sega-mount.git
synced 2026-09-25 15:57:55 +03:00
fac052d6c6f97babbfd20cf1787a0f98cf7e6741
sega-mount
SEGA游戏容器挂载工具。解析 ICF 配置文件,通过 fscrypt 驱动解密挂载 APP/OPT 容器,并创建 overlay 差分盘实现可写层,最后通过重解析点将卷设备链接到指定目录。
功能
- 解析 ICF 文件,筛选 Active 状态的 APP/OPT 条目(同 part 自动取最新版本)
- 通过
sgfscrypt驱动解密挂载 APP/OPT 容器(AES-128-CBC) - 创建 overlay.vhd 差分盘作为可写层,挂载到指定盘符
- 递归拷贝 overlay 目录文件到差分盘(首次创建时)
- 通过 NTFS 重解析点(Mount Point)将卷设备链接到目录
- 支持 config.ini 覆盖密钥,空则用内置密钥表
构建
环境要求
- C++20(MSVC 编译器)
- CMake 3.18+
- Windows SDK 10.0
- CLion(推荐)或命令行构建
步骤
mkdir build && cd build
cmake .. -G "Visual Studio 17 2022"
cmake --build . --config Release
CLion 用户直接打开项目即可,CMakeLists.txt 已配置好 /utf-8 和 SDK 版本宏。
生成密钥头文件
内置密钥表由 res/gen_keys.py 从 res/keys.json 生成:
python res/gen_keys.py
输出 src/utils/game_keys.h,包含 76 条游戏的 AES 密钥(编译期 constexpr 数组,无需运行时解析)。keys.json 更新后重新运行此脚本即可。
使用
命令
sega_mount -m [config.ini] 挂载
sega_mount -u [config.ini] 卸载
不指定 config.ini 路径时,默认读取 exe 所在目录的 config.ini。
需要管理员权限运行(驱动服务安装需要)。
config.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 镜像文件所在目录,空则用 exe 所在目录 |
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
挂载/卸载流程
挂载 (-m)
- 读取并解析 ICF 文件(AES 解密 → 结构体解析)
- 筛选 Active APP 条目,按 part_index 排序,验证 base version 依赖链
- 依次挂载 APP 容器(向 fscrypt 驱动发送 MOUNT IOCTL)
- 创建/复用 overlay.vhd 差分盘,挂载到指定盘符
- overlay.vhd 不存在 → 创建差分盘 + 拷贝 overlay 目录文件
- overlay.vhd 已存在 → 直接挂载(沿用数据)
- 挂载 OPT 容器
- 创建 APP/OPT 链接(NTFS 重解析点)
卸载 (-u)
- 移除 APP/OPT 链接(RemoveDirectory 移除 junction)
- 移除 overlay 盘符 + detach overlay.vhd(保留文件)
- 倒序卸载 APP 容器(向驱动发送 UNMOUNT IOCTL)
- 卸载 OPT 容器
项目结构
sega-mount/
├── CMakeLists.txt
├── config.ini # 配置文件示例
├── res/
│ ├── keys.json # 游戏密钥表(源数据)
│ └── gen_keys.py # 密钥表头文件生成脚本
├── src/
│ ├── main.cpp # 入口:INI 解析 + 命令分发
│ ├── config.h # Config 结构体定义
│ ├── 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)
│ └── utils/
│ ├── aes.cpp # AES-128-CBC 加解密(BCrypt)
│ ├── bcrypt_util.cpp # BCrypt 辅助函数
│ ├── crc32.cpp # CRC32 校验
│ ├── files.cpp # 文件读取/目录拷贝/exe路径
│ ├── log.cpp # 日志库(彩色输出 + 等级)
│ ├── strings.cpp # 字符串/路径转换工具
│ ├── crypto_constants.h # BootId/ICF 通用密钥常量
│ └── game_keys.h # 自动生成的游戏密钥表
技术细节
- ICF 解析:ICF 文件经 AES-128-CBC 解密后,按 0x40 字节 section 依次解析 Header 和 Entry,支持 Pack/App/Opt 三种类型
- 容器挂载:读取容器 BootId(0x60 字节)→ AES 解密 → 解析容器元数据 → 构造 0x280 字节 IOCTL 输入缓冲 → 发送 MOUNT IOCTL
- overlay 差分盘:使用
CreateVirtualDisk创建差分 VHD,父盘指向最后一个 APP 容器内的internal_N.vhd;差分盘保留不删除,仅首次创建时拷贝 overlay 目录文件 - 密钥查找优先级:config.ini
[KEYS]section 覆盖 → 内置game_keys::ENTRIES密钥表按 GameID 查找 - 日志格式:
[LEVEL][MODULE] message,彩色输出,不打印敏感信息(密钥/IV)
依赖
sgfscrypt.sys驱动(需放在 exe 同目录)- Windows API:
virtdisk.h(VHD)、winioctl.h(重解析点)、bcrypt.h(AES) - 无第三方 C++ 库依赖
Languages
C++
51.5%
C
46.1%
Python
1.5%
CMake
0.9%