MachO: Add ability to fetch exports with GetExports()

This commit is contained in:
Katy Coe
2020-07-18 19:05:15 +02:00
parent 67b979cd05
commit e74663a2ba
3 changed files with 100 additions and 1 deletions

View File

@@ -25,6 +25,8 @@ namespace Il2CppInspector
LC_DYSYMTAB = 0xb,
LC_SEGMENT_64 = 0x19,
LC_ENCRYPTION_INFO = 0x21,
LC_DYLD_INFO = 0x22,
LC_DYLD_INFO_ONLY = 0x80000022,
LC_FUNCTION_STARTS = 0x26,
LC_ENCRYPTION_INFO_64 = 0x2C,
@@ -90,6 +92,20 @@ namespace Il2CppInspector
public uint Size;
}
internal class MachODyldInfoCommand
{
public uint RebaseOffset;
public uint RebaseSize;
public uint BindOffset;
public uint BindSize;
public uint WeakBindOffset;
public uint WeakBindSize;
public uint LazyBindOffset;
public uint LazyBindSize;
public uint ExportOffset;
public uint ExportSize;
}
internal class MachOSymtabCommand
{
public uint SymOffset;

View File

@@ -1,5 +1,5 @@
/*
Copyright 2017-2020 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
Copyright 2017-2020 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
All rights reserved.
*/
@@ -60,6 +60,8 @@ namespace Il2CppInspector
private MachOSection<TWord> funcTab;
private MachOSymtabCommand symTab;
private List<Export> exports = new List<Export>();
protected MachOReader(Stream stream) : base(stream) { }
public override string Format => "Mach-O " + (Bits == 32 ? "32-bit" : "64-bit");
@@ -103,6 +105,8 @@ namespace Il2CppInspector
// Segments
case MachO cmd when cmd == lc_Segment:
var segment = ReadObject<MachOSegmentCommand<TWord>>();
// Code and data
if (segment.Name == "__TEXT" || segment.Name == "__DATA") {
for (int s = 0; s < segment.NumSections; s++) {
var section = ReadObject<MachOSection<TWord>>();
@@ -128,6 +132,14 @@ namespace Il2CppInspector
// TODO: Implement Mach-O dynamic symbol table
break;
// Compressed dyld information
case MachO.LC_DYLD_INFO:
case MachO.LC_DYLD_INFO_ONLY:
var dyld = ReadObject<MachODyldInfoCommand>();
loadExportTrie(dyld.ExportOffset);
break;
// Encryption check
// If cryptid == 1, this binary is encrypted with FairPlay DRM
case MachO.LC_ENCRYPTION_INFO:
@@ -159,6 +171,51 @@ namespace Il2CppInspector
return true;
}
// Handle export trie
private void loadExportTrie(uint trieOffset, uint nodeOffset = 0, string partialSymbol = "") {
Position = trieOffset + nodeOffset;
var size = ULEB128.Decode(this);
// Terminal information
if (size != 0) {
var flags = ReadByte();
var symbolKind = flags & 0x03;
var symbolType = (flags >> 2) & 0x03;
// 0 = regular, 1 = weak, 2 = re-export, 3 = stub
switch (symbolType) {
case 0:
var address = ULEB128.Decode(this);
exports.Add(new Export {Name = partialSymbol, VirtualAddress = GlobalOffset + address});
break;
case 1:
var weakAddress = ULEB128.Decode(this);
exports.Add(new Export {Name = partialSymbol, VirtualAddress = GlobalOffset + weakAddress});
break;
case 2:
var ordinal = ULEB128.Decode(this);
var name = ReadNullTerminatedString();
break;
case 3:
var stubOffset = ULEB128.Decode(this);
var resolverOffset = ULEB128.Decode(this);
break;
}
}
var branchCount = ReadByte();
for (int branch = 0; branch < branchCount; branch++) {
var prefix = ReadNullTerminatedString();
var childNodeOffset = (uint) ULEB128.Decode(this);
var currentPosition = Position;
loadExportTrie(trieOffset, childNodeOffset, partialSymbol + prefix);
Position = currentPosition;
}
}
public override uint[] GetFunctionTable() => ReadArray<TWord>(funcTab.ImageOffset, conv.Int(funcTab.Size) / (Bits / 8)).Select(x => MapVATR(conv.ULong(x)) & 0xffff_fffe).ToArray();
public override Dictionary<string, ulong> GetSymbolTable() {
@@ -180,7 +237,10 @@ namespace Il2CppInspector
if (value != 0)
symbols.TryAdd(name, value);
}
return symbols;
}
public override IEnumerable<Export> GetExports() => exports;
}
}

View File

@@ -0,0 +1,23 @@
/*
Copyright 2020 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
All rights reserved.
*/
using System.IO;
namespace Il2CppInspector
{
internal class ULEB128
{
public static ulong Decode(IFileFormatReader next) {
ulong uleb = 0;
byte b = 0x80;
for (var shift = 0; b >> 7 == 1; shift += 7) {
b = next.ReadByte();
uleb |= (ulong) (b & 0x7f) << shift;
}
return uleb;
}
}
}