SELF File Format

From Vita Dev Wiki
Jump to: navigation, search


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 ELF + SELF header. 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[edit]

Notes:

  • Numbers are stored in little endian format (whilst PS3 used big endian).

SELF/SCE Header[edit]

Struct[edit]

typedef struct {
  uint32_t magic;                 /* 53434500 = SCE\0 */
  uint32_t version;               /* header version 3*/
  uint16_t sdk_type;              /* */
  uint16_t header_type;           /* 1 self, 2 unknown, 3 pkg */
  uint32_t metadata_offset;       /* metadata offset */
  uint64_t header_len;            /* self header length */
  uint64_t elf_filesize;          /* ELF file length */
  uint64_t self_filesize;         /* SELF file length */
  uint64_t unknown;               /* UNKNOWN */
  uint64_t self_offset;           /* SELF offset */
  uint64_t appinfo_offset;        /* app info offset */
  uint64_t elf_offset;            /* ELF #1 offset */
  uint64_t phdr_offset;           /* program header offset */
  uint64_t shdr_offset;           /* section header offset */
  uint64_t section_info_offset;   /* section info offset */
  uint64_t sceversion_offset;     /* version offset */
  uint64_t controlinfo_offset;    /* control info offset */
  uint64_t controlinfo_size;      /* control info size */
  uint64_t padding;               
} __attribute__((packed)) SELF_header;

Table[edit]

field offset type notes
Magic 0x0 u32 Must be "SCE\0".
Version 0x4 u32 Must be 3 on PSVita.
SDK type 0x8 u16 Corresponds to the revision of the decryption key.
Header type 0xA u16 1 self, 2 rvk, 3 pkg, 4 spp
Metadata offset 0xC u32 Offset to the checksums. Must be at least 20 bytes before the end of the header.
Header length 0x10 u64 Length of the header (including the fake ELF header) (usually 0x100).
Encrypted size 0x18 u64 Size of the encrypted part of the SELF file.
File size 0x20 u64 Size of the SELF file.
unknown 0x28 u64 Must be 0.
SELF offset 0x30 u64 Offset to the SELF (usually 0x4).
App Info offset 0x38 u64 Offset to AppInfo, (usually 0x80). See App info struct.
ELF offset 0x40 u64 Offset to the fake ELF header (usually 0xA0).
Program header offset 0x48 u64 Offset to Program Header.
Segments header offset 0x50 u64 Offset to Segments Header.
encrypted phdr sizes/offsets table offset 0x58 u64 Offset to a table which maps phdr entries to the actual offset/size within the encrypted fself.

Because fselfs can be compressed, they might not match the values listed within the elf.

sceversion header offset 0x60 u64 Offset to a header which contains some version information, including an offset to the .sceversion section of the encrypted elf.
Control Information 0x68 u64 Several information containers.
Control Information Size 0x70 u64

App Info[edit]

Struct[edit]

typedef struct {
  uint64_t authority_id;          /* authority id */
  uint32_t vendorid;              /* vendor id */
  uint32_t selftype;              /* SELF type */
  uint64_t sceversion;            /* sdk version */
  uint64_t padding;               /* UNKNOWN */
} __attribute__((packed)) APP_INFO;

Table[edit]

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

Comments[edit]

Aligned to 0x10 bytes.

SELF type[edit]

value type
0x7 kernel module (.skprx)
0x8 NPDRM SELF and SDK fSELF (eboot.bin, .suprx)
0xB SM SELF (os0:sm/*.self)
0xD system userland SELF (.self, eboot.bin, .suprx)

ELF Header[edit]

Struct[edit]

 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 */
   uint64_t e_entry;                 /* entry point address */
   uint64_t e_phoff;                 /* program header offset */
   uint64_t e_shoff;                 /* section header offset */
   uint16_t e_flags;                 /* processor-specific flags */
   uint32_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[edit]

Name of the variable Offset Size Notes
e_ident[0]
,e_ident[1]
,e_ident[2]
,e_ident[3]
elf_offset+(0,1,2,3) 0x4 Magic
e_ident[4] elf_offset+4 0x1 Class Type [ELFCLASS32 = 1][ELFCLASS64 = 2]
e_ident[5] elf_offset+5 0x1 Data Type [ELFDATA2LSB (i.e. le) = 1][ELFDATA2MSB (i.e. be) = 2]
e_ident[6]->e_ident[15] elf_offset+(6->15) 0x1 they are all zeros
e_type elf_offset+0x10 0x2 SCE-specific e_type
e_machine elf_offset+0x12 0x2 seems to be 0x28 as machine type
e_version elf_offset+0x14 0x4 elf version

SCE-specific e_type[edit]

/* SCE-specific definitions for e_type: */
#define ET_SCE_ELF		0x2		/* 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

ELF Program Headers[edit]

Struct[edit]

 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[edit]

Comments[edit]

See Spec here: ELF Program Headers

ELF Section Headers[edit]

Struct[edit]

 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[edit]

Comments[edit]

Segment Information[edit]

Struct[edit]

typedef struct {
  uint64_t offset;
  uint64_t size;
  uint32_t compressed;
  uint32_t unknown1;
  uint32_t encrypted;
  uint32_t unknown2;
} __attribute__((packed)) SECTION_INFO;

Table[edit]

field offset type notes
Encrypted Data Offset 0x00 u64
Encrypted Data Size 0x08 u64
Compression 0x10 u32 1 = uncompressed, 2 = compressed
unknown1 0x14 u32
Encryption 0x18 u32 1 = encrypted, 2 = unencrypted
unknown2 0x1C u32

Comments[edit]

There is one of these entries (Segment 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[edit]

Struct[edit]

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

Table[edit]

Comment[edit]

Control Information[edit]

Struct[edit]

typedef struct {
  uint32_t type; // 4==PSVita control flags; 5==PSVita NPDRM; 6==PSVita unk6; 7==PSVita unk7
  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 digest1[0x14]; // hash digest, same for every file
      uint8_t digest2[0x20]; // unknown hash (maybe elf)
      uint8_t padding[0xC];
    } PSVita_file_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_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 with 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 unknown1; // 0x1
      uint8_t unknown2[0x9C];
    } PSVita_control_type_6;
    // type 7, 0x50 bytes
    struct { // 0x40 bytes of data
      uint8_t unk[0x40];
    } PSVita_control_type_7;
  };
} __attribute__((packed)) PSVita_CONTROL_INFO;

Table[edit]

Comments[edit]

Relocations[edit]

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[edit]

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)[edit]

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