From 5652e89abe763cf7956adf8b4f5d68a5f015121a Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Sat, 8 Feb 2020 11:58:09 +0100 Subject: [PATCH] ELF: Detect and defeat trivial XOR encryption --- .../FileFormatReaders/ElfReader.cs | 42 ++++++++++++++++++- .../FileFormatReaders/FormatLayouts/Elf.cs | 1 + 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/Il2CppInspector.Common/FileFormatReaders/ElfReader.cs b/Il2CppInspector.Common/FileFormatReaders/ElfReader.cs index 1e7cde8..bd6aba5 100644 --- a/Il2CppInspector.Common/FileFormatReaders/ElfReader.cs +++ b/Il2CppInspector.Common/FileFormatReaders/ElfReader.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using System.Text; namespace Il2CppInspector { @@ -108,6 +109,7 @@ namespace Il2CppInspector private elf_shdr[] section_header_table; private elf_dynamic[] dynamic_table; private elf_header elf_header; + private Dictionary> sectionByName = new Dictionary>(); public ElfReader(Stream stream) : base(stream) { } @@ -139,13 +141,22 @@ namespace Il2CppInspector if ((Elf) elf_header.m_dwFormat != Elf.ELFMAG) return false; - // 64-bit not supported + // Ensure supported architecture if ((Elf) elf_header.m_arch != ArchClass) return false; + // Get PHT and SHT 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); + // Get section name mappings + var pStrtab = section_header_table[elf_header.e_shtrndx].sh_offset; + foreach (var section in section_header_table) { + var name = ReadNullTerminatedString(conv.Long(pStrtab) + section.sh_name); + sectionByName.Add(name, section); + } + + // Get dynamic table if it exists if (getProgramHeader(Elf.PT_DYNAMIC) is TPHdr PT_DYNAMIC) dynamic_table = ReadArray>(conv.Long(PT_DYNAMIC.p_offset), (int) (conv.Long(PT_DYNAMIC.p_filesz) / Sizeof(typeof(elf_dynamic)))); @@ -187,7 +198,7 @@ namespace Il2CppInspector if (BaseStream is FileStream) throw new InvalidOperationException("Input stream to ElfReader is a file. Please supply a mutable stream source."); - var writer = new BinaryWriter(BaseStream); + using var writer = new BinaryWriter(BaseStream, Encoding.Default, true); var relsz = Sizeof(typeof(TSym)); foreach (var rel in rels) { @@ -236,9 +247,36 @@ namespace Il2CppInspector } Console.WriteLine($"Processed {rels.Count} relocations"); + // Detect and defeat trivial XOR encryption + if (dynamic_table.Any(d => (Elf) conv.Int(d.d_tag) == Elf.DT_INIT)) { + var rodataFirstBytes = ReadArray(conv.Long(sectionByName[".rodata"].sh_offset), 256); + var xorKey = rodataFirstBytes.GroupBy(b => b).OrderByDescending(f => f.Count()).First().Key; + + if (xorKey != 0x00) { + Console.WriteLine($"Performing trivial XOR decryption (key: 0x{xorKey:X2})"); + + xorSection(".text", xorKey); + xorSection(".rodata", xorKey); + } + } + return true; } + private void xorRange(int offset, int length, byte xorValue) { + using var writer = new BinaryWriter(BaseStream, Encoding.Default, true); + + var bytes = ReadArray(offset, length); + bytes = bytes.Select(b => (byte) (b ^ xorValue)).ToArray(); + writer.Seek(offset, SeekOrigin.Begin); + writer.Write(bytes); + } + + private void xorSection(string sectionName, byte xorValue) { + var section = sectionByName[sectionName]; + xorRange(conv.Int(section.sh_offset), conv.Int(section.sh_size), xorValue); + } + public override Dictionary GetSymbolTable() { // Three possible symbol tables in ELF files var pTables = new List<(TWord offset, TWord count, TWord strings)>(); diff --git a/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/Elf.cs b/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/Elf.cs index fd483b0..b9fe70b 100644 --- a/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/Elf.cs +++ b/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/Elf.cs @@ -45,6 +45,7 @@ namespace Il2CppInspector DT_RELA = 7, DT_RELASZ = 8, DT_RELAENT = 9, + DT_INIT = 12, DT_REL = 17, DT_RELSZ = 18, DT_RELENT = 19,