SELF File Format

From PS4 Developer wiki
Revision as of 05:42, 19 February 2022 by CelesteBlue (talk | contribs)
Jump to navigation Jump to search

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:

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(45 4c 46) 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.
Value ABI
0x00 System V
0x01 HP-UX
0x02 NetBSD
0x03 Linux
0x04 GNU Hurd
0x06 Solaris
0x07 AIX
0x08 IRIX
0x09 FreeBSD
0x0A Tru64
0x0B Novell Modesto
0x0C OpenBSD
0x0D OpenVMS
0x0E NonStop Kernel
0x0F AROS
0x10 Fenix OS
0x11 CloudABI

It is often set to 0 regardless of the target platform.

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.
Value Type
0x00 ET_NONE
0x01 ET_REL
0x02 ET_EXEC
0x03 ET_DYN
0x04 ET_CORE
0xfe00 ET_LOOS
0xfeff ET_HIOS
0xff00 ET_LOPROC
0xffff ET_HIPROC
0x12 2 e_machine Specifies target instruction set architecture. Some examples are:
Value ISA
0x00 No specific instruction set
0x02 SPARC
0x03 x86
0x08 MIPS
0x14 PowerPC
0x16 S390
0x28 ARM
0x2A SuperH
0x32 IA-64
0x3E x86-64
0xB7 AArch64
0xF3 RISC-V
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

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.
Value Name Meaning
0x00000000 PT_NULL Program header table entry unused
0x00000001 PT_LOAD Loadable segment
0x00000002 PT_DYNAMIC Dynamic linking information
0x00000003 PT_INTERP Interpreter information
0x00000004 PT_NOTE Auxiliary information
0x00000005 PT_SHLIB reserved
0x00000006 PT_PHDR segment containing program header table itself
0x60000000 PT_LOOS see below
0x6FFFFFFF PT_HIOS
0x70000000 PT_LOPROC
0x7FFFFFFF PT_HIPROC

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

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

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.