SELF - SPRX
Jump to navigation
Jump to search
Source: http://ps3wiki.lan.st/index.php?title=SELF_File_Format_and_Decryption
File Format
Notes:
- Numbers are stored in big endian format.
SELF/SCE 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.