SELF File Format: Difference between revisions
CelesteBlue (talk | contribs) No edit summary |
|||
Line 1: | Line 1: | ||
SELF stands for Signed Executable and Linkable Format. SPRX stands for Signed Playstation Relocatable eXecutable. They are the format used by the executables on the PS3, PS Vita and PS4. PS4 SELF files have a different structure from the PS3/PS Vita ones but contain mostly the same information. See [https://www.psdevwiki.com/ps3/SELF_-_SPRX PS3/PS Vita SELF/SPRX wiki page] and [https://www.psdevwiki.com/ps3/Certified_File PS3/PS Vita Certified File wiki page]. | |||
= SELF Header Structure = | = SELF Header Structure = | ||
Line 10: | Line 10: | ||
| 0x4 || 4 || Unknown || Always 00 01 01 12 | | 0x4 || 4 || Unknown || Always 00 01 01 12 | ||
|- | |- | ||
| 0x8 || 1 || | | 0x8 || 1 || Category || 1 on SELF, 4 on PUP Entry (probably SPP). See [https://www.psdevwiki.com/ps3/Certified_File#Category PS3/PS Vita Category]. | ||
|- | |- | ||
| 0x9 || 1 || [[Program Type]] || | | 0x9 || 1 || [[Program Type]] || | ||
Line 18: | Line 18: | ||
| 0xC || 2 || Header Size || | | 0xC || 2 || Header Size || | ||
|- | |- | ||
| 0xE || 2 || Signature Size || Metadata Size? | | 0xE || 2 || Signature Size || ?Metadata Size? | ||
|- | |- | ||
| 0x10 || 4 || Size of SELF | | 0x10 || 4 || File Size || Size of SELF | ||
|- | |- | ||
| 0x14 || 4 || Padding || | | 0x14 || 4 || Padding || | ||
|- | |- | ||
| 0x18 || 2 || Number of Segments || 1 Kernel, 2 SL and Modules, 4 Kernel ELFs, 6 .selfs, 2 .sdll, 6 .sprx, 6 ShellCore, 6 eboot.bin, 2 sexe | | 0x18 || 2 || Number of Segments || 1 Kernel, 2 SL and Secure Modules, 4 Kernel ELFs, 6 .selfs, 2 .sdll, 6 .sprx, 6 ShellCore, 6 eboot.bin, 2 sexe | ||
|- | |- | ||
| 0x1A || 2 || Unknown || Always 0x22 | | 0x1A || 2 || Unknown || Always 0x22 | ||
|- | |- | ||
| 0x1C || 4 || Padding || | | 0x1C || 4 || Padding || | ||
|} | |} | ||
== SELF Segment Structure == | == SELF Segment Structure == | ||
Depending on the number of segments, at 0x20 the following structure follows and presents a size multiple of 0x20. | Depending on the number of segments, at offset 0x20 the following structure follows and presents a size multiple of 0x20. | ||
<pre> | <pre> | ||
typedef struct | typedef struct { | ||
{ | |||
unsigned long long flags; // 0x130006 / 0x00040F / 0x000006 / 0x110006 | unsigned long long flags; // 0x130006 / 0x00040F / 0x000006 / 0x110006 | ||
unsigned long long offset; | unsigned long long offset; | ||
Line 49: | Line 47: | ||
<pre> | <pre> | ||
enum SegFlags | enum SegFlags { | ||
{ | |||
SF_ORDR = 0x1, // ordered? | SF_ORDR = 0x1, // ordered? | ||
SF_ENCR = 0x2, // encrypted | SF_ENCR = 0x2, // encrypted | ||
Line 62: | Line 59: | ||
<pre> | <pre> | ||
uint32_t Id() | uint32_t Id() { | ||
{ | |||
return Flags >> 20; //0 or 1 | return Flags >> 20; //0 or 1 | ||
} | } | ||
bool IsOrdered() | bool IsOrdered() { | ||
{ | |||
return (Flags & 1) != 0;//0 or 1 | return (Flags & 1) != 0;//0 or 1 | ||
} | } | ||
bool IsEncrypted() | bool IsEncrypted() { | ||
{ | |||
return (Flags & 2) != 0;//0 or 2 | return (Flags & 2) != 0;//0 or 2 | ||
} | } | ||
bool IsSigned() | bool IsSigned() { | ||
{ | |||
return (Flags & 4) != 0;//0 or 4 | return (Flags & 4) != 0;//0 or 4 | ||
} | } | ||
bool IsCompressed() | bool IsCompressed() { | ||
{ | |||
return (Flags & 8) != 0;//0 or 8 | return (Flags & 8) != 0;//0 or 8 | ||
} | } | ||
bool IsBlocked() | bool IsBlocked() { | ||
{ | |||
return (Flags & 0x800) != 0;//0 or 0x800 | return (Flags & 0x800) != 0;//0 or 0x800 | ||
} | } | ||
Line 323: | Line 314: | ||
|} | |} | ||
= | = Program Identification Header = | ||
Program Identification Header is located just before the SELF segments certifications. | |||
{| class="wikitable" | {| class="wikitable" | ||
Line 334: | Line 325: | ||
| 0x8 || 0x8 || [[Program Type]] || | | 0x8 || 0x8 || [[Program Type]] || | ||
|- | |- | ||
| 0x10 || 0x8 || Version | | 0x10 || 0x8 || Program Version || | ||
|- | |- | ||
| 0x18 || 0x8 || Version | | 0x18 || 0x8 || System Software Version || Requested minimum version. | ||
|- | |- | ||
| N.A/0x20 || 0x20 || Content ID || Only exists if the SELF is NPDRM | | N.A/0x20 || 0x20 || Content ID || Only exists if the SELF is protected by NPDRM. | ||
|- | |- | ||
| 0x20/0x40 || 0x20 || Digest || SHA-256 of the decrypted elf (for example, on 7.55 retail decrypted/mmapped elf libc.sprx hash is 67c19a2b053ee386819dcd316d21c4381b35bd3de283ce7ca2e143c86b34f79a) | | 0x20/0x40 || 0x20 || Digest || SHA-256 of the decrypted elf (for example, on 7.55 retail decrypted/mmapped elf libc.sprx hash is 67c19a2b053ee386819dcd316d21c4381b35bd3de283ce7ca2e143c86b34f79a) | ||
|} | |} | ||
= | = Segment Certification = | ||
From leaked 6.00b1 Kernel (containing only one segment) the following information can be deduced: | From leaked decrypted PS4 6.00b1 Kernel (containing only one segment) the following information can be deduced: | ||
{| class="wikitable" | {| class="wikitable" | ||
! Offset !! Size !! Description !! Notes | ! Offset !! Size !! Description !! Notes | ||
|- | |- | ||
| 0 || 0x10 || AES Key || | | 0 || 0x10 || AES Key || AES128CBC Key for Segment 1 | ||
|- | |- | ||
| 0x10 || 0x10 || AES IV || | | 0x10 || 0x10 || AES IV || AES128CBC IV for Segment 1 | ||
|- | |- | ||
| 0x20 || 0x20 || | | 0x20 || 0x20 || HMAC Hash || SHA256HMAC Hash for Segment 1 (decrypted but compressed in this case) (without extra at footer) | ||
|- | |- | ||
| 0x40 || 0x10 || HMAC Key || SHA256HMAC Key for Segment 1 | | 0x40 || 0x10 || HMAC Key || SHA256HMAC Key for Segment 1 | ||
Line 360: | Line 351: | ||
| 0x50 || 0x40 || License + BMP Header || ??? | | 0x50 || 0x40 || License + BMP Header || ??? | ||
|- | |- | ||
| 0x90 || 0x20 || BMP Entries || 2 (0x10) Entries ( | | 0x90 || 0x20 || BMP Entries || 2 (0x10) Entries (first entry is NULL) | ||
|- | |- | ||
| 0xB0 || 0x100 || RSA Signature || RSA Signature of the Segment Certification | |||
|} | |} | ||
= Footer Signature ( | = Footer Signature = | ||
Additionally, at the bottom of a SELF, there is likely a footer RSA signature as well as some extra data (relative size). | |||
= Tools = | |||
== Official tools == | |||
To document. | |||
== Unofficial tools == | |||
=== SELF Decrypter on PS4 === | |||
[https://github.com/AlexAltea/orbital/blob/master/tools/dumper/source/self_decrypter.c PS4 SELF Decrypter on PS4 by AlexAltea] | |||
As PS4 SELF decryption keys are not publicly known, to decrypt SELFs, one can use his PS4 as a blackbox. There are some conditions: the SELF must have valid signatures, it must have a required FW version lower than the FW version of the PS4 being used, and for System SELFs the SELF key_revision must be according to the PS4 FW version. There are exceptions like in first PS4 firmwares where some SELF checks were missing and allowed to decrypt SELFs that did not meet such requirements. | |||
=== make_fself by flatz === | |||
To document. | |||
=== SELF backport tools === | |||
To document. | |||
{{File Formats}} | {{File Formats}} | ||
<noinclude>[[Category:Main]]</noinclude> | <noinclude>[[Category:Main]]</noinclude> |
Revision as of 05:42, 19 February 2022
SELF stands for Signed Executable and Linkable Format. SPRX stands for Signed Playstation Relocatable eXecutable. They are the format used by the executables on the PS3, PS Vita and PS4. PS4 SELF files have a different structure from the PS3/PS Vita ones but contain mostly the same information. See PS3/PS Vita SELF/SPRX wiki page and PS3/PS Vita Certified File wiki page.
SELF Header Structure
Offset | Size | Description | Notes |
---|---|---|---|
0 | 4 | Magic | 4F 15 3D 1D |
0x4 | 4 | Unknown | Always 00 01 01 12 |
0x8 | 1 | Category | 1 on SELF, 4 on PUP Entry (probably SPP). See PS3/PS Vita Category. |
0x9 | 1 | Program Type | |
0xA | 2 | Padding | |
0xC | 2 | Header Size | |
0xE | 2 | Signature Size | ?Metadata Size? |
0x10 | 4 | File Size | Size of SELF |
0x14 | 4 | Padding | |
0x18 | 2 | Number of Segments | 1 Kernel, 2 SL and Secure Modules, 4 Kernel ELFs, 6 .selfs, 2 .sdll, 6 .sprx, 6 ShellCore, 6 eboot.bin, 2 sexe |
0x1A | 2 | Unknown | Always 0x22 |
0x1C | 4 | Padding |
SELF Segment Structure
Depending on the number of segments, at offset 0x20 the following structure follows and presents a size multiple of 0x20.
typedef struct { unsigned long long flags; // 0x130006 / 0x00040F / 0x000006 / 0x110006 unsigned long long offset; unsigned long long encrypted_compressed_size; unsigned long long decrypted_decompressed_size; } SEGMENT_TABLE;
Flags ID
enum SegFlags { SF_ORDR = 0x1, // ordered? SF_ENCR = 0x2, // encrypted SF_SIGN = 0x4, // signed SF_DFLG = 0x8, // deflated SF_BFLG = 0x800, // block segment };
Flags Maths
uint32_t Id() { return Flags >> 20; //0 or 1 } bool IsOrdered() { return (Flags & 1) != 0;//0 or 1 } bool IsEncrypted() { return (Flags & 2) != 0;//0 or 2 } bool IsSigned() { return (Flags & 4) != 0;//0 or 4 } bool IsCompressed() { return (Flags & 8) != 0;//0 or 8 } bool IsBlocked() { return (Flags & 0x800) != 0;//0 or 0x800 }
ELF Segment Structure
After this, follows the ELF Header:
Offset | Size (bytes) | Field | Purpose | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
32-bit | 64-bit | 32-bit | 64-bit | ||||||||||||||||||||||||||||||||||||||
0x00 | 4 | e_ident[EI_MAG0] through e_ident[EI_MAG3] | 0x7F followed by ELF ( ) in ASCII; these four bytes constitute the magic number.
| ||||||||||||||||||||||||||||||||||||||
0x04 | 1 | e_ident[EI_CLASS] | This byte is set to either 1 or 2 to signify 32- or 64-bit format, respectively.
| ||||||||||||||||||||||||||||||||||||||
0x05 | 1 | e_ident[EI_DATA] | This byte is set to either 1 or 2 to signify little or big endianness, respectively. This affects interpretation of multi-byte fields starting with offset 0x10 .
| ||||||||||||||||||||||||||||||||||||||
0x06 | 1 | e_ident[EI_VERSION] | Set to 1 for the original version of ELF.
| ||||||||||||||||||||||||||||||||||||||
0x07 | 1 | e_ident[EI_OSABI] | Identifies the target operating system ABI.
It is often set to | ||||||||||||||||||||||||||||||||||||||
0x08 | 1 | e_ident[EI_ABIVERSION] | Further specifies the ABI version. Its interpretation depends on the target ABI. Linux kernel (after at least 2.6) has no definition of it. In that case, offset and size of EI_PAD are 8 .
| ||||||||||||||||||||||||||||||||||||||
0x09 | 7 | e_ident[EI_PAD] | currently unused | ||||||||||||||||||||||||||||||||||||||
0x10 | 2 | e_type | Identifies object file type.
| ||||||||||||||||||||||||||||||||||||||
0x12 | 2 | e_machine | Specifies target instruction set architecture. Some examples are:
| ||||||||||||||||||||||||||||||||||||||
0x14 | 4 | e_version | Set to 1 for the original version of ELF.
| ||||||||||||||||||||||||||||||||||||||
0x18 | 4 | 8 | e_entry | This is the memory address of the entry point from where the process starts executing. This field is either 32 or 64 bits long depending on the format defined earlier. | |||||||||||||||||||||||||||||||||||||
0x1C | 0x20 | 4 | 8 | e_phoff | Points to the start of the program header table. It usually follows the file header immediately, making the offset 0x34 or 0x40 for 32- and 64-bit ELF executables, respectively.
| ||||||||||||||||||||||||||||||||||||
0x20 | 0x28 | 4 | 8 | e_shoff | Points to the start of the section header table. | ||||||||||||||||||||||||||||||||||||
0x24 | 0x30 | 4 | e_flags | Interpretation of this field depends on the target architecture. | |||||||||||||||||||||||||||||||||||||
0x28 | 0x34 | 2 | e_ehsize | Contains the size of this header, normally 64 Bytes for 64-bit and 52 Bytes for 32-bit format. | |||||||||||||||||||||||||||||||||||||
0x2A | 0x36 | 2 | e_phentsize | Contains the size of a program header table entry. | |||||||||||||||||||||||||||||||||||||
0x2C | 0x38 | 2 | e_phnum | Contains the number of entries in the program header table. | |||||||||||||||||||||||||||||||||||||
0x2E | 0x3A | 2 | e_shentsize | Contains the size of a section header table entry. | |||||||||||||||||||||||||||||||||||||
0x30 | 0x3C | 2 | e_shnum | Contains the number of entries in the section header table. | |||||||||||||||||||||||||||||||||||||
0x32 | 0x3E | 2 | e_shstrndx | Contains index of the section header table entry that contains the section names. |
Followed by the program header
Offset | Size (bytes) | Field | Purpose | |||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
32-bit | 64-bit | 32-bit | 64-bit | |||||||||||||||||||||||||||||||||||
0x00 | 4 | p_type | Identifies the type of the segment.
PT_LOOS to PT_HIOS (PT_LOPROC to PT_HIPROC) is an inclusive reserved ranges for operating system (processor) specific semantics. | |||||||||||||||||||||||||||||||||||
0x04 | 4 | p_flags | Segment-dependent flags (position for 64-bit structure). | |||||||||||||||||||||||||||||||||||
0x04 | 0x08 | 4 | 8 | p_offset | Offset of the segment in the file image. | |||||||||||||||||||||||||||||||||
0x08 | 0x10 | 4 | 8 | p_vaddr | Virtual address of the segment in memory. | |||||||||||||||||||||||||||||||||
0x0C | 0x18 | 4 | 8 | p_paddr | On systems where physical address is relevant, reserved for segment's physical address. | |||||||||||||||||||||||||||||||||
0x10 | 0x20 | 4 | 8 | p_filesz | Size in bytes of the segment in the file image. May be 0. | |||||||||||||||||||||||||||||||||
0x14 | 0x28 | 4 | 8 | p_memsz | Size in bytes of the segment in memory. May be 0. | |||||||||||||||||||||||||||||||||
0x18 | 4 | p_flags | Segment-dependent flags (position for 32-bit structure). | |||||||||||||||||||||||||||||||||||
0x1C | 0x30 | 4 | 8 | p_align | 0 and 1 specify no alignment. Otherwise should be a positive, integral power of 2, with p_vaddr equating p_offset modulus p_align.
| |||||||||||||||||||||||||||||||||
0x20 | 0x38 | End of Program Header (size) |
Program Identification Header
Program Identification Header is located just before the SELF segments certifications.
Offset | Size | Description | Notes |
---|---|---|---|
0 | 0x8 | Program Authority ID | |
0x8 | 0x8 | Program Type | |
0x10 | 0x8 | Program Version | |
0x18 | 0x8 | System Software Version | Requested minimum version. |
N.A/0x20 | 0x20 | Content ID | Only exists if the SELF is protected by NPDRM. |
0x20/0x40 | 0x20 | Digest | SHA-256 of the decrypted elf (for example, on 7.55 retail decrypted/mmapped elf libc.sprx hash is 67c19a2b053ee386819dcd316d21c4381b35bd3de283ce7ca2e143c86b34f79a) |
Segment Certification
From leaked decrypted PS4 6.00b1 Kernel (containing only one segment) the following information can be deduced:
Offset | Size | Description | Notes |
---|---|---|---|
0 | 0x10 | AES Key | AES128CBC Key for Segment 1 |
0x10 | 0x10 | AES IV | AES128CBC IV for Segment 1 |
0x20 | 0x20 | HMAC Hash | SHA256HMAC Hash for Segment 1 (decrypted but compressed in this case) (without extra at footer) |
0x40 | 0x10 | HMAC Key | SHA256HMAC Key for Segment 1 |
0x50 | 0x40 | License + BMP Header | ??? |
0x90 | 0x20 | BMP Entries | 2 (0x10) Entries (first entry is NULL) |
0xB0 | 0x100 | RSA Signature | RSA Signature of the Segment Certification |
Additionally, at the bottom of a SELF, there is likely a footer RSA signature as well as some extra data (relative size).
Tools
Official tools
To document.
Unofficial tools
SELF Decrypter on PS4
PS4 SELF Decrypter on PS4 by AlexAltea
As PS4 SELF decryption keys are not publicly known, to decrypt SELFs, one can use his PS4 as a blackbox. There are some conditions: the SELF must have valid signatures, it must have a required FW version lower than the FW version of the PS4 being used, and for System SELFs the SELF key_revision must be according to the PS4 FW version. There are exceptions like in first PS4 firmwares where some SELF checks were missing and allowed to decrypt SELFs that did not meet such requirements.
make_fself by flatz
To document.
SELF backport tools
To document.