Add Mach-O static symbol table analysis

This commit is contained in:
Katy Coe
2019-10-22 22:19:12 +02:00
parent 98d573d1c6
commit 490736f68e
3 changed files with 79 additions and 25 deletions

View File

@@ -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. All rights reserved.
*/ */
@@ -21,6 +21,8 @@ namespace Il2CppInspector
MH_EXECUTE = 0x2, MH_EXECUTE = 0x2,
LC_SEGMENT = 0x1, LC_SEGMENT = 0x1,
LC_SYMTAB = 0x2,
LC_DYSYMTAB = 0xb,
LC_SEGMENT_64 = 0x19, LC_SEGMENT_64 = 0x19,
LC_FUNCTION_STARTS = 0x26, LC_FUNCTION_STARTS = 0x26,
@@ -85,4 +87,21 @@ namespace Il2CppInspector
public uint Offset; public uint Offset;
public uint Size; public uint Size;
} }
internal class MachOSymtabCommand
{
public uint SymOffset;
public uint NumSyms;
public uint StrOffset;
public uint StrSize;
}
internal class MachO_nlist<TWord> where TWord : struct
{
public uint n_strx;
public byte n_type;
public byte n_sect;
public ushort n_desc;
public TWord n_value;
}
} }

View File

@@ -43,8 +43,8 @@ namespace Il2CppInspector
{ {
private MachOHeader<TWord> header; private MachOHeader<TWord> header;
private readonly List<MachOSection<TWord>> sections = new List<MachOSection<TWord>>(); private readonly List<MachOSection<TWord>> sections = new List<MachOSection<TWord>>();
private uint pFuncTable; private MachOLinkEditDataCommand funcTab;
private uint sFuncTable; private MachOSymtabCommand symTab;
protected MachOReader(Stream stream) : base(stream) { } protected MachOReader(Stream stream) : base(stream) { }
@@ -79,28 +79,41 @@ namespace Il2CppInspector
if ((MachO)header.FileType != MachO.MH_EXECUTE) if ((MachO)header.FileType != MachO.MH_EXECUTE)
return false; return false;
MachOLinkEditDataCommand functionStarts = null;
// Process load commands // Process load commands
for (var c = 0; c < header.NumCommands; c++) { for (var c = 0; c < header.NumCommands; c++) {
var startPos = Position; var startPos = Position;
var loadCommand = ReadObject<MachOLoadCommand>(); var loadCommand = ReadObject<MachOLoadCommand>();
if ((MachO)loadCommand.Command == lc_Segment) { switch ((MachO) loadCommand.Command) {
// Segments
case MachO cmd when cmd == lc_Segment:
var segment = ReadObject<MachOSegmentCommand<TWord>>(); var segment = ReadObject<MachOSegmentCommand<TWord>>();
if (segment.Name == "__TEXT" || segment.Name == "__DATA") { if (segment.Name == "__TEXT" || segment.Name == "__DATA") {
for (int s = 0; s < segment.NumSections; s++) { for (int s = 0; s < segment.NumSections; s++) {
var section = ReadObject<MachOSection<TWord>>(); var section = ReadObject<MachOSection<TWord>>();
sections.Add(section); sections.Add(section);
if (section.Name == "__text") { if (section.Name == "__text") {
GlobalOffset = (ulong)Convert.ChangeType(section.Address, typeof(ulong)) - section.ImageOffset; GlobalOffset = (ulong) Convert.ChangeType(section.Address, typeof(ulong)) -
} section.ImageOffset;
} }
} }
} }
break;
if ((MachO)loadCommand.Command == MachO.LC_FUNCTION_STARTS) { // Location of function table
functionStarts = ReadObject<MachOLinkEditDataCommand>(); case MachO.LC_FUNCTION_STARTS:
funcTab = ReadObject<MachOLinkEditDataCommand>();
break;
// Location of static symbol table
case MachO.LC_SYMTAB:
symTab = ReadObject<MachOSymtabCommand>();
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 // 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 // Must find LC_FUNCTION_STARTS load command
if (functionStarts == null) return (funcTab != null);
return false;
pFuncTable = functionStarts.Offset;
sFuncTable = functionStarts.Size;
return true;
} }
public override uint[] GetFunctionTable() { public override uint[] GetFunctionTable() {
Position = pFuncTable; Position = funcTab.Offset;
var functionPointers = new List<uint>(); var functionPointers = new List<uint>();
// Decompress ELB128 list of function offsets // Decompress ELB128 list of function offsets
// https://en.wikipedia.org/wiki/LEB128 // https://en.wikipedia.org/wiki/LEB128
uint previous = 0; uint previous = 0;
while (Position < pFuncTable + sFuncTable) { while (Position < funcTab.Offset + funcTab.Size) {
uint result = 0; uint result = 0;
int shift = 0; int shift = 0;
byte b; byte b;
@@ -142,6 +150,28 @@ namespace Il2CppInspector
return functionPointers.ToArray(); return functionPointers.ToArray();
} }
public override Dictionary<string, ulong> GetSymbolTable() {
var symbols = new Dictionary<string, ulong>();
// 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<MachO_nlist<TWord>>(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) { 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); 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)); return (uint) (uiAddr - ((ulong) Convert.ChangeType(section.Address, typeof(ulong)) - section.ImageOffset));

View File

@@ -75,6 +75,11 @@ namespace Il2CppInspector
symbols.TryGetValue("g_CodeRegistration", out var code); symbols.TryGetValue("g_CodeRegistration", out var code);
symbols.TryGetValue("g_MetadataRegistration", out var metadata); 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) { if (code != 0 && metadata != 0) {
Console.WriteLine("Required structures acquired from symbol lookup"); Console.WriteLine("Required structures acquired from symbol lookup");
Configure(subImage, code, metadata); Configure(subImage, code, metadata);