diff --git a/Il2CppInspector/FileFormatReaders/FormatLayouts/MachO.cs b/Il2CppInspector/FileFormatReaders/FormatLayouts/MachO.cs index 1b1ebe5..cac1106 100644 --- a/Il2CppInspector/FileFormatReaders/FormatLayouts/MachO.cs +++ b/Il2CppInspector/FileFormatReaders/FormatLayouts/MachO.cs @@ -1,5 +1,5 @@ /* - 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. */ @@ -21,6 +21,8 @@ namespace Il2CppInspector MH_EXECUTE = 0x2, LC_SEGMENT = 0x1, + LC_SYMTAB = 0x2, + LC_DYSYMTAB = 0xb, LC_SEGMENT_64 = 0x19, LC_FUNCTION_STARTS = 0x26, @@ -85,4 +87,21 @@ namespace Il2CppInspector public uint Offset; public uint Size; } + + internal class MachOSymtabCommand + { + public uint SymOffset; + public uint NumSyms; + public uint StrOffset; + public uint StrSize; + } + + internal class MachO_nlist where TWord : struct + { + public uint n_strx; + public byte n_type; + public byte n_sect; + public ushort n_desc; + public TWord n_value; + } } diff --git a/Il2CppInspector/FileFormatReaders/MachOReader.cs b/Il2CppInspector/FileFormatReaders/MachOReader.cs index c32dad5..7660368 100644 --- a/Il2CppInspector/FileFormatReaders/MachOReader.cs +++ b/Il2CppInspector/FileFormatReaders/MachOReader.cs @@ -43,8 +43,8 @@ namespace Il2CppInspector { private MachOHeader header; private readonly List> sections = new List>(); - private uint pFuncTable; - private uint sFuncTable; + private MachOLinkEditDataCommand funcTab; + private MachOSymtabCommand symTab; protected MachOReader(Stream stream) : base(stream) { } @@ -79,28 +79,41 @@ namespace Il2CppInspector if ((MachO)header.FileType != MachO.MH_EXECUTE) return false; - MachOLinkEditDataCommand functionStarts = null; - // Process load commands for (var c = 0; c < header.NumCommands; c++) { var startPos = Position; var loadCommand = ReadObject(); - if ((MachO)loadCommand.Command == lc_Segment) { - var segment = ReadObject>(); - if (segment.Name == "__TEXT" || segment.Name == "__DATA") { - for (int s = 0; s < segment.NumSections; s++) { - var section = ReadObject>(); - sections.Add(section); - if (section.Name == "__text") { - GlobalOffset = (ulong)Convert.ChangeType(section.Address, typeof(ulong)) - section.ImageOffset; + switch ((MachO) loadCommand.Command) { + + // Segments + case MachO cmd when cmd == lc_Segment: + var segment = ReadObject>(); + if (segment.Name == "__TEXT" || segment.Name == "__DATA") { + for (int s = 0; s < segment.NumSections; s++) { + var section = ReadObject>(); + sections.Add(section); + if (section.Name == "__text") { + GlobalOffset = (ulong) Convert.ChangeType(section.Address, typeof(ulong)) - + section.ImageOffset; + } } } - } - } + break; - if ((MachO)loadCommand.Command == MachO.LC_FUNCTION_STARTS) { - functionStarts = ReadObject(); + // Location of function table + case MachO.LC_FUNCTION_STARTS: + funcTab = ReadObject(); + break; + + // Location of static symbol table + case MachO.LC_SYMTAB: + symTab = ReadObject(); + break; + + case MachO.LC_DYSYMTAB: + // TODO: Implement Mach-O dynamic symbol table + break; } // There might be other data after the load command so always use the specified total size to step forwards @@ -108,22 +121,17 @@ namespace Il2CppInspector } // Must find LC_FUNCTION_STARTS load command - if (functionStarts == null) - return false; - - pFuncTable = functionStarts.Offset; - sFuncTable = functionStarts.Size; - return true; + return (funcTab != null); } public override uint[] GetFunctionTable() { - Position = pFuncTable; + Position = funcTab.Offset; var functionPointers = new List(); // Decompress ELB128 list of function offsets // https://en.wikipedia.org/wiki/LEB128 uint previous = 0; - while (Position < pFuncTable + sFuncTable) { + while (Position < funcTab.Offset + funcTab.Size) { uint result = 0; int shift = 0; byte b; @@ -142,6 +150,28 @@ namespace Il2CppInspector return functionPointers.ToArray(); } + public override Dictionary GetSymbolTable() { + var symbols = new Dictionary(); + + // https://opensource.apple.com/source/cctools/cctools-795/include/mach-o/nlist.h + // n_sect: https://opensource.apple.com/source/cctools/cctools-795/include/mach-o/stab.h + + var symbolList = ReadArray>(symTab.SymOffset, (int) symTab.NumSyms); + + // This is a really naive implementation that ignores the values of n_type and n_sect + // which may affect the interpretation of n_value + foreach (var symbol in symbolList) { + Position = symTab.StrOffset + symbol.n_strx; + var name = (symbol.n_strx != 0) ? ReadNullTerminatedString() : ""; + var value = (ulong) Convert.ChangeType(symbol.n_value, typeof(ulong)); + + // Ignore duplicates for now, also ignore symbols with no address + if (value != 0) + symbols.TryAdd(name, value); + } + return symbols; + } + public override uint MapVATR(ulong uiAddr) { var section = sections.First(x => uiAddr >= (uint)(object)x.Address && uiAddr <= (uint)(object)x.Address + (uint)(object)x.Size); return (uint) (uiAddr - ((ulong) Convert.ChangeType(section.Address, typeof(ulong)) - section.ImageOffset)); diff --git a/Il2CppInspector/Il2CppBinary.cs b/Il2CppInspector/Il2CppBinary.cs index 79cb964..7797f10 100644 --- a/Il2CppInspector/Il2CppBinary.cs +++ b/Il2CppInspector/Il2CppBinary.cs @@ -75,6 +75,11 @@ namespace Il2CppInspector symbols.TryGetValue("g_CodeRegistration", out var code); symbols.TryGetValue("g_MetadataRegistration", out var metadata); + if (code == 0) + symbols.TryGetValue("_g_CodeRegistration", out code); + if (metadata == 0) + symbols.TryGetValue("_g_MetadataRegistration", out metadata); + if (code != 0 && metadata != 0) { Console.WriteLine("Required structures acquired from symbol lookup"); Configure(subImage, code, metadata);