Skip to content

Instantly share code, notes, and snippets.

@yifanlu

yifanlu/psv.h Secret

Last active September 18, 2022 15:37
Show Gist options
  • Select an option

  • Save yifanlu/d546e687f751f951b1109ffc8dd8d903 to your computer and use it in GitHub Desktop.

Select an option

Save yifanlu/d546e687f751f951b1109ffc8dd8d903 to your computer and use it in GitHub Desktop.

Revisions

  1. yifanlu revised this gist Sep 11, 2017. 1 changed file with 23 additions and 4 deletions.
    27 changes: 23 additions & 4 deletions psv.h
    Original file line number Diff line number Diff line change
    @@ -45,18 +45,37 @@ typedef struct {
    uint8_t key1[0x10]; // for klicensee decryption
    uint8_t key2[0x10]; // for klicensee decryption
    uint8_t signature[0x14]; // same as in RIF
    uint8_t hash[0x20]; // optional consistancy check. sha256 over complete data (including any trimmed bytes) if cart dump, sha256 over just the pkg if digital dump.
    uint64_t rif_size; // set to 0 for cart dumps
    uint8_t hash[0x20]; // optional consistancy check. sha256 over complete data (including any trimmed bytes) if cart dump, sha256 over the pkg if digital dump.
    uint64_t image_size; // if trimmed, this will be actual size
    uint8_t data[]; // RIF (if digital) followed by dump (GC image OR PKG)
    } psv_file_header;
    uint64_t image_offset_sector; // image (dump/pkg) offset in multiple of 512 bytes. must be > 0 if an actual image exists. == 0 if no image is included.
    opt_header_t headers[]; // optional additional headers as defined by the flags
    } psv_file_header_t;

    #define PSV_MAGIC (0x00565350) // 'PSV\0'
    #define FLAG_TRIMMED (1 << 0) // if set, the file is trimmed and 'image_size' is the actual size
    #define FLAG_DIGITAL (1 << 1) // if set, RIF is present and an encrypted PKG file follows
    #define FLAG_COMPRESSED (1 << 2) // undefined if set with `FLAG_TRIMMED` or `FLAG_DIGITAL`. if set, the data must start with a compression header (not currently defined)
    #define FLAG_LICENSE_ONLY (FLAG_TRIMMED | FLAG_DIGITAL) // if set, the actual PKG is NOT stored and only RIF is present. 'image_size' will be size of actual package.

    typedef struct {
    uint32_t type; // 0x1 indicates header for digital content
    uint32_t flags; // 1 == game, 2 == DLC, etc (not yet specified)
    uint64_t license_size; // size of RIF that follows
    uint8_t rif[]; // rif file
    } digital_header_t;

    typedef struct {
    uint32_t type; // 0x2 indicates header for compression
    uint32_t compression_algorithm; // not yet specified
    uint64_t uncompressed_size;
    } compression_header_t;

    typedef union {
    uint32_t type;
    digital_header_t;
    compression_header_t;
    } opt_header_t;

    /**
    * Sample Usage 1: Game Cart Archival
    * flag = 0, rif_size = 0, image_size = size of game dump, header is
  2. yifanlu revised this gist Sep 8, 2017. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions psv.h
    Original file line number Diff line number Diff line change
    @@ -45,6 +45,7 @@ typedef struct {
    uint8_t key1[0x10]; // for klicensee decryption
    uint8_t key2[0x10]; // for klicensee decryption
    uint8_t signature[0x14]; // same as in RIF
    uint8_t hash[0x20]; // optional consistancy check. sha256 over complete data (including any trimmed bytes) if cart dump, sha256 over just the pkg if digital dump.
    uint64_t rif_size; // set to 0 for cart dumps
    uint64_t image_size; // if trimmed, this will be actual size
    uint8_t data[]; // RIF (if digital) followed by dump (GC image OR PKG)
    @@ -53,6 +54,7 @@ typedef struct {
    #define PSV_MAGIC (0x00565350) // 'PSV\0'
    #define FLAG_TRIMMED (1 << 0) // if set, the file is trimmed and 'image_size' is the actual size
    #define FLAG_DIGITAL (1 << 1) // if set, RIF is present and an encrypted PKG file follows
    #define FLAG_COMPRESSED (1 << 2) // undefined if set with `FLAG_TRIMMED` or `FLAG_DIGITAL`. if set, the data must start with a compression header (not currently defined)
    #define FLAG_LICENSE_ONLY (FLAG_TRIMMED | FLAG_DIGITAL) // if set, the actual PKG is NOT stored and only RIF is present. 'image_size' will be size of actual package.

    /**
  3. yifanlu revised this gist Sep 7, 2017. 1 changed file with 69 additions and 7 deletions.
    76 changes: 69 additions & 7 deletions psv.h
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,72 @@
    /**
    * Motivation: One unified .psv format for archiving (preserving) Vita games.
    * The goal is to preserve as much of the original game structure while ensuring
    * the all the information needed to decrypt and extract data can be derived
    * from just the file and a hacked Vita.
    *
    * We want something akin to .nds or .3ds/.cia or .iso but for Vita games. The
    * unique challenge is that Vita cart games require a per-cart key to decrypt
    * and digital games require a similar key from activation. With just the raw
    * game image, it is not possible to extract the game data.
    *
    * What's wrong with using .vpk? VPK is designed for homebrew. The patches to
    * enable homebrew strips out a lot of the game executable metadata as well as
    * change the system state to be different than a Vita running an original game.
    * This leads to many subtle as well as major bugs (saves not working, some
    * games require additional patches to run, saves are not compatible with
    * non-hacked Vitas, etc).
    *
    * Why not just ZIP the original files? Why not strip PFS as well to make data
    * mining/emulation easy? Why not make a compressed format? One reason is that
    * by stripping more than necessary (like, for example PFS), we might be losing
    * information that we currently do not think is important. An example of this
    * is when SNES games are first dumped and Earthbound was not dumped properly
    * and people did not know about the anti-piracy checks until much later. There
    * may be, for example, games that do timing checks or checks on the file
    * modification time or something. Either explicitly for anti-piracy or
    * implicitly due to bad programming (a lot of older consoles are infamous for
    * the latter case). By preserving as much of the original structure as
    * possible, we ensure that we can somehow play these games in a future where no
    * more Vitas exist.
    *
    * Different tools (data extraction, backup loaders, archival storage, etc)
    * might require different use cases. Someone might for example want to strip
    * PFS and compress the game data for more efficient storage. We invite them to
    * extend this format though flags BUT just as you shouldn't store all your
    * photos in level-9 compressed JPEG, your code in executables, or any data you
    * care about in a lossy format, you should archive your games in its original
    * form. You can easily go from a RAW image to a JPEG but you cannot go back.
    */

    typedef struct {
    uint32_t magic:24; // 'PSV'
    uint8_t version:8; // 0x00 = first version
    uint8_t key[0x20];
    uint8_t signature[0x14];
    uint64_t image_size;
    uint8_t game_image[]
    uint32_t magic; // 'PSV\0'
    uint32_t version; // 0x00 = first version
    uint32_t flags; // see below
    uint8_t key1[0x10]; // for klicensee decryption
    uint8_t key2[0x10]; // for klicensee decryption
    uint8_t signature[0x14]; // same as in RIF
    uint64_t rif_size; // set to 0 for cart dumps
    uint64_t image_size; // if trimmed, this will be actual size
    uint8_t data[]; // RIF (if digital) followed by dump (GC image OR PKG)
    } psv_file_header;

    #define PSV_MAGIC (0x00565350) // 'PSV\0' = magic for version 1
    #define PSV_MAGIC (0x00565350) // 'PSV\0'
    #define FLAG_TRIMMED (1 << 0) // if set, the file is trimmed and 'image_size' is the actual size
    #define FLAG_DIGITAL (1 << 1) // if set, RIF is present and an encrypted PKG file follows
    #define FLAG_LICENSE_ONLY (FLAG_TRIMMED | FLAG_DIGITAL) // if set, the actual PKG is NOT stored and only RIF is present. 'image_size' will be size of actual package.

    /**
    * Sample Usage 1: Game Cart Archival
    * flag = 0, rif_size = 0, image_size = size of game dump, header is
    * followed by raw dump of game cart
    * Sample Usage 2: Save space of dump
    * flag = FLAG_TRIMMED, rif_size = 0, image_size = size of game dump,
    * header is followed by trimmed dump (trailing zeros are not included)
    * Sample Usage 3: Digital content archival
    * flag = FLAG_DIGITAL, rif_size = 0x200 (size of rif), image_size =
    * size of PKG from PSN servers, header is followed by RIF followed
    * by the game PKG
    * Sample Usage 4: Backup of license for digital content
    * flag = FLAG_DIGITAL | FLAG_TRIMMED, rif_size = 0x200, image_size =
    * size of PKG from PSN servers, header is followed by RIF
    **/
  4. yifanlu created this gist Jun 30, 2017.
    10 changes: 10 additions & 0 deletions psv.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    typedef struct {
    uint32_t magic:24; // 'PSV'
    uint8_t version:8; // 0x00 = first version
    uint8_t key[0x20];
    uint8_t signature[0x14];
    uint64_t image_size;
    uint8_t game_image[]
    } psv_file_header;

    #define PSV_MAGIC (0x00565350) // 'PSV\0' = magic for version 1