diff --git a/Il2CppInspector/FileFormatReaders/ElfReader.cs b/Il2CppInspector/FileFormatReaders/ElfReader.cs index ee842bc..6c193f1 100644 --- a/Il2CppInspector/FileFormatReaders/ElfReader.cs +++ b/Il2CppInspector/FileFormatReaders/ElfReader.cs @@ -7,60 +7,142 @@ using System; using System.Collections.Generic; -using System.Data.Common; -using System.Diagnostics; using System.IO; using System.Linq; +using System.Reflection; namespace Il2CppInspector { - internal class ElfReader : FileFormatReader + internal class ElfReader32 : ElfReader { + public ElfReader32(Stream stream) : base(stream) { + ElfReloc.GetRelocType = info => (Elf) (info & 0xff); + ElfReloc.GetSymbolIndex = info => info >> 8; + } + + public override int Bits => 32; + protected override Elf ArchClass => Elf.ELFCLASS32; + + protected override void Write(BinaryWriter writer, uint value) => writer.Write(value); + } + + internal class ElfReader64 : ElfReader + { + public ElfReader64(Stream stream) : base(stream) { + ElfReloc.GetRelocType = info => (Elf) (info & 0xffff_ffff); + ElfReloc.GetSymbolIndex = info => info >> 32; + } + + public override int Bits => 64; + protected override Elf ArchClass => Elf.ELFCLASS64; + + protected override void Write(BinaryWriter writer, ulong value) => writer.Write(value); + } + + // NOTE: What we really should have done here is add a TWord type parameter to FileFormatReader + // then we could probably avoid most of this + interface IElfMath where TWord : struct + { + TWord Add(TWord a, TWord b); + TWord Sub(TWord a, TWord b); + TWord Div(TWord a, TWord b); + TWord Div(TWord a, int b); + int Int(TWord a); + long Long(TWord a); + ulong ULong(TWord a); + bool Gt(TWord a, TWord b); + uint[] UIntArray(TWord[] a); + } + + internal class ElfMath32 : IElfMath + { + public uint Add(uint a, uint b) => a + b; + public uint Sub(uint a, uint b) => a - b; + public uint Div(uint a, uint b) => a / b; + public uint Div(uint a, int b) => a / (uint) b; + public int Int(uint a) => (int) a; + public long Long(uint a) => a; + public ulong ULong(uint a) => a; + public bool Gt(uint a, uint b) => a > b; + public uint[] UIntArray(uint[] a) => a; + } + internal class ElfMath64 : IElfMath + { + public ulong Add(ulong a, ulong b) => a + b; + public ulong Sub(ulong a, ulong b) => a - b; + public ulong Div(ulong a, ulong b) => a / b; + public ulong Div(ulong a, int b) => a / (uint) b; + public int Int(ulong a) => (int) a; + public long Long(ulong a) => (long) a; + public ulong ULong(ulong a) => a; + public bool Gt(ulong a, ulong b) => a > b; + public uint[] UIntArray(ulong[] a) => Array.ConvertAll(a, x => (uint) x); + } + + internal abstract class ElfReader : FileFormatReader + where TWord : struct + where TPHdr : Ielf_phdr, new() + where TSym : Ielf_sym, new() + where TMath : IElfMath, new() + where TReader : FileFormatReader + { + private readonly TMath math = new TMath(); + // Internal relocation entry helper - private struct ElfReloc + protected class ElfReloc { public Elf Type; - public uint Offset; - public uint? Addend; - public uint SymbolTable; - public uint SymbolIndex; + public TWord Offset; + public TWord? Addend; + public TWord SymbolTable; + public TWord SymbolIndex; // Equality based on target address public override bool Equals(object obj) => obj is ElfReloc reloc && Equals(reloc); public bool Equals(ElfReloc other) { - return Offset == other.Offset; + return Offset.Equals(other.Offset); } - public override int GetHashCode() { - unchecked { - var hashCode = (int)Type; - hashCode = (hashCode * 397) ^ (int)Offset; - hashCode = (hashCode * 397) ^ Addend.GetHashCode(); - hashCode = (hashCode * 397) ^ (int)SymbolTable; - hashCode = (hashCode * 397) ^ (int)SymbolIndex; - return hashCode; - } - } + public override int GetHashCode() => Offset.GetHashCode(); // Cast operators (makes the below code MUCH easier to read) - public ElfReloc(elf_32_rel rel, uint symbolTable) { - Type = (Elf) (rel.r_info & 0xff); + public ElfReloc(elf_rel rel, TWord symbolTable) { Offset = rel.r_offset; Addend = null; - SymbolIndex = rel.r_info >> 8; // r_info >> 8 is an index into the symbol table + Type = GetRelocType(rel.r_info); + SymbolIndex = GetSymbolIndex(rel.r_info); SymbolTable = symbolTable; } - public ElfReloc(elf_32_rela rela, uint symbolTable) - : this(new elf_32_rel { r_info = rela.r_info, r_offset = rela.r_offset }, symbolTable) => + public ElfReloc(elf_rela rela, TWord symbolTable) + : this(new elf_rel { r_info = rela.r_info, r_offset = rela.r_offset }, symbolTable) => Addend = rela.r_addend; + + public static Func GetRelocType; + public static Func GetSymbolIndex; } - private elf_32_phdr[] program_header_table; - private elf_32_shdr[] section_header_table; - private elf_32_dynamic[] dynamic_table; - private elf_header elf_header; + // See also: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/sizeof + private int Sizeof(Type type) { + int size = 0; + foreach (var i in type.GetTypeInfo().GetFields()) { + if (i.FieldType == typeof(byte) || i.FieldType == typeof(sbyte)) + size += sizeof(byte); + if (i.FieldType == typeof(long) || i.FieldType == typeof(ulong)) + size += sizeof(ulong); + if (i.FieldType == typeof(int) || i.FieldType == typeof(uint)) + size += sizeof(uint); + if (i.FieldType == typeof(short) || i.FieldType == typeof(ushort)) + size += sizeof(ushort); + } + return size; + } + + private TPHdr[] program_header_table; + private elf_shdr[] section_header_table; + private elf_dynamic[] dynamic_table; + private elf_header elf_header; public ElfReader(Stream stream) : base(stream) { } @@ -76,35 +158,37 @@ namespace Il2CppInspector public override int Bits => (elf_header.m_arch == (uint) Elf.ELFCLASS64) ? 64 : 32; - private elf_32_shdr getSection(Elf sectionIndex) => section_header_table.FirstOrDefault(x => x.sh_type == (uint) sectionIndex); - private IEnumerable getSections(Elf sectionIndex) => section_header_table.Where(x => x.sh_type == (uint)sectionIndex); - private elf_32_phdr getProgramHeader(Elf programIndex) => program_header_table.FirstOrDefault(x => x.p_type == (uint) programIndex); - private elf_32_dynamic getDynamic(Elf dynamicIndex) => dynamic_table?.FirstOrDefault(x => x.d_tag == (uint) dynamicIndex); + private elf_shdr getSection(Elf sectionIndex) => section_header_table.FirstOrDefault(x => x.sh_type == (uint) sectionIndex); + private IEnumerable> getSections(Elf sectionIndex) => section_header_table.Where(x => x.sh_type == (uint) sectionIndex); + private TPHdr getProgramHeader(Elf programIndex) => program_header_table.FirstOrDefault(x => x.p_type == (uint) programIndex); + private elf_dynamic getDynamic(Elf dynamicIndex) => dynamic_table?.FirstOrDefault(x => (Elf) math.ULong(x.d_tag) == dynamicIndex); + + protected abstract Elf ArchClass { get; } + + protected abstract void Write(BinaryWriter writer, TWord value); protected override bool Init() { - elf_header = ReadObject(); + elf_header = ReadObject>(); // Check for magic bytes - if (elf_header.m_dwFormat != (uint) Elf.ELFMAG) { + if ((Elf) elf_header.m_dwFormat != Elf.ELFMAG) return false; - } // 64-bit not supported - if (elf_header.m_arch == (uint) Elf.ELFCLASS64) { + if ((Elf) elf_header.m_arch != ArchClass) return false; - } - program_header_table = ReadArray(elf_header.e_phoff, elf_header.e_phnum); - section_header_table = ReadArray(elf_header.e_shoff, elf_header.e_shnum); + program_header_table = ReadArray(math.Long(elf_header.e_phoff), elf_header.e_phnum); + section_header_table = ReadArray>(math.Long(elf_header.e_shoff), elf_header.e_shnum); - if (getProgramHeader(Elf.PT_DYNAMIC) is elf_32_phdr PT_DYNAMIC) - dynamic_table = ReadArray(PT_DYNAMIC.p_offset, (int) PT_DYNAMIC.p_filesz / 8 /* sizeof(elf_32_dynamic) */); + if (getProgramHeader(Elf.PT_DYNAMIC) is TPHdr PT_DYNAMIC) + dynamic_table = ReadArray>(math.Long(PT_DYNAMIC.p_offset), (int) (math.Long(PT_DYNAMIC.p_filesz) / Sizeof(typeof(elf_dynamic)))); // Get global offset table var _GLOBAL_OFFSET_TABLE_ = getDynamic(Elf.DT_PLTGOT)?.d_un; if (_GLOBAL_OFFSET_TABLE_ == null) throw new InvalidOperationException("Unable to get GLOBAL_OFFSET_TABLE from PT_DYNAMIC"); - GlobalOffset = (uint) _GLOBAL_OFFSET_TABLE_; + GlobalOffset = math.ULong((TWord) _GLOBAL_OFFSET_TABLE_); // Find all relocations; target address => (rela header (rels are converted to rela), symbol table base address, is rela?) var rels = new HashSet(); @@ -112,25 +196,25 @@ namespace Il2CppInspector // Two types: add value from offset in image, and add value from specified addend foreach (var relSection in getSections(Elf.SHT_REL)) rels.UnionWith( - from rel in ReadArray(relSection.sh_offset, (int) (relSection.sh_size / relSection.sh_entsize)) + from rel in ReadArray>(math.Long(relSection.sh_offset), math.Int(math.Div(relSection.sh_size, relSection.sh_entsize))) select new ElfReloc(rel, section_header_table[relSection.sh_link].sh_offset)); foreach (var relaSection in getSections(Elf.SHT_RELA)) rels.UnionWith( - from rela in ReadArray(relaSection.sh_offset, (int)(relaSection.sh_size / relaSection.sh_entsize)) + from rela in ReadArray>(math.Long(relaSection.sh_offset), math.Int(math.Div(relaSection.sh_size, relaSection.sh_entsize))) select new ElfReloc(rela, section_header_table[relaSection.sh_link].sh_offset)); // Relocations in dynamic section - if (getDynamic(Elf.DT_REL) is elf_32_dynamic dt_rel) { - var dt_rel_count = getDynamic(Elf.DT_RELSZ).d_un / getDynamic(Elf.DT_RELENT).d_un; - var dt_rel_list = ReadArray(MapVATR(dt_rel.d_un), (int) dt_rel_count); + if (getDynamic(Elf.DT_REL) is elf_dynamic dt_rel) { + var dt_rel_count = math.Div(getDynamic(Elf.DT_RELSZ).d_un, getDynamic(Elf.DT_RELENT).d_un); + var dt_rel_list = ReadArray>(MapVATR(math.ULong(dt_rel.d_un)), math.Int(dt_rel_count)); var dt_symtab = getDynamic(Elf.DT_SYMTAB).d_un; rels.UnionWith(from rel in dt_rel_list select new ElfReloc(rel, dt_symtab)); } - if (getDynamic(Elf.DT_RELA) is elf_32_dynamic dt_rela) { - var dt_rela_count = getDynamic(Elf.DT_RELASZ).d_un / getDynamic(Elf.DT_RELAENT).d_un; - var dt_rela_list = ReadArray(MapVATR(dt_rela.d_un), (int) dt_rela_count); + if (getDynamic(Elf.DT_RELA) is elf_dynamic dt_rela) { + var dt_rela_count = math.Div(getDynamic(Elf.DT_RELASZ).d_un, getDynamic(Elf.DT_RELAENT).d_un); + var dt_rela_list = ReadArray>(MapVATR(math.ULong(dt_rela.d_un)), math.Int(dt_rela_count)); var dt_symtab = getDynamic(Elf.DT_SYMTAB).d_un; rels.UnionWith(from rela in dt_rela_list select new ElfReloc(rela, dt_symtab)); } @@ -141,35 +225,43 @@ namespace Il2CppInspector throw new InvalidOperationException("Input stream to ElfReader is a file. Please supply a mutable stream source."); var writer = new BinaryWriter(BaseStream); + var relsz = Sizeof(typeof(TSym)); foreach (var rel in rels) { - var symValue = ReadObject(rel.SymbolTable + rel.SymbolIndex * 16 /* sizeof(elf_32_sym) */).st_value; // S + var symValue = ReadObject(math.Long(rel.SymbolTable) + math.Long(rel.SymbolIndex) * relsz).st_value; // S // The addend is specified in the struct for rela, and comes from the target location for rel - Position = MapVATR(rel.Offset); - var addend = rel.Addend ?? ReadUInt32(); // A + Position = MapVATR(math.ULong(rel.Offset)); + var addend = rel.Addend ?? ReadObject(); // A // Only handle relocation types we understand, skip the rest // Relocation types from https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-54839.html#scrolltoc // and https://studfiles.net/preview/429210/page:18/ - (uint newValue, bool recognized) result = (rel.Type, (Elf) elf_header.e_machine) switch { - (Elf.R_ARM_ABS32, Elf.EM_ARM) => (symValue + addend, true), // S + A - (Elf.R_ARM_REL32, Elf.EM_ARM) => (symValue - rel.Offset + addend, true), // S - P + A + // and http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf (AArch64) + (TWord newValue, bool recognized) result = (rel.Type, (Elf) elf_header.e_machine) switch { + (Elf.R_ARM_ABS32, Elf.EM_ARM) => (math.Add(symValue, addend), true), // S + A + (Elf.R_ARM_REL32, Elf.EM_ARM) => (math.Add(math.Sub(symValue, rel.Offset), addend), true), // S - P + A (Elf.R_ARM_COPY, Elf.EM_ARM) => (symValue, true), // S - (Elf.R_386_32, Elf.EM_386) => (symValue + addend, true), // S + A - (Elf.R_386_PC32, Elf.EM_386) => (symValue + addend - rel.Offset, true), // S + A - P + (Elf.R_AARCH64_ABS64, Elf.EM_AARCH64) => (math.Add(symValue, addend), true), // S + A + (Elf.R_AARCH64_PREL64, Elf.EM_AARCH64) => (math.Sub(math.Add(symValue, addend), rel.Offset), true), // S + A - P + (Elf.R_AARCH64_GLOB_DAT, Elf.EM_AARCH64) => (math.Add(symValue, addend), true), // S + A + (Elf.R_AARCH64_JUMP_SLOT, Elf.EM_AARCH64) => (math.Add(symValue, addend), true), // S + A + (Elf.R_AARCH64_RELATIVE, Elf.EM_AARCH64) => (math.Add(symValue, addend), true), // Delta(S) + A + + (Elf.R_386_32, Elf.EM_386) => (math.Add(symValue, addend), true), // S + A + (Elf.R_386_PC32, Elf.EM_386) => (math.Sub(math.Add(symValue, addend), rel.Offset), true), // S + A - P (Elf.R_386_GLOB_DAT, Elf.EM_386) => (symValue, true), // S (Elf.R_386_JMP_SLOT, Elf.EM_386) => (symValue, true), // S - (Elf.R_AMD64_64, Elf.EM_AARCH64) => (symValue + addend, true), // S + A + (Elf.R_AMD64_64, Elf.EM_AARCH64) => (math.Add(symValue, addend), true), // S + A - _ => (0, false) + _ => (default(TWord), false) }; if (result.recognized) { - Position = MapVATR(rel.Offset); - writer.Write(result.newValue); + Position = MapVATR(math.ULong(rel.Offset)); + Write(writer, result.newValue); } } Console.WriteLine($"Processed {rels.Count} relocations"); @@ -179,32 +271,32 @@ namespace Il2CppInspector public override Dictionary GetSymbolTable() { // Three possible symbol tables in ELF files - var pTables = new List<(uint offset, uint count, uint strings)>(); + var pTables = new List<(TWord offset, TWord count, TWord strings)>(); // String table (a sequence of null-terminated strings, total length in sh_size var SHT_STRTAB = getSection(Elf.SHT_STRTAB); if (SHT_STRTAB != null) { // Section header shared object symbol table (.symtab) - if (getSection(Elf.SHT_SYMTAB) is elf_32_shdr SHT_SYMTAB) - pTables.Add((SHT_SYMTAB.sh_offset, SHT_SYMTAB.sh_size / SHT_SYMTAB.sh_entsize, SHT_STRTAB.sh_offset)); + if (getSection(Elf.SHT_SYMTAB) is elf_shdr SHT_SYMTAB) + pTables.Add((SHT_SYMTAB.sh_offset, math.Div(SHT_SYMTAB.sh_size, SHT_SYMTAB.sh_entsize), SHT_STRTAB.sh_offset)); // Section header executable symbol table (.dynsym) - if (getSection(Elf.SHT_DYNSYM) is elf_32_shdr SHT_DYNSYM) - pTables.Add((SHT_DYNSYM.sh_offset, SHT_DYNSYM.sh_size / SHT_DYNSYM.sh_entsize, SHT_STRTAB.sh_offset)); + if (getSection(Elf.SHT_DYNSYM) is elf_shdr SHT_DYNSYM) + pTables.Add((SHT_DYNSYM.sh_offset, math.Div(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 // Dynamic string table - if (getDynamic(Elf.DT_STRTAB) is elf_32_dynamic DT_STRTAB) { - if (getDynamic(Elf.DT_SYMTAB) is elf_32_dynamic DT_SYMTAB) { + if (getDynamic(Elf.DT_STRTAB) is elf_dynamic DT_STRTAB) { + if (getDynamic(Elf.DT_SYMTAB) is elf_dynamic DT_SYMTAB) { // 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; + var end = (from x in dynamic_table where math.Gt(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)); + pTables.Add((DT_SYMTAB.d_un, math.Div(math.Sub(end, DT_SYMTAB.d_un), Sizeof(typeof(TSym))), DT_STRTAB.d_un)); } } @@ -212,13 +304,13 @@ namespace Il2CppInspector var symbolTable = new Dictionary(); foreach (var pTab in pTables) { - var symbol_table = ReadArray(pTab.offset, (int) pTab.count); + var symbol_table = ReadArray(math.Long(pTab.offset), math.Int(pTab.count)); foreach (var symbol in symbol_table) { - var name = ReadNullTerminatedString(pTab.strings + symbol.st_name); + var name = ReadNullTerminatedString(math.Long(pTab.strings) + symbol.st_name); // Avoid duplicates - symbolTable.TryAdd(name, symbol.st_value); + symbolTable.TryAdd(name, math.ULong(symbol.st_value)); } } @@ -229,19 +321,21 @@ namespace Il2CppInspector // INIT_ARRAY contains a list of pointers to initialization functions (not all functions in the binary) // INIT_ARRAYSZ contains the size of INIT_ARRAY - var init = MapVATR(getDynamic(Elf.DT_INIT_ARRAY).d_un); + var init = MapVATR(math.ULong(getDynamic(Elf.DT_INIT_ARRAY).d_un)); var size = getDynamic(Elf.DT_INIT_ARRAYSZ).d_un; - return ReadArray(init, (int) size / 4); + return math.UIntArray(ReadArray(init, math.Int(size) / (Bits / 8))); } // Map a virtual address to an offset into the image file. Throws an exception if the virtual address is not mapped into the file. // Note if uiAddr is a valid segment but filesz < memsz and the adjusted uiAddr falls between the range of filesz and memsz, // an exception will be thrown. This area of memory is assumed to contain all zeroes. public override uint MapVATR(ulong uiAddr) { - var addr32 = (uint) uiAddr; // 32-bit implementation - var program_header_table = this.program_header_table.First(x => addr32 >= x.p_vaddr && addr32 <= (x.p_vaddr + x.p_filesz)); - return addr32 - (program_header_table.p_vaddr - program_header_table.p_offset); + // Additions in the argument to MapVATR may cause an overflow which should be discarded for 32-bit files + if (Bits == 32) + uiAddr &= 0xffff_ffff; + var program_header_table = this.program_header_table.First(x => uiAddr >= math.ULong(x.p_vaddr) && uiAddr <= math.ULong(math.Add(x.p_vaddr, x.p_filesz))); + return (uint) (uiAddr - math.ULong(math.Sub(program_header_table.p_vaddr, program_header_table.p_offset))); } } } \ No newline at end of file diff --git a/Il2CppInspector/FileFormatReaders/FormatLayouts/Elf.cs b/Il2CppInspector/FileFormatReaders/FormatLayouts/Elf.cs index 25ffcfb..9d64e93 100644 --- a/Il2CppInspector/FileFormatReaders/FormatLayouts/Elf.cs +++ b/Il2CppInspector/FileFormatReaders/FormatLayouts/Elf.cs @@ -52,6 +52,12 @@ namespace Il2CppInspector R_ARM_REL32 = 3, R_ARM_COPY = 20, + R_AARCH64_ABS64 = 0x101, + R_AARCH64_PREL64 = 0x104, + R_AARCH64_GLOB_DAT = 0x401, + R_AARCH64_JUMP_SLOT = 0x402, + R_AARCH64_RELATIVE = 0x403, + R_386_32 = 1, R_386_PC32 = 2, R_386_GLOB_DAT = 6, @@ -61,7 +67,7 @@ namespace Il2CppInspector } #pragma warning disable CS0649 - internal class elf_header + internal class elf_header where TWord : struct { // 0x7f followed by ELF in ascii public uint m_dwFormat; @@ -98,9 +104,9 @@ namespace Il2CppInspector public uint e_version; - public uint e_entry; - public uint e_phoff; - public uint e_shoff; + public TWord e_entry; + public TWord e_phoff; + public TWord e_shoff; public uint e_flags; public ushort e_ehsize; public ushort e_phentsize; @@ -110,60 +116,111 @@ namespace Il2CppInspector public ushort e_shtrndx; } - internal class elf_32_phdr + internal interface Ielf_phdr where TWord : struct { - public uint p_type; - public uint p_offset; - public uint p_vaddr; + uint p_type { get; } + TWord p_offset { get; } + TWord p_filesz { get; } + TWord p_vaddr { get; } + } + + internal class elf_32_phdr : Ielf_phdr + { + public uint p_type => f_p_type; + public uint p_offset => f_p_offset; + public uint p_filesz => f_p_filesz; + public uint p_vaddr => f_p_vaddr; + + public uint f_p_type; + public uint f_p_offset; + public uint f_p_vaddr; public uint p_paddr; - public uint p_filesz; + public uint f_p_filesz; public uint p_memsz; public uint p_flags; public uint p_align; - //public byte[] p_data;忽略 } - internal class elf_32_shdr + internal class elf_64_phdr : Ielf_phdr + { + public uint p_type => f_p_type; + public ulong p_offset => f_p_offset; + public ulong p_filesz => f_p_filesz; + public ulong p_vaddr => f_p_vaddr; + + public uint f_p_type; + public uint p_flags; + public ulong f_p_offset; + public ulong f_p_vaddr; + public ulong p_paddr; + public ulong f_p_filesz; + public ulong p_memsz; + public ulong p_align; + } + + internal class elf_shdr where TWord : struct { public uint sh_name; public uint sh_type; - public uint sh_flags; - public uint sh_addr; - public uint sh_offset; - public uint sh_size; + public TWord sh_flags; + public TWord sh_addr; + public TWord sh_offset; + public TWord sh_size; public uint sh_link; public uint sh_info; - public uint sh_addralign; - public uint sh_entsize; + public TWord sh_addralign; + public TWord sh_entsize; } - internal class elf_32_sym + internal interface Ielf_sym where TWord : struct { - public uint st_name; - public uint st_value; + uint st_name { get; } + TWord st_value { get; } + } + + internal class elf_32_sym : Ielf_sym + { + public uint st_name => f_st_name; + public uint st_value => f_st_value; + + public uint f_st_name; + public uint f_st_value; public uint st_size; public byte st_info; public byte st_other; public ushort st_shndx; } - internal class elf_32_dynamic + internal class elf_64_sym : Ielf_sym { - public uint d_tag; - public uint d_un; + public uint st_name => f_st_name; + public ulong st_value => f_st_value; + + public uint f_st_name; + public byte st_info; + public byte st_other; + public ushort st_shndx; + public ulong f_st_value; + public ulong st_size; } - internal class elf_32_rel + internal class elf_dynamic where TWord : struct { - public uint r_offset; - public uint r_info; + public TWord d_tag; + public TWord d_un; } - internal class elf_32_rela + internal class elf_rel where TWord : struct { - public uint r_offset; - public uint r_info; - public uint r_addend; + public TWord r_offset; + public TWord r_info; + } + + internal class elf_rela where TWord : struct + { + public TWord r_offset; + public TWord r_info; + public TWord r_addend; } #pragma warning restore CS0649 } diff --git a/README.md b/README.md index ade79bb..7e4c246 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # Il2CppInspector Extract types, methods, properties and fields from Unity IL2CPP binaries. +* **No manual reverse-engineering required; all data is calculated automatically!** * Supports ELF (Android .so), PE (Windows .exe), Mach-O (Apple iOS/Mac) and Universal Binary (Fat Mach-O) file formats -* 64-bit support for Mach-O files +* 32-bit support for all file formats; 64-bit support for ELF and Mach-O file formats * Supports ARMv7, ARMv7 Thumb T1, ARMv8 (A64) and x86 architectures regardless of file format * Supports metadata versions 21, 22, 23, 24, 24.1 (Unity 2018.3+) and 24.2 (Unity 2019+) -* No manual reverse-engineering required; all data is calculated automatically * Support for classes, methods, fields, properties, enumerations, events, delegates, interfaces, structs and default field values * Static symbol table scanning for ELF and Mach-O binaries if present * Dynamic symbol table scanning for ELF binaries if present @@ -66,7 +66,7 @@ Thanks to the following individuals whose code and research helped me develop th - nevermoe - https://github.com/nevermoe/unity_metadata_loader - branw - https://github.com/branw/pogo-proto-dumper - fry - https://github.com/fry/d3 -- ARMConvertor - http://armconverter.com +- ARMConverter - http://armconverter.com This tool uses Perfare's Il2CppDumper code as a base.