MachO: Add ability to fetch exports with GetExports()
This commit is contained in:
@@ -25,6 +25,8 @@ namespace Il2CppInspector
|
|||||||
LC_DYSYMTAB = 0xb,
|
LC_DYSYMTAB = 0xb,
|
||||||
LC_SEGMENT_64 = 0x19,
|
LC_SEGMENT_64 = 0x19,
|
||||||
LC_ENCRYPTION_INFO = 0x21,
|
LC_ENCRYPTION_INFO = 0x21,
|
||||||
|
LC_DYLD_INFO = 0x22,
|
||||||
|
LC_DYLD_INFO_ONLY = 0x80000022,
|
||||||
LC_FUNCTION_STARTS = 0x26,
|
LC_FUNCTION_STARTS = 0x26,
|
||||||
LC_ENCRYPTION_INFO_64 = 0x2C,
|
LC_ENCRYPTION_INFO_64 = 0x2C,
|
||||||
|
|
||||||
@@ -90,6 +92,20 @@ namespace Il2CppInspector
|
|||||||
public uint Size;
|
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
|
internal class MachOSymtabCommand
|
||||||
{
|
{
|
||||||
public uint SymOffset;
|
public uint SymOffset;
|
||||||
|
|||||||
@@ -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.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
@@ -60,6 +60,8 @@ namespace Il2CppInspector
|
|||||||
private MachOSection<TWord> funcTab;
|
private MachOSection<TWord> funcTab;
|
||||||
private MachOSymtabCommand symTab;
|
private MachOSymtabCommand symTab;
|
||||||
|
|
||||||
|
private List<Export> exports = new List<Export>();
|
||||||
|
|
||||||
protected MachOReader(Stream stream) : base(stream) { }
|
protected MachOReader(Stream stream) : base(stream) { }
|
||||||
|
|
||||||
public override string Format => "Mach-O " + (Bits == 32 ? "32-bit" : "64-bit");
|
public override string Format => "Mach-O " + (Bits == 32 ? "32-bit" : "64-bit");
|
||||||
@@ -103,6 +105,8 @@ namespace Il2CppInspector
|
|||||||
// Segments
|
// Segments
|
||||||
case MachO cmd when cmd == lc_Segment:
|
case MachO cmd when cmd == lc_Segment:
|
||||||
var segment = ReadObject<MachOSegmentCommand<TWord>>();
|
var segment = ReadObject<MachOSegmentCommand<TWord>>();
|
||||||
|
|
||||||
|
// Code and data
|
||||||
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>>();
|
||||||
@@ -128,6 +132,14 @@ namespace Il2CppInspector
|
|||||||
// TODO: Implement Mach-O dynamic symbol table
|
// TODO: Implement Mach-O dynamic symbol table
|
||||||
break;
|
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
|
// Encryption check
|
||||||
// If cryptid == 1, this binary is encrypted with FairPlay DRM
|
// If cryptid == 1, this binary is encrypted with FairPlay DRM
|
||||||
case MachO.LC_ENCRYPTION_INFO:
|
case MachO.LC_ENCRYPTION_INFO:
|
||||||
@@ -159,6 +171,51 @@ namespace Il2CppInspector
|
|||||||
return true;
|
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 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() {
|
public override Dictionary<string, ulong> GetSymbolTable() {
|
||||||
@@ -180,7 +237,10 @@ namespace Il2CppInspector
|
|||||||
if (value != 0)
|
if (value != 0)
|
||||||
symbols.TryAdd(name, value);
|
symbols.TryAdd(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return symbols;
|
return symbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<Export> GetExports() => exports;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
Il2CppInspector.Common/ULEB128.cs
Normal file
23
Il2CppInspector.Common/ULEB128.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user