mirror of
https://gitea.tendokyu.moe/beerpsi/fsdecrypt.git
synced 2026-10-01 11:17:55 +03:00
When multiple APP files are provided (base seq=0 + delta seq>0), fsdecrypt now automatically links and merges the differencing VHD into the parent using Set-VHD + Merge-VHD (Windows/Hyper-V only). Triggers a single UAC prompt for elevation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
122 lines
4.3 KiB
Markdown
122 lines
4.3 KiB
Markdown
# fsdecrypt
|
|
|
|
Decryptor and extractor for SEGA arcade filesystem containers (fscrypt format).
|
|
|
|
Handles AES-128-CBC encrypted container images used on SEGA Nu/ALLS arcade hardware, automatically parsing the embedded BootID header to identify the game and container type, then decrypting and extracting the contents.
|
|
|
|
## Features
|
|
|
|
- Decrypts OS, APP, and OPTION (DLC) containers
|
|
- Extracts NTFS-based containers (OS/APP) including internal VHD images
|
|
- Extracts ExFAT-based containers (OPTION/DLC packs)
|
|
- **Auto-merges delta update VHDs** with their base on Windows (Hyper-V)
|
|
- Preserves file timestamps during extraction
|
|
- Built-in key database for 70+ game titles
|
|
- Supports external key files for unlisted games
|
|
- Progress bars with transfer speed and ETA
|
|
|
|
## Installation
|
|
|
|
Requires [Rust](https://www.rust-lang.org/tools/install) 1.56+ (edition 2021).
|
|
|
|
```bash
|
|
cargo build --release
|
|
```
|
|
|
|
The binary will be at `target/release/fsdecrypt` (or `fsdecrypt.exe` on Windows).
|
|
|
|
## Usage
|
|
|
|
```
|
|
fsdecrypt [OPTIONS] <FILES>...
|
|
```
|
|
|
|
### Arguments
|
|
|
|
- `<FILES>...` - One or more encrypted container files (`.app`, `.opt`, etc.)
|
|
|
|
### Options
|
|
|
|
- `--no-extract` - Decrypt the container to a raw image file without extracting its contents
|
|
- `-h, --help` - Print help
|
|
- `-V, --version` - Print version
|
|
|
|
### Examples
|
|
|
|
```bash
|
|
# Decrypt and extract an APP container
|
|
fsdecrypt ABCD_1.00.00_20240101120000_0.app
|
|
|
|
# Decrypt and extract an OPTION container
|
|
fsdecrypt ABCD_A001_20240101120000_0.opt
|
|
|
|
# Process multiple containers at once
|
|
fsdecrypt game_v1.app game_v2.app extras.opt
|
|
|
|
# Decrypt only, skip extraction
|
|
fsdecrypt --no-extract ABCD_1.00.00_20240101120000_0.app
|
|
```
|
|
|
|
### Delta Updates
|
|
|
|
When a game ships incremental updates, you get a base `.app` (seq=0) and one or more delta `.app` files (seq>0). Pass them all together and fsdecrypt handles the rest:
|
|
|
|
```bash
|
|
# Base + delta update: fsdecrypt extracts both VHDs, then auto-merges
|
|
fsdecrypt ABCD_1.00.00_20240101120000_0.app ABCD_1.01.00_20240215143000_1_1.00.00.app
|
|
```
|
|
|
|
The merge workflow (Windows only, requires Hyper-V):
|
|
1. Both containers are decrypted and their internal VHDs extracted
|
|
2. `Set-VHD` links the delta (differencing) VHD to its parent
|
|
3. `Merge-VHD` merges the delta into the base VHD
|
|
4. A UAC prompt will appear since these cmdlets require elevation
|
|
|
|
If you only provide the delta without its base, fsdecrypt will extract the VHD and print a warning with instructions.
|
|
|
|
### Output
|
|
|
|
By default, the tool extracts container contents directly:
|
|
|
|
| Type | Extracted contents |
|
|
|--------|--------------------|
|
|
| OS | `internal_{seq}.vhd` |
|
|
| APP | `internal_{seq}.vhd` (auto-merged if delta + base provided) |
|
|
| OPTION | Directory with all DLC files |
|
|
|
|
With `--no-extract`, a raw decrypted image is written instead:
|
|
|
|
| Type | Output filename |
|
|
|--------|-----------------|
|
|
| OS | `{os_id}_{version}_{timestamp}_{seq}.ntfs` |
|
|
| APP | `{game_id}_{version}_{timestamp}_{seq}.ntfs` |
|
|
| OPTION | `{game_id}_{option}_{timestamp}_{seq}.exfat` |
|
|
|
|
## External Key Files
|
|
|
|
For games not in the built-in database, place a key file named `{GAME_ID}.bin` in the working directory:
|
|
|
|
- **16 bytes**: AES-128 key only (IV will be derived automatically)
|
|
- **32 bytes**: AES-128 key (first 16 bytes) + IV (last 16 bytes)
|
|
|
|
## How It Works
|
|
|
|
1. The first 128 bytes of the container are decrypted using a hardcoded master key to obtain the **BootID** header
|
|
2. The BootID contains metadata: game ID, container type, block layout, and an IV mode flag
|
|
3. The game-specific AES-128 key is looked up from the built-in database (or read from an external `.bin` file)
|
|
4. If no IV is hardcoded or the container uses a custom IV, the IV is derived by trial-decrypting the first data page against the expected filesystem header (NTFS or ExFAT magic bytes)
|
|
5. Each 4096-byte page is decrypted independently using AES-128-CBC, with a per-page IV computed by XORing the file IV with the page's file offset
|
|
6. The decrypted stream is parsed as NTFS or ExFAT depending on container type, and contents are extracted
|
|
|
|
## Container Types
|
|
|
|
| Type | ID | Filesystem | Description |
|
|
|------|----|-----------|-------------|
|
|
| OS | `0x00` | NTFS | Operating system image |
|
|
| APP | `0x01` | NTFS | Game application and assets |
|
|
| OPTION | `0x02` | ExFAT | Downloadable content / option packs |
|
|
|
|
## License
|
|
|
|
[BSD Zero Clause License](LICENSE) (0BSD)
|