From e4034e6a3959425019351bf34077c9b6563e479d Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Tue, 25 Feb 2020 16:15:37 +0100 Subject: [PATCH] SELF: More boilerplate code --- .../FileFormatReaders/FSELFReader.cs | 84 ------------- .../FileFormatReaders/FormatLayouts/Elf.cs | 3 + .../FileFormatReaders/FormatLayouts/FSELF.cs | 83 ------------- .../FileFormatReaders/FormatLayouts/SElf.cs | 117 ++++++++++++++++++ .../FileFormatReaders/SElfReader.cs | 108 ++++++++++++++++ 5 files changed, 228 insertions(+), 167 deletions(-) delete mode 100644 Il2CppInspector.Common/FileFormatReaders/FSELFReader.cs delete mode 100644 Il2CppInspector.Common/FileFormatReaders/FormatLayouts/FSELF.cs create mode 100644 Il2CppInspector.Common/FileFormatReaders/FormatLayouts/SElf.cs create mode 100644 Il2CppInspector.Common/FileFormatReaders/SElfReader.cs diff --git a/Il2CppInspector.Common/FileFormatReaders/FSELFReader.cs b/Il2CppInspector.Common/FileFormatReaders/FSELFReader.cs deleted file mode 100644 index 96a972a..0000000 --- a/Il2CppInspector.Common/FileFormatReaders/FSELFReader.cs +++ /dev/null @@ -1,84 +0,0 @@ -/* - Copyright 2020 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com - - All rights reserved. -*/ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; - -namespace Il2CppInspector -{ - // Sony PlayStation 4 fake signed ELF reader - // Not compatible with PlayStation 3, PSP or Vita - // References: - // http://hitmen.c02.at/files/yapspd/psp_doc/chap26.html - // https://www.psdevwiki.com/ps3/SELF_-_SPRX#File_Format - // https://www.psdevwiki.com/ps4/SELF_File_Format - // https://www.psxhax.com/threads/ps4-self-spkg-file-format-documentation-detailed-for-scene-devs.6636/ - // https://wiki.henkaku.xyz/vita/images/a/a2/Vita_SDK_specifications.pdf - internal class FSELFReader : FileFormatReader - { - public FSELFReader(Stream stream) : base(stream) { } - - public override string Format => "FSELF"; - - public override string Arch => "x64"; - - public override int Bits => 64; - - protected override bool Init() { - var fselfHeader = ReadObject(); - - // Check for magic bytes - if ((FSELFConsts) fselfHeader.Magic != FSELFConsts.Magic) - return false; - - if ((FSELFConsts) fselfHeader.Unk4 != FSELFConsts.Unk4) - return false; - - // Read segments - var segments = ReadArray(fselfHeader.NumberOfSegments); - - // Read ELF header - // PS4 files as follows: - // m_arch = 0x2 (64-bit) - // m_endian = 0x1 (little endian) - // m_version = 0x1 (ELF version 1) - // m_osabi = 0x9 (FreeBSD) - // e_type = special type, see psdevwiki documentation; probably 0xFE10 or 0xFE18 - // e_machine = 0x3E (x86-64) - var startOfElf = Position; - var elfHeader = ReadObject>(); - - // There are no sections, but read all the program headers - var program_header_table = ReadArray(startOfElf + (long) elfHeader.e_phoff, elfHeader.e_phnum); - - // Read the special section - var sceSpecial = ReadObject(); - - // TODO: Implement the rest of FSELF - // TODO: Set GlobalOffset - - throw new NotImplementedException("Il2CppInspector does not have PRX support yet"); - - return true; - } - - public override Dictionary GetSymbolTable() { - throw new NotImplementedException(); - } - - public override uint[] GetFunctionTable() { - throw new NotImplementedException(); - } - - public override uint MapVATR(ulong uiAddr) { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/Elf.cs b/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/Elf.cs index b9fe70b..b232d8c 100644 --- a/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/Elf.cs +++ b/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/Elf.cs @@ -26,6 +26,9 @@ namespace Il2CppInspector ELFCLASS32 = 1, ELFCLASS64 = 2, + // elf_header.e_Type + ET_EXEC = 2, + // PHTs PT_DYNAMIC = 2, DT_PLTGOT = 3, diff --git a/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/FSELF.cs b/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/FSELF.cs deleted file mode 100644 index 13c2fb1..0000000 --- a/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/FSELF.cs +++ /dev/null @@ -1,83 +0,0 @@ -/* - Copyright 2020 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com - - All rights reserved. -*/ - -using System; -using NoisyCowStudios.Bin2Object; - -namespace Il2CppInspector -{ - internal enum FSELFConsts : uint - { - Magic = 0x1D3D154F, - Unk4 = 0x12010100 - } - - [Flags] - internal enum FSELFSegmentFlags - { - Ordered = 0x1, - Encrypted = 0x2, - Signed = 0x4, - Deflated = 0x8, - Blocked = 0x800 - } - - // SCE-specific definitions for e_type - internal enum FSELFTypes : ushort - { - ET_SCE_EXEC = 0xFE00, - ET_SCE_RELEXEC = 0xFE04, - ET_SCE_STUBLIB = 0xFE0C, - ET_SCE_DYNEXEC = 0xFE10, // SCE EXEC_ASLR (PS4 Executable with ASLR) - ET_SCE_DYNAMIC = 0xFE18, - ET_SCE_IOPRELEXEC = 0xFF80, - ET_SCE_IOPRELEXEC2 = 0xFF81, - ET_SCE_EERELEXEC = 0xFF90, - ET_SCE_EERELEXEC2 = 0xFF91, - ET_SCE_PSPRELEXEC = 0xFFA0, - ET_SCE_PPURELEXEC = 0xFFA4, - ET_SCE_ARMRELEXEC = 0xFFA5, - ET_SCE_PSPOVERLAY = 0xFFA8 - } - -#pragma warning disable CS0649 - internal class FSELFHeader - { - public uint Magic; - public uint Unk4; - public byte ContentType; - public byte ProductType; - public ushort Padding1; - public ushort HeaderSize; - public ushort MetadataSize; - public uint SELFSize; - public uint Padding2; - public ushort NumberOfSegments; - public ushort Unk2; - public uint Padding3; - } - - internal class FSELFSegment - { - public ulong Flags; - public ulong FileOffset; - public ulong EncryptedCompressedSize; - public ulong MemorySize; - } - - internal class FSELFSCE - { - public ulong AuthID; - public ulong ProductType; - public ulong Version_1; - public ulong Version_2; - [ArrayLength(FixedSize = 0x20)] - public byte[] ContentID; // Only if NPDRM - [ArrayLength(FixedSize = 0x20)] - public byte[] SHA256Sum; - } -#pragma warning restore CS0649 -} diff --git a/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/SElf.cs b/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/SElf.cs new file mode 100644 index 0000000..733eddb --- /dev/null +++ b/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/SElf.cs @@ -0,0 +1,117 @@ +/* + Copyright 2020 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com + + All rights reserved. +*/ + +using System; +using NoisyCowStudios.Bin2Object; + +namespace Il2CppInspector +{ + internal enum SElfConsts : uint + { + Magic = 0x1D3D154F + } + + [Flags] + internal enum SElfEntryFlags : ulong + { + Ordered = 0x1, + Encrypted = 0x2, + Signed = 0x4, + Deflated = 0x8, + WindowMask = 0x700, + Blocks = 0x800, + BlockSizeMask = 0xF000, + Digests = 0x10000, + Extents = 0x20000, + SegmentIndexMask = 0x_000F_FFF0_0000 + } + + // SCE-specific definitions for e_type + internal enum SElfETypes : ushort + { + ET_SCE_EXEC = 0xFE00, + ET_SCE_RELEXEC = 0xFE04, + ET_SCE_STUBLIB = 0xFE0C, + ET_SCE_DYNEXEC = 0xFE10, // SCE EXEC_ASLR (PS4 Executable with ASLR) + ET_SCE_DYNAMIC = 0xFE18, + ET_SCE_IOPRELEXEC = 0xFF80, + ET_SCE_IOPRELEXEC2 = 0xFF81, + ET_SCE_EERELEXEC = 0xFF90, + ET_SCE_EERELEXEC2 = 0xFF91, + ET_SCE_PSPRELEXEC = 0xFFA0, + ET_SCE_PPURELEXEC = 0xFFA4, + ET_SCE_ARMRELEXEC = 0xFFA5, + ET_SCE_PSPOVERLAY = 0xFFA8 + } + + // SCE-specific definitions for program header type + internal enum SElfPTypes : uint + { + PT_SCE_RELA = 0x60000000, + PT_SCE_DYNLIBDATA = 0x61000000, + PT_SCE_PROCPARAM = 0x61000001, + PT_SCE_MODULE_PARAM = 0x61000002, + PT_SCE_RELRO = 0x61000010, + PT_SCE_COMMENT = 0x6FFFFF00, + PT_SCE_VERSION = 0x6FFFFF01 + } + + // Extended info types + internal enum SElfExInfoTypes + { + PTYPE_FAKE = 0x1, + PTYPE_NPDRM_EXEC = 0x4, + PTYPE_NPDRM_DYNLIB = 0x5, + PTYPE_SYSTEM_EXEC = 0x8, + PTYPE_SYSTEM_DYNLIB = 0x9, + PTYPE_HOST_KERNEL = 0xC, + PTYPE_SECURE_MODULE = 0xE, + PTYPE_SECURE_KERNEL = 0xF + } + +#pragma warning disable CS0649 + internal class SElfHeader + { + public uint Magic; + public byte Version; + public byte Mode; + public byte Endian; + public byte Attributes; + public uint KeyType; + public ushort HeaderSize; + public ushort MetadataSize; + public ulong FileSize; + public ushort NumberOfEntries; + public ushort Flags; + public uint Padding; + } + + internal class SElfEntry + { + public ulong Flags; + public ulong FileOffset; + public ulong EncryptedCompressedSize; + public ulong MemorySize; + + public bool IsEncrypted => (Flags & (ulong) SElfEntryFlags.Encrypted) != 0; + public bool IsDeflated => (Flags & (ulong) SElfEntryFlags.Deflated) != 0; + public bool HasBlocks => (Flags & (ulong) SElfEntryFlags.Blocks) != 0; + public ushort SegmentIndex => (ushort) ((Flags & (ulong) SElfEntryFlags.SegmentIndexMask) >> 20); + } + + internal class SElfSCEData + { + public ulong ProductAuthID; + public ulong ProductType; + public ulong AppVersion; + public ulong FirmwareVersion; + [ArrayLength(FixedSize = 0x20)] + public byte[] ContentID; // Only if NPDRM + [ArrayLength(FixedSize = 0x20)] + public byte[] SHA256Digest; + } +#pragma warning restore CS0649 +} diff --git a/Il2CppInspector.Common/FileFormatReaders/SElfReader.cs b/Il2CppInspector.Common/FileFormatReaders/SElfReader.cs new file mode 100644 index 0000000..b7b1cf8 --- /dev/null +++ b/Il2CppInspector.Common/FileFormatReaders/SElfReader.cs @@ -0,0 +1,108 @@ +/* + Copyright 2020 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com + + All rights reserved. +*/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using NoisyCowStudios.Bin2Object; + +namespace Il2CppInspector +{ + // Sony PlayStation 4 fake signed ELF reader + // Not compatible with PlayStation 3, PSP or Vita + // References: + // http://hitmen.c02.at/files/yapspd/psp_doc/chap26.html + // https://www.psdevwiki.com/ps3/SELF_-_SPRX#File_Format + // https://www.psdevwiki.com/ps4/SELF_File_Format + // https://www.psxhax.com/threads/ps4-self-spkg-file-format-documentation-detailed-for-scene-devs.6636/ + // https://wiki.henkaku.xyz/vita/images/a/a2/Vita_SDK_specifications.pdf + // https://www.psxhax.com/threads/make-fself-gui-for-flat_zs-make_fself-py-script-by-cfwprophet.3494/ + internal class SElfReader : FileFormatReader + { + public SElfReader(Stream stream) : base(stream) { } + + public override string Format => sceData.ProductType == (ulong) SElfExInfoTypes.PTYPE_FAKE? "FSELF" : "SELF"; + + public override string Arch => "x64"; + + public override int Bits => 64; + + private SElfHeader selfHeader; + private SElfEntry[] entries; + private SElfSCEData sceData; + private elf_header elfHeader; + private elf_64_phdr[] pht; + private elf_64_phdr getProgramHeader(Elf programIndex) => pht.FirstOrDefault(x => x.p_type == (uint) programIndex); + + protected override bool Init() { + selfHeader = ReadObject(); + + // Check for magic bytes + if ((SElfConsts) selfHeader.Magic != SElfConsts.Magic) + return false; + + if (selfHeader.Endian != 0x1) + Endianness = Endianness.Big; + + // Read entries + entries = ReadArray(selfHeader.NumberOfEntries); + + // We can't deal with encrypted or compressed segments right now + if (entries.Any(e => e.HasBlocks && e.IsEncrypted)) + throw new NotImplementedException("This file contains encrypted segments not currently supported by Il2CppInspector."); + + if (entries.Any(e => e.HasBlocks && e.IsDeflated)) + throw new NotImplementedException("This file contains compressed segments not currently supported by Il2CppInspector."); + + // Read ELF header + // PS4 files as follows: + // m_arch = 0x2 (64-bit) + // m_endian = 0x1 (little endian) + // m_version = 0x1 (ELF version 1) + // m_osabi = 0x9 (FreeBSD) + // e_type = special type, see psdevwiki documentation; probably 0xFE10 or 0xFE18 + // e_machine = 0x3E (x86-64) + var startOfElf = Position; + elfHeader = ReadObject>(); + + // Must be one of these supported binary types + if (elfHeader.e_type != (ushort) Elf.ET_EXEC + && elfHeader.e_type != (ushort) SElfETypes.ET_SCE_EXEC + && elfHeader.e_type != (ushort) SElfETypes.ET_SCE_DYNEXEC + && elfHeader.e_type != (ushort) SElfETypes.ET_SCE_DYNAMIC) + return false; + + // There are no sections, but read all the program headers + // Each segment of type PT_LOAD, PT_SCE_RELRO, PT_SCE_DYNLIBDATA and PT_SCE_COMMENT + // generates two SELF entries above - one pointing to the ELF segment and one pointing to a digest. + // Only p_vaddr is used for memory mapping; all other fields are ignored. + // offset, memsz and filesz are taken from the SELF entries. + // The digests are all-zero in FSELF files. + // All other ELF segments are ignored completely. + pht = ReadArray(startOfElf + (long) elfHeader.e_phoff, elfHeader.e_phnum); + + // Read extended info + sceData = ReadObject(startOfElf + (long) elfHeader.e_phoff + elfHeader.e_phentsize * elfHeader.e_phnum); + + // TODO: Implement the rest of FSELF + // TODO: Set GlobalOffset + + throw new NotImplementedException("Il2CppInspector does not have PRX support yet"); + + return true; + } + + // Only the DT_INIT function equivalent + public override uint[] GetFunctionTable() => new [] { MapVATR(elfHeader.e_entry) }; + + public override uint MapVATR(ulong uiAddr) { + throw new NotImplementedException(); + } + } +} \ No newline at end of file