diff --git a/Il2CppInspector.Common/FileFormatReaders/ElfReader.cs b/Il2CppInspector.Common/FileFormatReaders/ElfReader.cs index fda3497..46f0bf3 100644 --- a/Il2CppInspector.Common/FileFormatReaders/ElfReader.cs +++ b/Il2CppInspector.Common/FileFormatReaders/ElfReader.cs @@ -112,6 +112,8 @@ namespace Il2CppInspector private elf_header elf_header; private Dictionary> sectionByName = new Dictionary>(); private List<(uint Start, uint End)> reverseMapExclusions = new List<(uint Start, uint End)>(); + private bool preferPHT = false; + private bool isDumpedImage = false; public ElfReader(Stream stream) : base(stream) { } @@ -156,6 +158,45 @@ namespace Il2CppInspector program_header_table = ReadArray(conv.Long(elf_header.e_phoff), elf_header.e_phnum); section_header_table = ReadArray>(conv.Long(elf_header.e_shoff), elf_header.e_shnum); + // Determine if SHT is valid + + // These can happen as a result of conversions from other formats to ELF, + // or if the SHT has been deliberately stripped + if (!section_header_table.Any()) { + Console.WriteLine("ELF binary has no SHT - reverting to PHT"); + preferPHT = true; + } + + else if (section_header_table.All(s => conv.ULong(s.sh_addr) == 0ul)) { + Console.WriteLine("ELF binary SHT is all-zero - reverting to PHT"); + preferPHT = true; + } + + // Check for overlaps in sections that are memory-allocated on load + else { + var shtShouldBeOrdered = section_header_table + .Where(s => ((Elf) conv.Int(s.sh_flags) & Elf.SHF_ALLOC) == Elf.SHF_ALLOC) + .OrderBy(s => s.sh_addr) + .Select(s => new[] { conv.ULong(s.sh_addr), conv.ULong(s.sh_addr) + conv.ULong(s.sh_size) }) + .SelectMany(s => s); + + // No sections that map into memory - this is probably a dumped image + if (!shtShouldBeOrdered.Any()) { + Console.WriteLine("ELF binary appears to be a dumped memory image"); + isDumpedImage = true; + preferPHT = true; + } + + // Sections overlap - this can happen if the ELF has been improperly generated or processed by another tool + else { + var shtOverlap = shtShouldBeOrdered.Aggregate((x, y) => x <= y? y : ulong.MaxValue) == ulong.MaxValue; + if (shtOverlap) { + Console.WriteLine("ELF binary SHT contains invalid ranges - reverting to PHT"); + preferPHT = true; + } + } + } + // Get section name mappings if there are any // This is currently only used to defeat the XOR obfuscation handled below // Note: There can be more than one section with the same name, or unnamed; we take the first section with a given name @@ -577,7 +618,7 @@ namespace Il2CppInspector public override IEnumerable
GetSections() { // If the sections have been stripped, use the segment list from the PHT instead - if (section_header_table.All(s => conv.Int(s.sh_offset) == 0)) { + if (preferPHT) return program_header_table.Select(p => new Section { VirtualStart = conv.ULong(p.p_vaddr), VirtualEnd = conv.ULong(p.p_vaddr) + conv.ULong(p.p_memsz) - 1, @@ -591,7 +632,6 @@ namespace Il2CppInspector Name = string.Empty }); - } // Return sections list return section_header_table.Select(s => new Section {