Editing SELF File Format
Jump to navigation
Jump to search
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
Latest revision | Your text | ||
Line 1: | Line 1: | ||
# | [[Category:Software]]<noinclude>[[Category:Main]]</noinclude> | ||
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 = | |||
Notes: | |||
* Numbers are stored in little endian format (whilst PS3 used big endian). | |||
== SELF/SCE Header == | |||
=== Struct === | |||
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; | |||
===Table=== | |||
{| class="wikitable" | |||
|- | |||
! field !! offset !! type !! notes | |||
|- | |||
| magic || 0x0 || u32 || Must be "SCE\0" | |||
|- | |||
| version || 0x4 || u32 || This must be 3 on PSVita | |||
|- | |||
| sdk_type || 0x8 || u16|| This corresponds to the revision of the key to decrypt | |||
|- | |||
| 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_len || 0x10 || u64 || This is the length of the header (including the fake elf headers) | |||
|- | |||
| Encrypted size || 0x18 || u64 || The size of the encrypted part of the self file. | |||
|- | |||
| File size || 0x20 || u64 || The size of the encrypted part of the self file. | |||
|- | |||
| unknown || 0x28 || u64 || Must be 0 | |||
|- | |||
| self_offset || 0x30 || u64 || SELF Offset | |||
|- | |||
| App_info_offset || 0x38 || u64 || An offset in the header, usually at 0x80. See App info header. | |||
|- | |||
| elf_offset || 0x40 || u64 || offset to the elf header | |||
|- | |||
| phdr_offset || 0x48 || u64 || offset to phdr | |||
|- | |||
| shdr_offset || 0x50 || u64 || offset to shdr | |||
|- | |||
| 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 || 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 || | |||
|- | |||
|} | |||
===comments=== | |||
The real ELF data is located after the SCE header (see header size). | |||
== App Info == | |||
===Struct=== | |||
typedef struct { | |||
uint64_t authid; /* auth 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=== | |||
{| class="wikitable" | |||
|- | |||
! field !! offset !! type !! notes | |||
|- | |||
| authid || 0x00 || u64 || [[Authentication_IDs|AuthorityId]] | |||
|- | |||
| vendorid || 0x08 || u32 || [[VendorId]] (strangley always 00 00 00 00) | |||
|- | |||
| selftype || 0x0c || u32 || [[SELF_File_Format#SELF type|SELF type]] | |||
|- | |||
| sceversion || 0x10 || u64 || sce version (ex: 0x0000036000000000 (3.60), 0x0000009450000000 (0.945.040)) | |||
|- | |||
| padding || 0x18 || u64 || | |||
|} | |||
===Comments=== | |||
Aligned to 0x10 bytes. | |||
==== SELF type ==== | |||
{| class="wikitable" | |||
|- | |||
! value !! type | |||
|- | |||
| 0x7 || kernel module (.skprx) | |||
|- | |||
| 0x8 || NPDRM SELF and SDK SELF (eboot.bin, .suprx) | |||
|- | |||
| 0xB || SM SELF (os0:sm/*.self) | |||
|- | |||
| 0xD || system userland SELF (.suprx, eboot.bin, .self) | |||
|} | |||
== 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 */ | |||
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=== | |||
{| class="wikitable sortable" | |||
|- | |||
! Name of the variable !! Offset !! Size !! Notes | |||
|- | |||
| e_ident[0]<br />,e_ident[1]<br />,e_ident[2]<br />,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 || PRX=0xFE00 EXEC=0x0002 | |||
|- | |||
| e_machine || elf_offset+0x12 || 0x2 || seems to be 0x28 as machine type | |||
|- | |||
| e_version || elf_offset+0x14 || 0x4 || elf version | |||
|- | |||
|} | |||
===Comments=== | |||
See Specifications here: | |||
[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] | |||
Notes: | |||
*e_type: ET_PSVPRX=0xFE00 | |||
*e_type: ET_PSVELF=0x0002 | |||
== 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: [http://www.sco.com/developers/gabi/latest/ch5.pheader.html 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=== | |||
== Segment Information == | |||
=== Struct === | |||
typedef struct { | |||
uint64_t offset; | |||
uint64_t size; | |||
uint32_t compressed; // 2=compressed | |||
uint32_t unknown1; | |||
uint32_t encrypted; // 1=encrypted | |||
uint32_t unknown2; | |||
} __attribute__((packed)) SECTION_INFO; | |||
=== Table === | |||
{| class="wikitable" | |||
|- | |||
! field !! offset !! type !! notes | |||
|- | |||
|Encrypted Data Offset || 0x00 || u64 || | |||
|- | |||
|Encrypted Data Size || 0x08 || u64 || | |||
|- | |||
|Compression|| 0x10 || u32 || | |||
|- | |||
|unknown || 0x14 || u32 || | |||
|- | |||
|Encryption|| 0x18 || u32 || | |||
|- | |||
|unknown || 0x1C || u32 || | |||
|- | |||
|} | |||
=== Comments === | |||
There is one of these entries for each phdr entry in the elf file so that the ps3 knows where to decrypt the data from. (because it might also be compressed.) | |||
Notes: | |||
*There is one Segment Information for each ELF Program Header.<br> | |||
== SCE Version Info == | |||
===Struct=== | |||
typedef struct { | |||
uint32_t unknown1; | |||
uint32_t unknown2; | |||
uint32_t unknown3; | |||
uint32_t unknown4; | |||
} __attribute__((packed)) SCEVERSION_INFO; | |||
===Table=== | |||
===Comment=== | |||
== Control Information == | |||
===Struct=== | |||
typedef struct { | |||
uint32_t type; // 4== ; 6==;7== | |||
uint32_t size; | |||
uint64_t unknown; // 0;1 | |||
union { | |||
// type 4 0x50 bytes | |||
struct { | |||
uint8_t digest1[20]; //hash digest, same for every file | |||
uint8_t digest2[20]; //sha1 hash digest calculated of .elf file... | |||
uint8_t digest3[12]; // | |||
uint64_t padding; | |||
} file_digest50; | |||
// type 6 0x110 bytes | |||
struct { | |||
uint32_t unknown1; // 0x00000001 | |||
uint8_t unknown2[252]; | |||
} file_digest110; | |||
// type 7 0x50 bytes | |||
struct { | |||
uint64_t unknown1; | |||
uint64_t unknown2; | |||
uint64_t unknown3; | |||
uint64_t unknown4; | |||
uint64_t unknown5; | |||
uint64_t unknown6; | |||
uint64_t unknown7; | |||
uint64_t unknown8; | |||
} file_digest50_2; | |||
}; | |||
} __attribute__((packed)) CONTROL_INFO; | |||
===Table=== | |||
===Comments=== | |||
== Relocations == | |||
{| class="wikitable" | |||
|- | |||
! 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 === | |||
{| class="wikitable" | |||
|- | |||
! 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) === | |||
{| class="wikitable" | |||
|- | |||
! 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 | |||
|- | |||
|} |