Add 64-bit Mach-O support
This commit is contained in:
@@ -30,7 +30,7 @@ namespace Il2CppInspector
|
|||||||
CPU_TYPE_ARM64 = 0x01000000 + CPU_TYPE_ARM
|
CPU_TYPE_ARM64 = 0x01000000 + CPU_TYPE_ARM
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MachOHeader
|
internal class MachOHeader<TWord> where TWord : struct
|
||||||
{
|
{
|
||||||
public uint Magic;
|
public uint Magic;
|
||||||
public uint CPUType;
|
public uint CPUType;
|
||||||
@@ -38,8 +38,7 @@ namespace Il2CppInspector
|
|||||||
public uint FileType;
|
public uint FileType;
|
||||||
public uint NumCommands;
|
public uint NumCommands;
|
||||||
public uint SizeOfCommands;
|
public uint SizeOfCommands;
|
||||||
public uint Flags;
|
public TWord Flags;
|
||||||
// 64-bit header has an extra 32-bit Reserved field
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MachOLoadCommand
|
internal class MachOLoadCommand
|
||||||
@@ -48,69 +47,36 @@ namespace Il2CppInspector
|
|||||||
public uint Size;
|
public uint Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MachOSegmentCommand
|
internal class MachOSegmentCommand<TWord> where TWord : struct
|
||||||
{
|
{
|
||||||
// MachOLoadCommand
|
// MachOLoadCommand
|
||||||
[String(FixedSize = 16)]
|
[String(FixedSize = 16)]
|
||||||
public string Name;
|
public string Name;
|
||||||
public uint VirtualAddress;
|
public TWord VirtualAddress;
|
||||||
public uint VirtualSize;
|
public TWord VirtualSize;
|
||||||
public uint ImageOffset;
|
public TWord ImageOffset;
|
||||||
public uint ImageSize;
|
public TWord ImageSize;
|
||||||
public uint VMMaxProt;
|
public uint VMMaxProt;
|
||||||
public uint VMInitProt;
|
public uint VMInitProt;
|
||||||
public uint NumSections;
|
public uint NumSections;
|
||||||
public uint Flags;
|
public uint Flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MachOSegmentCommand64
|
internal class MachOSection<TWord> where TWord : struct
|
||||||
{
|
|
||||||
// MachOLoadCommand
|
|
||||||
[String(FixedSize = 16)]
|
|
||||||
public string Name;
|
|
||||||
public ulong VirtualAddress;
|
|
||||||
public ulong VirtualSize;
|
|
||||||
public ulong ImageOffset;
|
|
||||||
public ulong ImageSize;
|
|
||||||
public uint VMMaxProt;
|
|
||||||
public uint VMInitProt;
|
|
||||||
public uint NumSections;
|
|
||||||
public uint Flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class MachOSection
|
|
||||||
{
|
{
|
||||||
[String(FixedSize = 16)]
|
[String(FixedSize = 16)]
|
||||||
public string Name;
|
public string Name;
|
||||||
[String(FixedSize = 16)]
|
[String(FixedSize = 16)]
|
||||||
public string SegmentName;
|
public string SegmentName;
|
||||||
public uint Address;
|
public TWord Address;
|
||||||
public uint Size;
|
public TWord Size;
|
||||||
public uint ImageOffset;
|
public uint ImageOffset;
|
||||||
public uint Align;
|
public uint Align;
|
||||||
public uint ImageRelocOffset;
|
public uint ImageRelocOffset;
|
||||||
public uint NumRelocEntries;
|
public uint NumRelocEntries;
|
||||||
public uint Flags;
|
public uint Flags;
|
||||||
public uint Reserved1;
|
public uint Reserved1;
|
||||||
public uint Reserved2;
|
public TWord Reserved2;
|
||||||
}
|
|
||||||
|
|
||||||
internal class MachOSection64
|
|
||||||
{
|
|
||||||
[String(FixedSize = 16)]
|
|
||||||
public string Name;
|
|
||||||
[String(FixedSize = 16)]
|
|
||||||
public string SegmentName;
|
|
||||||
public ulong Address;
|
|
||||||
public ulong Size;
|
|
||||||
public uint ImageOffset;
|
|
||||||
public uint Align;
|
|
||||||
public uint ImageRelocOffset;
|
|
||||||
public uint NumRelocEntries;
|
|
||||||
public uint Flags;
|
|
||||||
public uint Reserved1;
|
|
||||||
public uint Reserved2;
|
|
||||||
public uint Reserved3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MachOLinkEditDataCommand
|
internal class MachOLinkEditDataCommand
|
||||||
|
|||||||
@@ -13,20 +13,45 @@ using NoisyCowStudios.Bin2Object;
|
|||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
internal class MachOReader : FileFormatReader<MachOReader>
|
internal class MachOReader32 : MachOReader<uint, MachOReader32>
|
||||||
{
|
{
|
||||||
private MachOHeader header;
|
public MachOReader32(Stream stream) : base(stream) { }
|
||||||
|
|
||||||
|
public override int Bits => 32;
|
||||||
|
|
||||||
|
protected override bool checkMagicLE(MachO magic) => magic == MachO.MH_MAGIC;
|
||||||
|
protected override bool checkMagicBE(MachO magic) => magic == MachO.MH_CIGAM;
|
||||||
|
|
||||||
|
protected override MachO lc_Segment => MachO.LC_SEGMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class MachOReader64 : MachOReader<ulong, MachOReader64>
|
||||||
|
{
|
||||||
|
public MachOReader64(Stream stream) : base(stream) { }
|
||||||
|
|
||||||
|
public override int Bits => 64;
|
||||||
|
|
||||||
|
protected override bool checkMagicLE(MachO magic) => magic == MachO.MH_MAGIC_64;
|
||||||
|
protected override bool checkMagicBE(MachO magic) => magic == MachO.MH_CIGAM_64;
|
||||||
|
|
||||||
|
protected override MachO lc_Segment => MachO.LC_SEGMENT_64;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need this convoluted generic TReader declaration so that "static T FileFormatReader.Load(Stream)"
|
||||||
|
// is inherited to MachOReader32/64 with a correct definition of T
|
||||||
|
internal abstract class MachOReader<TWord, TReader> : FileFormatReader<TReader> where TWord : struct where TReader : FileFormatReader<TReader>
|
||||||
|
{
|
||||||
|
private MachOHeader<TWord> header;
|
||||||
|
private readonly List<MachOSection<TWord>> sections = new List<MachOSection<TWord>>();
|
||||||
private uint pFuncTable;
|
private uint pFuncTable;
|
||||||
private uint sFuncTable;
|
private uint sFuncTable;
|
||||||
private bool is64;
|
|
||||||
private List<MachOSection> sections = new List<MachOSection>();
|
|
||||||
private List<MachOSection64> sections64 = new List<MachOSection64>();
|
|
||||||
|
|
||||||
public MachOReader(Stream stream) : base(stream) { }
|
protected MachOReader(Stream stream) : base(stream) { }
|
||||||
|
|
||||||
public override string Format => "Mach-O";
|
public override string Format => "Mach-O";
|
||||||
|
|
||||||
public override string Arch => (MachO)header.CPUType switch {
|
public override string Arch => (MachO)header.CPUType switch
|
||||||
|
{
|
||||||
MachO.CPU_TYPE_ARM => "ARM",
|
MachO.CPU_TYPE_ARM => "ARM",
|
||||||
MachO.CPU_TYPE_ARM64 => "ARM64",
|
MachO.CPU_TYPE_ARM64 => "ARM64",
|
||||||
MachO.CPU_TYPE_X86 => "x86",
|
MachO.CPU_TYPE_X86 => "x86",
|
||||||
@@ -34,57 +59,42 @@ namespace Il2CppInspector
|
|||||||
_ => "Unsupported"
|
_ => "Unsupported"
|
||||||
};
|
};
|
||||||
|
|
||||||
public override int Bits => is64 ? 64 : 32;
|
protected abstract bool checkMagicLE(MachO magic);
|
||||||
|
protected abstract bool checkMagicBE(MachO magic);
|
||||||
|
protected abstract MachO lc_Segment { get; }
|
||||||
|
|
||||||
protected override bool Init() {
|
protected override bool Init() {
|
||||||
// Detect endianness - default is little-endianness
|
// Detect endianness - default is little-endianness
|
||||||
MachO magic = (MachO)ReadUInt32();
|
MachO magic = (MachO)ReadUInt32();
|
||||||
if (magic == MachO.MH_CIGAM || magic == MachO.MH_CIGAM_64) {
|
|
||||||
|
if (checkMagicBE(magic))
|
||||||
Endianness = Endianness.Big;
|
Endianness = Endianness.Big;
|
||||||
}
|
|
||||||
else if (magic != MachO.MH_MAGIC && magic != MachO.MH_MAGIC_64) {
|
if (!checkMagicBE(magic) && !checkMagicLE(magic))
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Position -= sizeof(uint);
|
header = ReadObject<MachOHeader<TWord>>(0);
|
||||||
header = ReadObject<MachOHeader>();
|
|
||||||
|
|
||||||
// 64-bit files have an extra 4 bytes after the header
|
|
||||||
is64 = false;
|
|
||||||
if (magic == MachO.MH_MAGIC_64) {
|
|
||||||
is64 = true;
|
|
||||||
ReadUInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must be executable file
|
// Must be executable file
|
||||||
if ((MachO) header.FileType != MachO.MH_EXECUTE)
|
if ((MachO)header.FileType != MachO.MH_EXECUTE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MachOLinkEditDataCommand functionStarts = null;
|
MachOLinkEditDataCommand functionStarts = null;
|
||||||
|
|
||||||
|
// 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 == MachO.LC_SEGMENT) {
|
if ((MachO)loadCommand.Command == lc_Segment) {
|
||||||
var segment = ReadObject<MachOSegmentCommand>();
|
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>();
|
var section = ReadObject<MachOSection<TWord>>();
|
||||||
sections.Add(section);
|
sections.Add(section);
|
||||||
if (section.Name == "__text")
|
if (section.Name == "__text") {
|
||||||
GlobalOffset = section.Address - section.ImageOffset;
|
GlobalOffset = (ulong)Convert.ChangeType(section.Address, typeof(ulong)) - section.ImageOffset;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((MachO)loadCommand.Command == MachO.LC_SEGMENT_64) {
|
|
||||||
var segment = ReadObject<MachOSegmentCommand64>();
|
|
||||||
if (segment.Name == "__TEXT" || segment.Name == "__DATA") {
|
|
||||||
for (int s = 0; s < segment.NumSections; s++) {
|
|
||||||
var section64 = ReadObject<MachOSection64>();
|
|
||||||
sections64.Add(section64);
|
|
||||||
if (section64.Name == "__text")
|
|
||||||
GlobalOffset = (uint)section64.Address - section64.ImageOffset;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,12 +143,8 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override uint MapVATR(ulong uiAddr) {
|
public override uint MapVATR(ulong uiAddr) {
|
||||||
if (!is64) {
|
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 >= x.Address && uiAddr <= (x.Address + x.Size));
|
return (uint) (uiAddr - ((ulong) Convert.ChangeType(section.Address, typeof(ulong)) - section.ImageOffset));
|
||||||
return (uint) (uiAddr - (section.Address - section.ImageOffset));
|
|
||||||
}
|
|
||||||
var section64 = sections64.First(x => uiAddr >= x.Address && uiAddr <= (x.Address + x.Size));
|
|
||||||
return (uint) (uiAddr - ((uint)section64.Address - section64.ImageOffset));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
*/
|
*/
|
||||||
@@ -37,7 +37,8 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
Position = arch.Offset;
|
Position = arch.Offset;
|
||||||
Endianness = Endianness.Little;
|
Endianness = Endianness.Little;
|
||||||
return MachOReader.Load(new MemoryStream(ReadBytes((int)arch.Size)));
|
var s = new MemoryStream(ReadBytes((int) arch.Size));
|
||||||
|
return (IFileFormatReader) MachOReader32.Load(s) ?? MachOReader64.Load(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
Extract types, methods, properties and fields from Unity IL2CPP binaries.
|
Extract types, methods, properties and fields from Unity IL2CPP binaries.
|
||||||
|
|
||||||
* Supports ELF (Android .so), PE (Windows .exe), Mach-O (Apple iOS/Mac) and Universal Binary (Fat Mach-O) file formats
|
* Supports ELF (Android .so), PE (Windows .exe), Mach-O (Apple iOS/Mac) and Universal Binary (Fat Mach-O) file formats
|
||||||
|
* 64-bit support for Mach-O files
|
||||||
* Supports ARMv7, ARMv7 Thumb T1 and x86 architectures regardless of file format
|
* Supports ARMv7, ARMv7 Thumb T1 and x86 architectures regardless of file format
|
||||||
* Supports metadata versions 21, 22, 23, 24, 24.1 (Unity 2018.3+) and 24.2 (Unity 2019+)
|
* Supports metadata versions 21, 22, 23, 24, 24.1 (Unity 2018.3+) and 24.2 (Unity 2019+)
|
||||||
* No manual reverse-engineering required; all data is calculated automatically
|
* No manual reverse-engineering required; all data is calculated automatically
|
||||||
|
|||||||
Reference in New Issue
Block a user