SELF File Format: Difference between revisions

From Vita Developer wiki
Jump to navigation Jump to search
Line 17: Line 17:
Notes:  
Notes:  


* Numbers are stored in little endian format because of ARM endianness (whilst PS3 used big endian because of PowerPC endianness).
* For PSVita SELF, little endian is used because of ARM32 endianness (whilst PS3 used big endian because of PowerPC endianness).
* Encapsulated ELF header fields are useless (only the EI_CLASS EI_DATA and EI_VERSION fields are checked)
* Encapsulated ELF header fields are useless (only the EI_CLASS EI_DATA and EI_VERSION fields are checked)


== Extended Header ==
== Extended Header ==
Extended Header offsets are relative to Certified File start.


=== Struct ===
=== Struct ===
Line 46: Line 48:
| Extended Header version || 0x0 || u64 || ?Version of Extended Header?
| Extended Header version || 0x0 || u64 || ?Version of Extended Header?
|-
|-
| App Info offset || 0x8 || u64 || Offset to AppInfo, (usually 0x80).
| App Info offset || 0x8 || u64 || Offset to App Info, (usually 0x80).
|-
|-
| ELF Header offset || 0x10 || u64 || Offset to ELF header (usually 0xA0).
| ELF Header offset || 0x10 || u64 || Offset to ELF header (usually 0xA0).
Line 61: Line 63:
| Control Info offset || 0x38 || u64 || Several information containers.
| Control Info offset || 0x38 || u64 || Several information containers.
|-
|-
| Control Info size || 0x40 || u64 ||
| Control Info size || 0x40 || u64 ||
|-
|-
| Padding || 0x48 || u64 ||
| Padding || 0x48 || u64 ||
|}
|}


Line 70: Line 72:
=== Struct ===
=== Struct ===


<source lang="C">
  typedef struct {
  typedef struct {
   uint64_t authority_id;         /* authority id */
   uint64_t authority_id;
   uint32_t vendorid;             /* vendor id */
   uint32_t vendor_id;
   uint32_t selftype;             /* SELF type */
   uint32_t self_type;
   uint64_t sceversion;           /* sdk version */
   uint64_t sceversion;
   uint64_t padding;               /* UNKNOWN */
   uint64_t padding;
  } __attribute__((packed)) APP_INFO;
  } __attribute__((packed)) APP_INFO;
</source>


=== Table ===
=== Table ===
Line 85: Line 89:
| authority_id || 0x00 || u64 || [[Authentication_IDs|AuthorityId]] || ex: 21 00 00 10 1C CA 01 30
| authority_id || 0x00 || u64 || [[Authentication_IDs|AuthorityId]] || ex: 21 00 00 10 1C CA 01 30
|-
|-
| vendorid || 0x08 || u32 || [[VendorId]] (strangely always 00 00 00 00) || ex: 00 00 00 00
| vendor_id || 0x08 || u32 || [[VendorId]] (strangely always 00 00 00 00) || ex: 00 00 00 00
|-
|-
| selftype || 0x0C || u32 || [[SELF_File_Format#SELF type|SELF type]] || ex: 08 00 00 00
| self_type || 0x0C || u32 || [[SELF_File_Format#SELF type|SELF type]] || ex: 08 00 00 00
|-
|-
| version || 0x10 || u64 || version || ex: 0x0000036000000000 (3.600.011), 0x0000009450000000 (0.945.040)
| sceversion || 0x10 || u64 || SDK version || ex: 0x0000036000000000 (3.600.011), 0x0000009450000000 (0.945.040)
|-
|-
| padding || 0x18 || u64 || || 00 00 00 00 00 00 00 00
| padding || 0x18 || u64 || Padding || 00 00 00 00 00 00 00 00
|}
|}


Line 114: Line 118:
|}
|}


== ELF Header ==
== ELF Header ==
 
=== Struct ===


===Struct===
<source lang="C">
   typedef struct {
   typedef struct {
     uint8_t e_ident[16];              /* ELF identification */
     uint8_t e_ident[16];              /* ELF identification */
Line 133: Line 139:
     uint16_t e_shstrndx;              /* section name string table index */
     uint16_t e_shstrndx;              /* section name string table index */
   } __attribute__((packed)) ELF;
   } __attribute__((packed)) ELF;
</source>
=== Table ===


===Table===
{| class="wikitable sortable"
{| class="wikitable sortable"
! Name of the variable !! Offset !! Size !! Notes
! Name of the variable !! Offset !! Size !! Notes
Line 173: Line 181:
|-
|-
| e_shstrndx || elf_offset+0x32 ||    2 || unused
| e_shstrndx || elf_offset+0x32 ||    2 || unused
|-
|}
|}


Line 181: Line 187:
<source lang="C">
<source lang="C">
/* SCE-specific definitions for e_type: */
/* SCE-specific definitions for e_type: */
#define ET_SCE_ELF 0x2 /* SCE Executable file */
#define ET_SCE_ELF 0x0002 /* SCE Executable file */
#define ET_SCE_EXEC 0xFE00 /* SCE Executable file */
#define ET_SCE_EXEC 0xFE00 /* SCE Executable file */
#define ET_SCE_RELEXEC 0xFE04 /* SCE Relocatable Executable file */
#define ET_SCE_RELEXEC 0xFE04 /* SCE Relocatable Executable file */
Line 194: Line 200:
[http://www.sco.com/developers/gabi/latest/ch4.eheader.html ELF Header]
[http://www.sco.com/developers/gabi/latest/ch4.eheader.html ELF Header]
[http://www.openwatcom.com/ftp/devel/docs/elf-64-gen.pdf ELF-64 Object File Format]
[http://www.openwatcom.com/ftp/devel/docs/elf-64-gen.pdf ELF-64 Object File Format]
[https://wiki.henkaku.xyz/vita/images/a/a2/Vita_SDK_specifications.pdf yifanlu specs]
== ELF Program Headers ==


== ELF Program Headers  ==
=== Struct ===


===Struct===
<source lang="C">
   typedef struct {
   typedef struct {
     uint32_t p_type;                  /* type of segment */
     uint32_t p_type;                  /* type of segment */
Line 208: Line 217:
     uint64_t p_align;                /* alignment of segment */
     uint64_t p_align;                /* alignment of segment */
   } __attribute__((packed)) ELF_PHDR;
   } __attribute__((packed)) ELF_PHDR;
</source>


===Table===
=== Table ===


===Comments===
=== Comments ===
See Spec here: [http://www.sco.com/developers/gabi/latest/ch5.pheader.html ELF Program Headers]  
See Spec here: [http://www.sco.com/developers/gabi/latest/ch5.pheader.html ELF Program Headers]  


== ELF Section Headers ==
== ELF Section Headers ==


===Struct===
=== Struct ===
 
<source lang="C">
   typedef struct {
   typedef struct {
     uint32_t sh_name;                /* section name */
     uint32_t sh_name;                /* section name */
Line 229: Line 241:
     uint64_t sh_entsize;              /* size of entries, if section has table */
     uint64_t sh_entsize;              /* size of entries, if section has table */
   } __attribute__((packed)) ELF_SHDR;
   } __attribute__((packed)) ELF_SHDR;
</source>


===Table===
=== Table ===


===Comments===
=== Comments ===


== Section Information ==
== Section Information ==
Line 273: Line 286:
== SCE Version Info ==
== SCE Version Info ==


===Struct===
=== Struct ===
 
<source lang="C">
  typedef struct {
  typedef struct {
   uint32_t unknown1; // 0x1
   uint32_t unknown1; // 0x1
Line 280: Line 295:
   uint32_t unknown4;
   uint32_t unknown4;
  } __attribute__((packed)) SCEVERSION_INFO;
  } __attribute__((packed)) SCEVERSION_INFO;
</source>


===Table===
=== Table ===


===Comment===
=== Comment ===


== Control Information ==
== Control Information ==
Line 289: Line 305:
=== Struct ===
=== Struct ===


<source lang="C">
  typedef struct {
  typedef struct {
   uint32_t type; // 4==PSVita ELF digest info; 5==PSVita NPDRM info; 6==PSVita boot param info; 7==PSVita shared secret info
   uint32_t type; // 4==PSVita ELF digest info; 5==PSVita NPDRM info; 6==PSVita boot param info; 7==PSVita shared secret info
Line 330: Line 347:
   };
   };
  } __attribute__((packed)) PSVita_CONTROL_INFO;
  } __attribute__((packed)) PSVita_CONTROL_INFO;
</source>


=== Table ===
=== Table ===

Revision as of 17:26, 23 December 2019


SELF stands for Signed Executable and Linkable Format.

It is the format used by the executables on the PS3 (SCE Header Version 2), PS Vita (SCE Header Version 3).

It consists of an SELF header followed by the encapsulated ELF file. ELF segments can be compressed using gzip.

System and NPDRM SELFs are encrypted and signed and are decrypted on PSVita to memory by F00D.

ELF sections might be encrypted using AES CTR and signed using ECDSA + HMAC-SHA1.

SELF file has a specific header called SCE header where it stores all the parameters for this program.

File Format

Notes:

  • For PSVita SELF, little endian is used because of ARM32 endianness (whilst PS3 used big endian because of PowerPC endianness).
  • Encapsulated ELF header fields are useless (only the EI_CLASS EI_DATA and EI_VERSION fields are checked)

Extended Header

Extended Header offsets are relative to Certified File start.

Struct

 typedef struct { // size is 0x50
   uint64_t ext_hdr_version;
   uint64_t appinfo_offset;
   uint64_t ehdr_offset;
   uint64_t phdr_offset;
   uint64_t shdr_offset;
   uint64_t sectioninfo_offset;
   uint64_t sceversion_offset;
   uint64_t controlinfo_offset;
   uint64_t controlinfo_size;
   uint64_t padding;
 } __attribute__((packed)) ext_hdr_header;

Table

field offset type notes
Extended Header version 0x0 u64 ?Version of Extended Header?
App Info offset 0x8 u64 Offset to App Info, (usually 0x80).
ELF Header offset 0x10 u64 Offset to ELF header (usually 0xA0).
Program Header offset 0x18 u64 Offset to Program Header.
Segments Header offset 0x20 u64 Offset to Segments Header.
Section Info offset 0x28 u64 Offset to Section Info. A table which maps phdr entries to the actual offset/size within the encrypted CF.

Because CF can be compressed, they might not match the values listed within the ELF.

sceversion offset 0x30 u64 Offset to a header which contains some version information, including an offset to the .sceversion section of the encrypted elf.
Control Info offset 0x38 u64 Several information containers.
Control Info size 0x40 u64
Padding 0x48 u64

App Info

Struct

 typedef struct {
   uint64_t authority_id;
   uint32_t vendor_id;
   uint32_t self_type;
   uint64_t sceversion;
   uint64_t padding;
 } __attribute__((packed)) APP_INFO;

Table

field offset type notes example
authority_id 0x00 u64 AuthorityId ex: 21 00 00 10 1C CA 01 30
vendor_id 0x08 u32 VendorId (strangely always 00 00 00 00) ex: 00 00 00 00
self_type 0x0C u32 SELF type ex: 08 00 00 00
sceversion 0x10 u64 SDK version ex: 0x0000036000000000 (3.600.011), 0x0000009450000000 (0.945.040)
padding 0x18 u64 Padding 00 00 00 00 00 00 00 00

Comments

Aligned to 0x10 bytes.

SELF type

value name files
0x7 KERNEL kernel module (.skprx)
0x8 APP NPDRM SELF and SDK fSELF (eboot.bin, .suprx)
0x9 BOOT kernel_boot_loader.self
0xB SECURE SM SELF (os0:sm/*.self and slb2:kprx_auth_sm.self)
0xD USER system userland SELF (.self, eboot.bin, .suprx)

ELF Header

Struct

  typedef struct {
    uint8_t e_ident[16];              /* ELF identification */
    uint16_t e_type;                  /* object file type */
    uint16_t e_machine;               /* machine type */
    uint32_t e_version;               /* object file version */
    uint32_t e_entry;                 /* entry point address */
    uint32_t e_phoff;                 /* program header offset */
    uint32_t e_shoff;                 /* section header offset */
    uint32_t e_flags;                 /* processor-specific flags */
    uint16_t e_ehsize;                /* ELF header size */
    uint16_t e_phentsize;             /* size of program header entry */
    uint16_t e_phnum;                 /* number of program header entries */
    uint16_t e_shentsize;             /* size of section header entry */
    uint16_t e_shnum;                 /* number of section header entries */
    uint16_t e_shstrndx;              /* section name string table index */
  } __attribute__((packed)) ELF;

Table

Name of the variable Offset Size Notes
e_ident[0..3] elf_offset+(0,1,2,3) 4 Magic
e_ident[4] elf_offset+4 1 Class Type must be [ELFCLASS32 = 0x01]
e_ident[5] elf_offset+5 1 Data Type must be [ELFDATA2LSB (i.e. le) = 0x01]
e_ident[6] elf_offset+6 1 File version (must be 0x1)
e_ident[7..15] elf_offset+(6->15) 1 unused
e_type elf_offset+0x10 2 SCE-specific e_type
e_machine elf_offset+0x12 2 Machine type must be [EM_ARM = 0x0028]
e_version elf_offset+0x14 4 elf version (must be 0x00000001)
e_entry elf_offset+0x18 4 Address to jump to in order to start program
e_phoff elf_offset+0x1c 4 boundary checked, but unused (already given by SELF header)
e_shoff elf_offset+0x20 4 unused
e_flags elf_offset+0x24 4 unused
e_ehsize elf_offset+0x28 2 Must be sizeof(Elf32_Ehdr) = 0x0034
e_phentsize elf_offset+0x2a 2 Must be sizeof(Elf32_Phdr) = 0x0020
e_phnum elf_offset+0x2c 2 Count of Program Header in this elf
e_shentsize elf_offset+0x2e 2 unused
e_shnum elf_offset+0x30 2 unused
e_shstrndx elf_offset+0x32 2  unused

SCE-specific e_type

/* SCE-specific definitions for e_type: */
#define ET_SCE_ELF		0x0002		/* SCE Executable file */
#define ET_SCE_EXEC		0xFE00		/* SCE Executable file */
#define ET_SCE_RELEXEC		0xFE04		/* SCE Relocatable Executable file */
#define ET_SCE_STUBLIB		0xFE0C		/* SCE SDK Stubs */
#define ET_SCE_DYNAMIC		0xFE18		/* Unused */
#define ET_SCE_PSPRELEXEC	0xFFA0		/* Unused (PSP ELF only) */
#define ET_SCE_PPURELEXEC	0xFFA4		/* Unused (SPU ELF only) */
#define ET_SCE_UNK		0xFFA5		/* Unknown */

See Specifications here: ELF Header ELF-64 Object File Format yifanlu specs

ELF Program Headers

Struct

  typedef struct {
    uint32_t p_type;                  /* type of segment */
    uint32_t p_flags;                 /* segment attributes */
    uint64_t p_offset;                /* offset in file */
    uint64_t p_vaddr;                 /* virtual address in memory */
    uint64_t p_paddr;                 /* reserved */
    uint64_t p_filesz;                /* size of segment in file */
    uint64_t p_memsz;                 /* size of segment in memory */
    uint64_t p_align;                 /* alignment of segment */
  } __attribute__((packed)) ELF_PHDR;

Table

Comments

See Spec here: ELF Program Headers

ELF Section Headers

Struct

  typedef struct {
    uint32_t sh_name;                 /* section name */
    uint32_t sh_type;                 /* section type */
    uint64_t sh_flags;                /* section attributes */
    uint64_t sh_addr;                 /* virtual address in memory */
    uint64_t sh_offset;               /* offset in file */
    uint64_t sh_size;                 /* size of section */
    uint32_t sh_link;                 /* link to other section */
    uint32_t sh_info;                 /* miscellaneous information */
    uint64_t sh_addralign;            /* address alignment boundary */
    uint64_t sh_entsize;              /* size of entries, if section has table */
  } __attribute__((packed)) ELF_SHDR;

Table

Comments

Section Information

Struct

typedef struct {
   uint64_t offset;
   uint64_t size;
   uint32_t compression;
   uint32_t unk1;
   uint32_t encryption;
   uint32_t unk2;
} __attribute__((packed)) SECTION_INFO;

Table

field offset type notes
Offset 0x00 u64 Offset of data
Size 0x08 u64 Size of data
Compression 0x10 u32 1 = uncompressed, 2 = compressed
unknown 1 0x14 u32
Encryption 0x18 u32 1 = encrypted, 2 = unencrypted
unknown 2 0x1C u32

Comments

There is one of these entries (Section Information) for each phdr entry (Program Header) in the ELF file so that the console knows where to decrypt the data from (because it might also be compressed).

SCE Version Info

Struct

 typedef struct {
   uint32_t unknown1; // 0x1
   uint32_t unknown2;
   uint32_t unknown3; // 0x10 ?size?
   uint32_t unknown4;
 } __attribute__((packed)) SCEVERSION_INFO;

Table

Comment

Control Information

Struct

 typedef struct {
   uint32_t type; // 4==PSVita ELF digest info; 5==PSVita NPDRM info; 6==PSVita boot param info; 7==PSVita shared secret info
   uint32_t size;
   uint64_t next; // 1 if another Control Info structure follows else 0
   
   union {
     // type 4, 0x50 bytes
     struct { // 0x40 bytes of data
       uint8_t constant[0x14]; // same for every PSVita/PS3 SELF, hardcoded in make_fself.exe: 627CB1808AB938E32C8C091708726A579E2586E4
       uint8_t elf_digest[0x20]; // on PSVita: SHA-256 of source ELF file, on PS3: SHA-1
       uint8_t padding[8];
       uint32_t min_required_fw; // ex: 0x363 for 3.63
     } PSVita_elf_digest_info;
     
     // type 5, 0x110 bytes
     struct { // 0x80 bytes of data
       uint32_t magic;               // 7F 44 52 4D (".DRM")
       uint32_t finalized_flag;      // ex: 80 00 00 01
       uint32_t drm_type;            // [[License Types|license_type]] ex: 2 local, 0xD free with license
       uint32_t padding;
       uint8_t content_id[0x30];
       uint8_t digest[0x10];         // ?sha-1 hash of debug self/sprx created using make_fself_npdrm?
       uint8_t padding_78[0x78];
       uint8_t hash_signature[0x38]; // unknown hash/signature
     } PSVita_npdrm_info;
     
     // type 6, 0x110 bytes
     struct { // 0x100 bytes of data
       uint32_t is_used; // 0=false, 1=true
       uint8_t boot_param[0x9C]; // ex: starting with 02 00 00 00
     } PSVita_boot_param_info;
     
     // type 7, 0x50 bytes
     struct { // 0x40 bytes of data
       uint8_t shared_secret_0[0x10]; // ex: 0x7E7FD126A7B9614940607EE1BF9DDF5E or full of zeroes
       uint8_t shared_secret_1[0x10]; // ex: full of zeroes
       uint8_t shared_secret_2[0x10]; // ex: full of zeroes
       uint8_t shared_secret_3[0x10]; // ex: full of zeroes
     } PSVita_shared_secret_info;
   };
 } __attribute__((packed)) PSVita_CONTROL_INFO;

Table

Comments

Relocations

Offset Size Description
0x0 0x4 Relocation Type
0x4 0x4 Long entry: Addend
0x4 0x4 Short entry: 0-19 = Bits 10-29 of offset, 20-31 = addend
0x8 0x4 Long entry: Offset

Relocations can be of two types: 8 byte "short" entries or 12 byte "long" entries. The relocation code is the same as ARM ELF format.


Segment start = Buffer address of segment indexed at "Patch segment"

Symbol start = Buffer address of segment indexed at "Symbol segment"

Address to patch = segment start + offset

P = address to patch

S = "Symbol segment" == 15 ? 0 : symbol start

A = addend

Relocation Type

Start End Description
0 3 Short entry if set
4 7 Symbol segment
8 15 Relocation code
16 19 Patch segment
20 27 Long entry: Optional relocation code 2
28 31 Long entry: Optional distance 2
20 31 Short entry: Lower 12 bits of offset

Supported Relocation Codes (1.69)

Code Description
0 R_ARM_NONE
2 R_ARM_ABS32
3 R_ARM_REL32
10 R_ARM_THM_CALL
28 R_ARM_CALL
29 R_ARM_JUMP24
38 R_ARM_TARGET1 (same as R_ARM_ABS32)
40 R_ARM_V4BX (same as R_ARM_NONE)
41 R_ARM_TARGET2 (same as R_ARM_REL32)
42 R_ARM_PREL31
43 R_ARM_MOVW_ABS_NC
44 R_ARM_MOVT_ABS
47 R_ARM_THM_MOVW_ABS_NC
48 R_ARM_THM_MOVT_ABS