# How Apollo Save Tool Mounts and Manages trophy.img Files for PS4 Trophy Support

> Apollo Save Tool mounts and manages trophy.img files by decrypting data and exposing it for read/write access via the Orbis file-system API. Learn how it works.

- Repository: [Damián Parrino/apollo-ps4](https://github.com/bucanero/apollo-ps4)
- Tags: how-to-guide
- Published: 2026-02-26

---

**Apollo Save Tool mounts trophy.img files by treating trophy data as encrypted save-data blocks, decrypting the sealed key with the Orbis file-system API, and exposing the mounted image under `/data/apollo/mount/` for read/write access while synchronizing progress to a SQLite database.**

The Apollo Save Tool for PlayStation 4 provides comprehensive trophy editing capabilities by allowing users to mount and manage trophy.img files directly. This open-source utility, available in the `bucanero/apollo-ps4` repository, treats trophy data as a specialized save-data block that requires specific decryption and mounting procedures to access the underlying SQLite database and icon files.

## Understanding Trophy Data as Save Data Blocks

Apollo Save Tool treats PlayStation 4 trophy data as a **save-data block** with special handling. When a save entry is marked with `SAVE_FLAG_TROPHY` (value 128), the tool initiates a specialized mount process that differs from standard save data mounting. This approach allows the tool to leverage the same encryption and file-system abstractions used for regular saves while providing access to the trophy-specific SQLite database and icon resources stored within the `trophy.img` container.

## Step-by-Step Mount Process

The mounting sequence involves path construction, image creation, sealed key decryption, and Orbis API integration. Each step is orchestrated across three core source files: [`source/saves.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/saves.c), [`source/sd.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/sd.c), and [`source/sqlite_db.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/sqlite_db.c).

### Detecting Trophy Saves via SAVE_FLAG_TROPHY

When the UI loads a save entry, it checks the `flags` field for the `SAVE_FLAG_TROPHY` bit. If detected, `orbis_SaveMount()` routes execution to the trophy-specific mounting logic:

```c
if (mount_mode & SAVE_FLAG_TROPHY) { 
    // Trophy-specific mount logic
}

```

*Source:* `orbis_SaveMount()` lines 87-92 in [`source/saves.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/saves.c) – [GitHub link](https://github.com/bucanero/apollo-ps4/blob/main/source/saves.c#L87-L92)

### Building HDD Trophy Paths

The tool constructs the absolute paths to the `trophy.img` and `sealedkey` files using the user's PlayStation Network ID (`apollo_config.user_id`) and the game's title ID:

```c
snprintf(keyPath, sizeof(keyPath), TROPHY_PATH_HDD "%s/sealedkey",
         apollo_config.user_id, save->title_id);
snprintf(volumePath, sizeof(volumePath), TROPHY_PATH_HDD "%s/trophy.img",
         apollo_config.user_id, save->title_id);

```

The `TROPHY_PATH_HDD` macro resolves to `/user/home/%08x/trophy/data/` (defined in [`include/saves.h`](https://github.com/bucanero/apollo-ps4/blob/main/include/saves.h) line 36), resulting in paths like `/user/home/12345678/trophy/data/ABCD1234/trophy.img`.

*Source:* `orbis_SaveMount()` in [`source/saves.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/saves.c) – [GitHub link](https://github.com/bucanero/apollo-ps4/blob/main/source/saves.c#L87-L92)

### Creating the Trophy Image

If the `trophy.img` file does not exist, `orbis_SaveMount()` executes the creation branch (lines 103-115). It opens the SQLite database for the save, inserts a placeholder row, then invokes `createSave()` to generate a clean PFS image and corresponding sealed key:

```c
// Creation logic for missing trophy.img
createSave(volumePath, keyPath, save);

```

*Source:* `orbis_SaveMount()` lines 103-115 in [`source/saves.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/saves.c) – [GitHub link](https://github.com/bucanero/apollo-ps4/blob/main/source/saves.c#L103-L115)

### Decrypting the Sealed Key

The `mountSave()` function in [`source/sd.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/sd.c) receives the `volumePath` and `keyPath`, then decrypts the sealed key using the PlayStation 4's cryptographic services:

```c
ret = decryptSealedKeyAtPath(volumeKeyPath, decryptedSealedKey);
if (ret != 0) {
    LOG("Failed to decrypt sealed key");
    return 0;
}

```

This step is critical because the `trophy.img` is encrypted with a key that is itself encrypted by the console's unique key derivation hardware.

*Source:* `mountSave()` in [`source/sd.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/sd.c) – [GitHub link](https://github.com/bucanero/apollo-ps4/blob/main/source/sd.c#L89-L105)

### Mounting with Orbis File System API

After decryption, the tool initializes the mount options and invokes the Orbis kernel to mount the image:

```c
sceFsInitMountSaveDataOpt(&opt);
opt.budgetid = "system";
ret = sceFsMountSaveData(&opt, volumePath, mountPath, decryptedSealedKey);

```

The `sceFsMountSaveData` function mounts the PFS-formatted `trophy.img` to a temporary sandbox directory, making the trophy files accessible through standard file I/O operations.

*Source:* `mountSave()` lines 89-105 in [`source/sd.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/sd.c) – [GitHub link](https://github.com/bucanero/apollo-ps4/blob/main/source/sd.c#L89-L105)

### Exposing the Mounted Directory

After successful mounting, `orbis_SaveMount()` logs the mount point and copies the directory name back to the caller:

```c
LOG("'%s/%s' mountPath (%s)", save->title_id, save->dir_name, mountDir);
strlcpy(mount_path, save->dir_name, ORBIS_SAVE_DATA_DIRNAME_DATA_MAXSIZE);

```

The UI can now access files under `/data/apollo/mount/<dir_name>/sce_sys/`, which contains the `trophy_local.db` SQLite database and icon resources. This layout mirrors the structure used for standard save data, ensuring consistency across the codebase.

*Source:* `orbis_SaveMount()` lines 44-48 in [`source/saves.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/saves.c) – [GitHub link](https://github.com/bucanero/apollo-ps4/blob/main/source/saves.c#L44-L48)

## Managing Trophy Progress with SQLite

While the mounted `trophy.img` provides raw file access, the **visible progress** displayed in the UI originates from a separate SQLite database located at `TROPHY_DB_PATH` (`/user/home/%08x/trophy/db/trophy_local.db`). The tool provides three core functions for manipulating this data:

| Function | Purpose | Location |
|----------|---------|----------|
| `trophy_unlock()` | Marks a trophy as unlocked, updates flag tables, increments counters, and recomputes group/title progress | [`source/sqlite_db.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/sqlite_db.c) lines 390-428 |
| `trophy_lock()` | Re-locks a previously unlocked trophy, clears timestamps, and decrements progress counters | [`source/sqlite_db.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/sqlite_db.c) lines 430-468 |
| `trophySet_delete()` | Removes an entire trophy set from the DB and deletes the physical `trophy.img` and `sealedkey` files | [`source/sqlite_db.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/sqlite_db.c) lines 470-508 |

The UI populates the Trophies menu by executing a SELECT query against `tbl_trophy_flag` (see [`saves.c`](https://github.com/bucanero/apollo-ps4/blob/main/saves.c) lines 691-704), then decorates each entry with the appropriate icon (bronze, silver, gold, or platinum) based on the `unlocked` column value.

## Practical Implementation Example

Below is a minimal code snippet demonstrating how a developer could implement a command to **unlock all trophies** for a selected game using the Apollo Save Tool's internal APIs:

```c
/* Assume `save_entry_t *game` has been obtained from the UI */
int unlock_all_trophies(const save_entry_t *game) {
    char query[256];
    sqlite3 *db;
    char dbpath[256];

    /* Open the trophy DB for the current user */
    snprintf(dbpath, sizeof(dbpath), TROPHY_DB_PATH, apollo_config.user_id);
    db = open_sqlite_db(dbpath);
    if (!db) return 0;

    /* Simple loop over every trophy id for the game */
    for (int id = 0; id < game->blocks; ++id) {
        /* Unlock each trophy – type is stored in the DB, pass 0 to let the helper resolve it */
        trophy_unlock(game, id, /*group_id*/0, /*type*/0);
    }
    sqlite3_close(db);
    return 1;
}

```

**Key implementation details:**

- Uses the `TROPHY_DB_PATH` macro defined in [`include/saves.h`](https://github.com/bucanero/apollo-ps4/blob/main/include/saves.h) to construct the correct database path.
- Leverages the existing `trophy_unlock()` helper which handles counter increments and progress recomputation automatically.
- Assumes the trophy image is already mounted via `orbis_SaveMount()` before database operations occur.

## Summary

Apollo Save Tool mounts and manages trophy.img files through a sophisticated multi-layered approach that bridges PlayStation 4 system APIs with user-friendly file access:

- **Detection**: The tool identifies trophy entries via the `SAVE_FLAG_TROPHY` bit flag in [`source/saves.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/saves.c).
- **Path Construction**: HDD paths are built using `TROPHY_PATH_HDD` macros incorporating the user's PSN ID and title ID.
- **Image Creation**: Missing trophy images are generated via `createSave()` with proper PFS formatting and sealed keys.
- **Cryptographic Mounting**: `mountSave()` in [`source/sd.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/sd.c) decrypts sealed keys and invokes `sceFsMountSaveData` to mount the encrypted image.
- **Database Management**: Trophy progress is synchronized to `trophy_local.db` via functions like `trophy_unlock()` and `trophy_lock()` in [`source/sqlite_db.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/sqlite_db.c).

This architecture allows seamless read/write access to trophy data while maintaining compatibility with the PlayStation 4's security model and file system expectations.

## Frequently Asked Questions

### How does Apollo Save Tool identify which games have trophy support?

Apollo Save Tool checks the `flags` field of each save entry for the `SAVE_FLAG_TROPHY` bit (value 128) when loading the save list in [`source/saves.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/saves.c). If this bit is set, the tool routes the mount operation through the trophy-specific logic in `orbis_SaveMount()` rather than standard save mounting, ensuring the correct paths and decryption keys are used for trophy data.

### What happens if the trophy.img file doesn't exist on the HDD?

If `orbis_SaveMount()` detects a missing `trophy.img` during the mount process, it executes the creation branch (lines 103-115 in [`source/saves.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/saves.c)). This process opens the SQLite database, inserts a placeholder row, and calls `createSave()` to generate a new PFS-formatted image along with its corresponding sealed key file, effectively initializing a fresh trophy container for the game.

### Where are trophy files mounted for editing?

After successful decryption and mounting via `sceFsMountSaveData` in [`source/sd.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/sd.c), the trophy image is exposed under `/data/apollo/mount/<dir_name>/` where `<dir_name>` represents the save directory name. This sandboxed path contains the `sce_sys/` subdirectory with `trophy_local.db` and icon resources, allowing the UI to perform standard file I/O operations as if accessing normal save data.

### How does the tool keep trophy unlock states synchronized?

Trophy progress is maintained in the `trophy_local.db` SQLite database located at `/user/home/%08x/trophy/db/trophy_local.db`. The tool uses functions like `trophy_unlock()` and `trophy_lock()` in [`source/sqlite_db.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/sqlite_db.c) to update the `tbl_trophy_flag` table, increment or decrement counters, and recompute group progress, ensuring the database state remains consistent with the mounted trophy image contents.