Add Mach-O static symbol table analysis
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user