SELF - SPRX
Source: http://ps3wiki.lan.st/index.php?title=SELF_File_Format_and_Decryption
Contents
File Format
Notes:
- Numbers are stored in big endian format.
SELF Header
typedef struct
{
uint32_t magic; // "SCE\0"
uint32_t version; // 2
uint16_t attribute; // 0x8000 - fself
uint16_t category;
uint32_t metadataInfoOffset;
uint64_t fileOffset;
uint64_t fileSize;
uint64_t unknown06;
uint64_t programInfoOffset;
uint64_t elfHeaderOffset;
uint64_t elfProgramHeadersOffset;
uint64_t elfSectionHeadersOffset;
uint64_t sInfoOffset;
uint64_t versionInfoOffset;
uint64_t controlInfoOffset;
uint64_t controlInfoSize;
uint64_t unknown15;
}
SELFHEADER_t;
Program Info
typedef struct
{
uint64_t programAuthId;
uint64_t unknown01;
uint16_t programVersion[4];
uint64_t unknown03;
}
PROGRAMINFO_t;
ELF Header
See Spec here: ELF Header
Notes:
- e_type: ET_PS3PRX=0xFFA4
- EI_OSABI: ELFOSABI_CELL_LV2=0x66
ELF Program Headers
See Spec here: ELF Program Headers
Segment Information
typedef struct
{
uint64_t dataOffset;
uint64_t dataSize;
uint32_t compressed; //1:NO, 2:YES
uint32_t unknown03;
uint32_t unknown04;
uint32_t encrypted; //0:NA, 1:YES, 2:NO
}
SEGMENTINFO_t;
Notes:
- There is one Segment Information for each ELF Program Header.
Control Information
typedef struct
{
uint32_t unknown00;
uint32_t unknown01;
uint32_t unknown02;
uint32_t unknown03;
uint32_t controlFlags[8];
uint32_t unknown05;
uint32_t unknown06;
uint32_t unknown07;
uint32_t unknown08;
char digest[64];
uint32_t unknown10;
uint32_t unknown11;
}
CONTROLINFO_t;
Metadata Information
typedef struct
{
uint8_t unknown00[32];
uint8_t key[32];
uint8_t ivec[32];
}
METADATAINFO_t;
Notes:
- The key and ivec fields are encrypted using AES256CBC.
- This is not present if it is an FSELF.
Metadata Header
typedef struct
{
uint64_t signatureInputLength;
uint32_t unknown02;
uint32_t sectionCount;
uint32_t keyCount;
uint32_t signatureInfoSize;
uint32_t unknown06;
uint32_t unknown07;
}
METADATAHEADER_t;
Notes:
- The metadata header is located after the metadata info in the SELF file.
- It is decrypted using AES128CTR with the key and ivec entries from the metadata information.
- The signature input length is the number of bytes which are used to generate the SHA-1 which is used to generate the ECDSA signature. The length should be eveything from the beginning until the signature itself. The decrypted version of the input data is used.
- This is only present if the metadata Information is present.
Metadata Section Headers
typedef struct
{
uint64_t dataOffset;
uint64_t dataSize;
uint32_t unknown02;
uint32_t programIndex;
uint32_t unknown04;
uint32_t sha1Index;
uint32_t encrypted; //1:NO, 3:YES
uint32_t keyIndex;
uint32_t ivecIndex;
uint32_t compressed; //1:NO, 2:YES
}
METADATASECTIONHEADER_t;
Notes:
- The metadata section headers are located after the metadata header in the SELF file.
- The number of sections is indicated by the sectionCount entry in the metadata header.
- They are decrypted using AES128CTR with the key and ivec entries from the metadata information.
- Section data is decrypted using AES128CTR with the key and ivec from the metadata keys specified by keyIndex and ivecIndex.
- Section data will also need to be uncompressed using zlib.
- The dataOffsets of the metadata section headers match in general the segment information dataOffsets.
- This is only present if the metadata header is present.
Metadata Keys
typedef uint8_t METADATAKEY_t [16];
Notes:
- The metadata keys are located after the metadata section headers in the SELF file.
- The number of keys is indicated by the keyCount entry in the metadata header.
- They are decrypted using AES128CTR with the key and ivec entries from the metadata information.
- If the sha1Index points to a key, then key[sha1Index] and key[sha1Index+1] form the 160-bit hash. key[sha1Index+2] to key[key[sha1Index+6] form the 512-bit key for the HMAC-SHA1. The HMAC-SHA1 is calculated on the decrypted data and before the decompression.
Signature Information
typedef struct
{
uint32_t unknown00;
uint32_t signatureSize;
uint64_t unknown02;
uint64_t unknown03;
uint64_t unknown04;
uint64_t unknown05;
uint32_t unknown06;
uint32_t unknown07;
}
SIGNATUREINFO_t;
Notes:
- The signature information is located after the metadata keys in the SELF file.
- It is only present if the signatureInfoSize in the metadata header is not zero.
- It is decrypted using AES128CTR with the key and ivec entries from the metadata information.
Signature
typedef struct
{
uint8_t r[21];
uint8_t s[21];
uint8_t padding[6];
}
SIGNATURE_t;
Notes:
- The signature is located after the the signature information in the SELF file.
- It is even present if the signature information is not present.
- It is decrypted using AES128CTR with the key and ivec entries from the metadata information.
Extracting an ELF
ELF Header
Elf64_Ehdr elfHeader; fseek ( selfFile, fix64 ( selfHeader.elfHeaderOffset ), SEEK_SET ); fread ( &elfHeader, sizeof ( Elf64_Ehdr ), 1, selfFile ); fseek ( elfFile, 0, SEEK_SET ); fwrite ( &elfHeader, sizeof ( Elf64_Ehdr ), 1, elfFile );
Section Headers
Elf64_Shdr elfSectionHeaders[100]; fseek ( selfFile, fix64 ( selfHeader.elfSectionHeadersOffset ), SEEK_SET ); fread ( elfSectionHeaders, sizeof ( Elf64_Shdr ), fix16 ( elfHeader.e_shnum ), selfFile ); fseek ( elfFile, fix64 ( elfHeader.e_shoff ), SEEK_SET ); fwrite ( elfSectionHeaders, sizeof ( Elf64_Shdr ), fix16 ( elfHeader.e_shnum ), elfFile );
Section Data
Notes:
- Unknown, manually copying the data over works for now.
- There should be a section data offset somewhere.
Program Headers
Elf64_Phdr elfProgramHeaders[100]; fseek ( selfFile, fix64 ( selfHeader.elfProgramHeadersOffset ), SEEK_SET ); fread ( elfProgramHeaders, sizeof ( Elf64_Phdr ), fix16 ( elfHeader.e_phnum ), selfFile ); fseek ( elfFile, fix64 ( elfHeader.e_phoff ), SEEK_SET ); fwrite ( elfProgramHeaders, sizeof ( Elf64_Phdr ), fix16 ( elfHeader.e_phnum ), elfFile );
Program Data
Notes:
- Load the metadata information and decrypt the key and ivec entries using AES256CBC using erk and riv.
- Load the metadata header and decrypt it using AES128CTR with the key and ivec entries from the metadata information.
- Load sectionCount metadata section headers and decrypt them using AES128CTR with the key and ivec entries from the metadata information.
- Load keyCount metadata keys and decrypt them using AES128CTR with the key and ivec entries from the metadata information.
- For each metadata section:
- In the SELF file, fseek to dataOffset and read in dataSize bytes.
- Decrypt the data using AES128CTR with the key and ivec from the metadata keys specified by keyIndex and ivecIndex from the metadata section header.
- Uncompress the data using zlib.
- Write it to the ELF file as the program section specified by section Index in the metadata section header.