diff --git a/Il2CppInspector/FileFormatReader.cs b/Il2CppInspector/FileFormatReader.cs index 03f7a66..6e1d273 100644 --- a/Il2CppInspector/FileFormatReader.cs +++ b/Il2CppInspector/FileFormatReader.cs @@ -20,6 +20,7 @@ namespace Il2CppInspector long Position { get; set; } string Arch { get; } uint GlobalOffset { get; } + Dictionary GetSymbolTable(); uint[] GetFunctionTable(); U ReadMappedObject(uint uiAddr) where U : new(); U[] ReadMappedArray(uint uiAddr, int count) where U : new(); @@ -76,6 +77,9 @@ namespace Il2CppInspector } } + // Find search locations in the symbol table for Il2Cpp data + public virtual Dictionary GetSymbolTable() => null; + // Find search locations in the machine code for Il2Cpp data public virtual uint[] GetFunctionTable() => throw new NotImplementedException(); diff --git a/Il2CppInspector/FileFormatReaders/ElfReader.cs b/Il2CppInspector/FileFormatReaders/ElfReader.cs index 6166edf..91ea5fd 100644 --- a/Il2CppInspector/FileFormatReaders/ElfReader.cs +++ b/Il2CppInspector/FileFormatReaders/ElfReader.cs @@ -1,19 +1,23 @@ /* Copyright 2017 Perfare - https://github.com/Perfare/Il2CppDumper - Copyright 2017 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com + Copyright 2017-2019 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com All rights reserved. */ using System; +using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; +using System.Net.Sockets; namespace Il2CppInspector { internal class ElfReader : FileFormatReader { private program_header_table[] program_table_element; + private elf_32_shdr[] section_header_table; private elf_header elf_header; public ElfReader(Stream stream) : base(stream) { } @@ -44,9 +48,65 @@ namespace Il2CppInspector return false; } program_table_element = ReadArray(elf_header.e_phoff, elf_header.e_phnum); + section_header_table = ReadArray(elf_header.e_shoff, elf_header.e_shnum); return true; } + public override Dictionary GetSymbolTable() { + // Three possible symbol tables in ELF files + var pTables = new List<(uint offset, uint count, uint strings)>(); + + // String table (a sequence of null-terminated strings, total length in sh_size + var SHT_STRTAB = section_header_table.FirstOrDefault(x => x.sh_type == 3u); // SHT_STRTAB = 3 + + if (SHT_STRTAB != null) { + // Section header shared object symbol table (.symtab) + if (section_header_table.FirstOrDefault(x => x.sh_type == 2u) is elf_32_shdr SHT_SYMTAB) // SHT_SYMTAB = 2 + pTables.Add((SHT_SYMTAB.sh_offset, SHT_SYMTAB.sh_size / SHT_SYMTAB.sh_entsize, SHT_STRTAB.sh_offset)); + + // Section header executable symbol table (.dynsym) + if (section_header_table.FirstOrDefault(x => x.sh_type == 11u) is elf_32_shdr SHT_DYNSYM) // SHT_DYNSUM = 11 + pTables.Add((SHT_DYNSYM.sh_offset, SHT_DYNSYM.sh_size / SHT_DYNSYM.sh_entsize, SHT_STRTAB.sh_offset)); + } + + // Symbol table in dynamic section (DT_SYMTAB) + // Normally the same as .dynsym except that .dynsym may be removed in stripped binaries + if (program_table_element.FirstOrDefault(x => x.p_type == 2u) is program_header_table PT_DYNAMIC) // PT_DYNAMIC = 2 + { + // Get the dynamic table + var dynamic_table = ReadArray(PT_DYNAMIC.p_offset, (int) PT_DYNAMIC.p_filesz / 8 /* sizeof(elf_32_dynamic) */); + + // Dynamic string table + var DT_STRTAB = dynamic_table.FirstOrDefault(x => x.d_tag == 5u); // DT_STRTAB = 5 + + if (DT_STRTAB != null) { + if (dynamic_table.FirstOrDefault(x => x.d_tag == 6u) is elf_32_dynamic DT_SYMTAB) { // DT_SYMTAB = 6 + // Find the next pointer in the dynamic table to calculate the length of the symbol table + var end = (from x in dynamic_table where x.d_un > DT_SYMTAB.d_un orderby x.d_un select x).First().d_un; + + // Dynamic symbol table + pTables.Add((DT_SYMTAB.d_un, (end - DT_SYMTAB.d_un) / 16 /* sizeof(elf_32_sym) */, DT_STRTAB.d_un)); + } + } + } + + // Now iterate through all of the symbol and string tables we found to build a full list + var symbolTable = new Dictionary(); + + foreach (var pTab in pTables) { + var symbol_table = ReadArray(pTab.offset, (int) pTab.count); + + foreach (var symbol in symbol_table) { + var name = ReadNullTerminatedString(pTab.strings + symbol.st_name); + + // Avoid duplicates + symbolTable.TryAdd(name, symbol.st_value); + } + } + + return symbolTable; + } + public override uint[] GetFunctionTable() { // Find dynamic section var dynamic = new elf_32_shdr(); diff --git a/Il2CppInspector/FileFormatReaders/FormatLayouts/Elf.cs b/Il2CppInspector/FileFormatReaders/FormatLayouts/Elf.cs index e0f50a4..31a2fda 100644 --- a/Il2CppInspector/FileFormatReaders/FormatLayouts/Elf.cs +++ b/Il2CppInspector/FileFormatReaders/FormatLayouts/Elf.cs @@ -1,6 +1,6 @@ /* Copyright 2017 Perfare - https://github.com/Perfare/Il2CppDumper - Copyright 2017 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com + Copyright 2017-2019 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com All rights reserved. */ @@ -85,5 +85,21 @@ namespace Il2CppInspector public uint sh_addralign; public uint sh_entsize; } + + internal class elf_32_sym + { + public uint st_name; + public uint st_value; + public uint st_size; + public byte st_info; + public byte st_other; + public ushort st_shndx; + } + + internal class elf_32_dynamic + { + public uint d_tag; + public uint d_un; + } #pragma warning restore CS0649 } diff --git a/Il2CppInspector/Il2CppBinary.cs b/Il2CppInspector/Il2CppBinary.cs index 0b08c9d..7af6291 100644 --- a/Il2CppInspector/Il2CppBinary.cs +++ b/Il2CppInspector/Il2CppBinary.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; namespace Il2CppInspector @@ -50,19 +51,49 @@ namespace Il2CppInspector public bool Initialize(double version, uint imageIndex = 0) { var subImage = Image[imageIndex]; subImage.Stream.Version = version; + + // Try searching the symbol table + var symbols = subImage.GetSymbolTable(); + + if (symbols?.Any() ?? false) { + Console.WriteLine($"Symbol table(s) found with {symbols.Count} entries"); + + symbols.TryGetValue("g_CodeRegistration", out var code); + symbols.TryGetValue("g_MetadataRegistration", out var metadata); + + if (code != 0 && metadata != 0) { + Console.WriteLine("Required structures acquired from symbol lookup"); + Configure(subImage, code, metadata); + return true; + } + else { + Console.WriteLine("No matches in symbol table"); + } + } + else if (symbols != null) { + Console.WriteLine("No symbol table present in binary file"); + } + else { + Console.WriteLine("Symbol table search not implemented for this binary format"); + } + + // Try searching the function table var addrs = subImage.GetFunctionTable(); - Console.WriteLine("Function Table:"); - Console.WriteLine(string.Join(", ", from a in addrs select string.Format($"0x{a:X8}"))); + Debug.WriteLine("Function table:"); + Debug.WriteLine(string.Join(", ", from a in addrs select string.Format($"0x{a:X8}"))); foreach (var loc in addrs) if (loc != 0) { var (code, metadata) = ConsiderCode(loc, Image.GlobalOffset); if (code != 0) { + Console.WriteLine("Required structures acquired from code heuristics"); Configure(subImage, code, metadata); return true; } } + + Console.WriteLine("No matches via code heuristics"); return false; }