Add Fat Mach-O (Universal Binary) support
Fix fieldOffsets bug in some metadata versions Add support for generic multi-architecture binaries Add Mach-O section RVA mapping
This commit is contained in:
@@ -43,7 +43,7 @@ namespace Il2CppInspector
|
||||
var fieldEnd = typeDef.fieldStart + typeDef.field_count;
|
||||
for (int i = typeDef.fieldStart; i < fieldEnd; ++i) {
|
||||
var pField = metadata.Fields[i];
|
||||
var pType = il2cpp.Code.GetTypeFromTypeIndex(pField.typeIndex);
|
||||
var pType = il2cpp.GetTypeFromTypeIndex(pField.typeIndex);
|
||||
var pDefault = metadata.GetFieldDefaultFromIndex(i);
|
||||
writer.Write("\t");
|
||||
if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_PRIVATE) ==
|
||||
@@ -59,7 +59,7 @@ namespace Il2CppInspector
|
||||
writer.Write($"{il2cpp.GetTypeName(pType)} {metadata.GetString(pField.nameIndex)}");
|
||||
if (pDefault != null && pDefault.dataIndex != -1) {
|
||||
var pointer = metadata.GetDefaultValueFromIndex(pDefault.dataIndex);
|
||||
Il2CppType pTypeToUse = il2cpp.Code.GetTypeFromTypeIndex(pDefault.typeIndex);
|
||||
Il2CppType pTypeToUse = il2cpp.GetTypeFromTypeIndex(pDefault.typeIndex);
|
||||
if (pointer > 0) {
|
||||
metadata.Position = pointer;
|
||||
object multi = null;
|
||||
@@ -110,14 +110,14 @@ namespace Il2CppInspector
|
||||
}
|
||||
}
|
||||
writer.Write("; // 0x{0:x}\n",
|
||||
il2cpp.Code.GetFieldOffsetFromIndex(idx, i - typeDef.fieldStart));
|
||||
il2cpp.GetFieldOffsetFromIndex(idx, i - typeDef.fieldStart));
|
||||
}
|
||||
writer.Write("\t// Methods\n");
|
||||
var methodEnd = typeDef.methodStart + typeDef.method_count;
|
||||
for (int i = typeDef.methodStart; i < methodEnd; ++i) {
|
||||
var methodDef = metadata.Methods[i];
|
||||
writer.Write("\t");
|
||||
Il2CppType pReturnType = il2cpp.Code.GetTypeFromTypeIndex(methodDef.returnType);
|
||||
Il2CppType pReturnType = il2cpp.GetTypeFromTypeIndex(methodDef.returnType);
|
||||
if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) ==
|
||||
DefineConstants.METHOD_ATTRIBUTE_PRIVATE)
|
||||
writer.Write("private ");
|
||||
@@ -133,7 +133,7 @@ namespace Il2CppInspector
|
||||
for (int j = 0; j < methodDef.parameterCount; ++j) {
|
||||
Il2CppParameterDefinition pParam = metadata.parameterDefs[methodDef.parameterStart + j];
|
||||
string szParamName = metadata.GetString(pParam.nameIndex);
|
||||
Il2CppType pType = il2cpp.Code.GetTypeFromTypeIndex(pParam.typeIndex);
|
||||
Il2CppType pType = il2cpp.GetTypeFromTypeIndex(pParam.typeIndex);
|
||||
string szTypeName = il2cpp.GetTypeName(pType);
|
||||
if ((pType.attrs & DefineConstants.PARAM_ATTRIBUTE_OPTIONAL) != 0)
|
||||
writer.Write("optional ");
|
||||
|
||||
@@ -40,13 +40,14 @@ namespace Il2CppInspector
|
||||
}
|
||||
|
||||
// Analyze data
|
||||
var il2cpp = Il2CppProcessor.LoadFromFile(imageFile, metaFile);
|
||||
if (il2cpp == null)
|
||||
var il2cppProcessors = Il2CppProcessor.LoadFromFile(imageFile, metaFile);
|
||||
if (il2cppProcessors == null)
|
||||
Environment.Exit(1);
|
||||
|
||||
// Write output file
|
||||
var dumper = new Il2CppDumper(il2cpp);
|
||||
dumper.WriteFile(outFile);
|
||||
int i = 0;
|
||||
foreach (var il2cpp in il2cppProcessors)
|
||||
new Il2CppDumper(il2cpp).WriteFile(outFile + "-" + (i++));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
|
||||
namespace Il2CppInspector
|
||||
@@ -13,6 +15,9 @@ namespace Il2CppInspector
|
||||
public interface IFileFormatReader
|
||||
{
|
||||
BinaryObjectReader Stream { get; }
|
||||
uint NumImages { get; }
|
||||
IEnumerable<IFileFormatReader> Images { get; }
|
||||
IFileFormatReader this[uint index] { get; }
|
||||
long Position { get; set; }
|
||||
string Arch { get; }
|
||||
uint GlobalOffset { get; }
|
||||
@@ -35,17 +40,26 @@ namespace Il2CppInspector
|
||||
|
||||
public BinaryObjectReader Stream => this;
|
||||
|
||||
public uint NumImages { get; protected set; } = 1;
|
||||
|
||||
public uint GlobalOffset { get; protected set; }
|
||||
|
||||
public virtual string Arch => throw new NotImplementedException();
|
||||
|
||||
public static T Load(string filename, uint offset = 0) {
|
||||
using (var stream = new FileStream(filename, FileMode.Open))
|
||||
return Load(stream, offset);
|
||||
public IEnumerable<IFileFormatReader> Images {
|
||||
get {
|
||||
for (uint i = 0; i < NumImages; i++)
|
||||
yield return this[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static T Load(Stream stream, uint offset = 0) {
|
||||
stream.Position = offset;
|
||||
public static T Load(string filename) {
|
||||
using (var stream = new FileStream(filename, FileMode.Open))
|
||||
return Load(stream);
|
||||
}
|
||||
|
||||
public static T Load(Stream stream) {
|
||||
stream.Position = 0;
|
||||
var pe = (T) Activator.CreateInstance(typeof(T), stream);
|
||||
return pe.Init() ? pe : null;
|
||||
}
|
||||
@@ -53,11 +67,21 @@ namespace Il2CppInspector
|
||||
// Confirm file is valid and set up RVA mappings
|
||||
protected virtual bool Init() => throw new NotImplementedException();
|
||||
|
||||
// Choose a sub-binary within the image for multi-architecture binaries
|
||||
public virtual IFileFormatReader this[uint index] {
|
||||
get {
|
||||
if (index == 0)
|
||||
return this;
|
||||
throw new IndexOutOfRangeException("Binary image index out of bounds");
|
||||
}
|
||||
}
|
||||
|
||||
// Find search locations in the machine code for Il2Cpp data
|
||||
public virtual uint[] GetSearchLocations() => throw new NotImplementedException();
|
||||
|
||||
|
||||
// Map an RVA to an offset into the file image
|
||||
public virtual uint MapVATR(uint uiAddr) => throw new NotImplementedException();
|
||||
// No mapping by default
|
||||
public virtual uint MapVATR(uint uiAddr) => uiAddr;
|
||||
|
||||
// Retrieve object(s) from specified RVA(s)
|
||||
public U ReadMappedObject<U>(uint uiAddr) where U : new() {
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Il2CppInspector
|
||||
Metadata = metadata;
|
||||
}
|
||||
|
||||
public static Il2CppProcessor LoadFromFile(string codeFile, string metadataFile) {
|
||||
public static List<Il2CppProcessor> LoadFromFile(string codeFile, string metadataFile) {
|
||||
// Load the metadata file
|
||||
Metadata metadata;
|
||||
try {
|
||||
@@ -34,36 +34,41 @@ namespace Il2CppInspector
|
||||
// Load the il2cpp code file (try ELF and PE)
|
||||
var memoryStream = new MemoryStream(File.ReadAllBytes(codeFile));
|
||||
IFileFormatReader stream =
|
||||
((IFileFormatReader) ElfReader.Load(memoryStream) ??
|
||||
PEReader.Load(memoryStream)) ??
|
||||
MachOReader.Load(memoryStream);
|
||||
(((IFileFormatReader) ElfReader.Load(memoryStream) ??
|
||||
PEReader.Load(memoryStream)) ??
|
||||
MachOReader.Load(memoryStream)) ??
|
||||
UBReader.Load(memoryStream);
|
||||
if (stream == null) {
|
||||
Console.Error.WriteLine("Unsupported executable file format");
|
||||
return null;
|
||||
}
|
||||
|
||||
Il2CppReader il2cpp;
|
||||
var processors = new List<Il2CppProcessor>();
|
||||
foreach (var image in stream.Images) {
|
||||
Il2CppReader il2cpp;
|
||||
|
||||
// We are currently supporting x86 and ARM architectures
|
||||
switch (stream.Arch) {
|
||||
case "x86":
|
||||
il2cpp = new Il2CppReaderX86(stream);
|
||||
break;
|
||||
case "ARM":
|
||||
il2cpp = new Il2CppReaderARM(stream);
|
||||
break;
|
||||
default:
|
||||
Console.Error.WriteLine("Unsupported architecture");
|
||||
return null;
|
||||
// We are currently supporting x86 and ARM architectures
|
||||
switch (image.Arch) {
|
||||
case "x86":
|
||||
il2cpp = new Il2CppReaderX86(image);
|
||||
break;
|
||||
case "ARM":
|
||||
il2cpp = new Il2CppReaderARM(image);
|
||||
break;
|
||||
default:
|
||||
Console.Error.WriteLine("Unsupported architecture");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find code and metadata regions
|
||||
if (!il2cpp.Load(metadata.Version)) {
|
||||
Console.Error.WriteLine("Could not process IL2CPP image");
|
||||
}
|
||||
else {
|
||||
processors.Add(new Il2CppProcessor(il2cpp, metadata));
|
||||
}
|
||||
}
|
||||
|
||||
// Find code and metadata regions
|
||||
if (!il2cpp.Load(metadata.Version)) {
|
||||
Console.Error.WriteLine("Could not process IL2CPP image");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Il2CppProcessor(il2cpp, metadata);
|
||||
return processors;
|
||||
}
|
||||
|
||||
public string GetTypeName(Il2CppType pType) {
|
||||
@@ -106,6 +111,31 @@ namespace Il2CppInspector
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Il2CppType GetTypeFromTypeIndex(int idx) {
|
||||
return Code.PtrMetadataRegistration.types[idx];
|
||||
}
|
||||
|
||||
public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType) {
|
||||
// Versions from 22 onwards use an array of pointers in fieldOffsets
|
||||
bool fieldOffsetsArePointers = (Metadata.Version >= 22);
|
||||
|
||||
// Some variants of 21 also use an array of pointers
|
||||
if (Metadata.Version == 21) {
|
||||
var f = Code.PtrMetadataRegistration.fieldOffsets;
|
||||
fieldOffsetsArePointers = (f[0] == 0 && f[1] == 0 && f[2] == 0 && f[3] == 0 && f[4] == 0 && f[5] > 0);
|
||||
}
|
||||
|
||||
// All older versions use values directly in the array
|
||||
if (!fieldOffsetsArePointers) {
|
||||
var typeDef = Metadata.Types[typeIndex];
|
||||
return Code.PtrMetadataRegistration.fieldOffsets[typeDef.fieldStart + fieldIndexInType];
|
||||
}
|
||||
|
||||
var ptr = Code.PtrMetadataRegistration.fieldOffsets[typeIndex];
|
||||
Code.Image.Stream.Position = Code.Image.MapVATR((uint)ptr) + 4 * fieldIndexInType;
|
||||
return Code.Image.Stream.ReadInt32();
|
||||
}
|
||||
|
||||
private readonly string[] szTypeString =
|
||||
{
|
||||
"END",
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Il2CppInspector
|
||||
|
||||
protected Il2CppReader(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration) {
|
||||
Image = stream;
|
||||
Configure(codeRegistration, metadataRegistration);
|
||||
Configure(Image, codeRegistration, metadataRegistration);
|
||||
}
|
||||
|
||||
public Il2CppCodeRegistration PtrCodeRegistration { get; protected set; }
|
||||
@@ -27,44 +27,35 @@ namespace Il2CppInspector
|
||||
protected abstract (uint, uint) Search(uint loc, uint globalOffset);
|
||||
|
||||
// Check all search locations
|
||||
public bool Load(int version) {
|
||||
public bool Load(int version, uint imageIndex = 0) {
|
||||
var subImage = Image[imageIndex];
|
||||
Image.Stream.Version = version;
|
||||
var addrs = Image.GetSearchLocations();
|
||||
var addrs = subImage.GetSearchLocations();
|
||||
foreach (var loc in addrs)
|
||||
if (loc != 0) {
|
||||
var (code, metadata) = Search(loc, Image.GlobalOffset);
|
||||
if (code != 0) {
|
||||
Configure(code, metadata);
|
||||
Image.FinalizeInit(this);
|
||||
Configure(subImage, code, metadata);
|
||||
subImage.FinalizeInit(this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void Configure(uint codeRegistration, uint metadataRegistration) {
|
||||
PtrCodeRegistration = Image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
|
||||
PtrMetadataRegistration = Image.ReadMappedObject<Il2CppMetadataRegistration>(metadataRegistration);
|
||||
PtrCodeRegistration.methodPointers = Image.ReadMappedArray<uint>(PtrCodeRegistration.pmethodPointers,
|
||||
private void Configure(IFileFormatReader image, uint codeRegistration, uint metadataRegistration) {
|
||||
PtrCodeRegistration = image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
|
||||
PtrMetadataRegistration = image.ReadMappedObject<Il2CppMetadataRegistration>(metadataRegistration);
|
||||
PtrCodeRegistration.methodPointers = image.ReadMappedArray<uint>(PtrCodeRegistration.pmethodPointers,
|
||||
(int) PtrCodeRegistration.methodPointersCount);
|
||||
PtrMetadataRegistration.fieldOffsets = Image.ReadMappedArray<int>(PtrMetadataRegistration.pfieldOffsets,
|
||||
PtrMetadataRegistration.fieldOffsets = image.ReadMappedArray<int>(PtrMetadataRegistration.pfieldOffsets,
|
||||
PtrMetadataRegistration.fieldOffsetsCount);
|
||||
var types = Image.ReadMappedArray<uint>(PtrMetadataRegistration.ptypes, PtrMetadataRegistration.typesCount);
|
||||
var types = image.ReadMappedArray<uint>(PtrMetadataRegistration.ptypes, PtrMetadataRegistration.typesCount);
|
||||
PtrMetadataRegistration.types = new Il2CppType[PtrMetadataRegistration.typesCount];
|
||||
for (int i = 0; i < PtrMetadataRegistration.typesCount; ++i) {
|
||||
PtrMetadataRegistration.types[i] = Image.ReadMappedObject<Il2CppType>(types[i]);
|
||||
PtrMetadataRegistration.types[i] = image.ReadMappedObject<Il2CppType>(types[i]);
|
||||
PtrMetadataRegistration.types[i].Init();
|
||||
}
|
||||
}
|
||||
|
||||
public Il2CppType GetTypeFromTypeIndex(int idx) {
|
||||
return PtrMetadataRegistration.types[idx];
|
||||
}
|
||||
|
||||
public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType) {
|
||||
var ptr = PtrMetadataRegistration.fieldOffsets[typeIndex];
|
||||
Image.Stream.Position = Image.MapVATR((uint) ptr) + 4 * fieldIndexInType;
|
||||
return Image.Stream.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Il2CppInspector
|
||||
// Assembly bytes to search for at start of each function
|
||||
uint metadataRegistration, codeRegistration;
|
||||
|
||||
// ARM
|
||||
// ARMv7
|
||||
var bytes = new byte[] { 0x1c, 0x0, 0x9f, 0xe5, 0x1c, 0x10, 0x9f, 0xe5, 0x1c, 0x20, 0x9f, 0xe5 };
|
||||
Image.Position = loc;
|
||||
var buff = Image.ReadBytes(12);
|
||||
@@ -35,7 +35,7 @@ namespace Il2CppInspector
|
||||
return (codeRegistration, metadataRegistration);
|
||||
}
|
||||
|
||||
// ARM metadata v23
|
||||
// ARMv7 metadata v23
|
||||
Image.Position = loc;
|
||||
|
||||
// Check for ADD Rx, PC in relevant parts of function
|
||||
@@ -51,7 +51,7 @@ namespace Il2CppInspector
|
||||
|
||||
// Follow path to code pointer
|
||||
var pCode = decodeMovImm32(func.Skip(8).Take(4).Concat(func.Skip(14).Take(4)).ToArray());
|
||||
codeRegistration = pCode + loc + 0x1A - globalOffset;
|
||||
codeRegistration = pCode + loc + 0x1A + globalOffset;
|
||||
|
||||
return (codeRegistration, metadataRegistration);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@ namespace Il2CppInspector
|
||||
private MachOHeader header;
|
||||
private uint pFuncTable;
|
||||
private uint sFuncTable;
|
||||
private uint fatIndex;
|
||||
private bool is64;
|
||||
private List<MachOSection> sections = new List<MachOSection>();
|
||||
private List<MachOSection64> sections64 = new List<MachOSection64>();
|
||||
|
||||
public MachOReader(Stream stream) : base(stream) { }
|
||||
|
||||
@@ -37,8 +39,6 @@ namespace Il2CppInspector
|
||||
}
|
||||
|
||||
protected override bool Init() {
|
||||
fatIndex = (uint)Position;
|
||||
|
||||
// Detect endianness - default is little-endianness
|
||||
MachO magic = (MachO)ReadUInt32();
|
||||
if (magic == MachO.MH_CIGAM || magic == MachO.MH_CIGAM_64) {
|
||||
@@ -50,11 +50,11 @@ namespace Il2CppInspector
|
||||
|
||||
Console.WriteLine("Endianness: {0}", Endianness);
|
||||
|
||||
Position = fatIndex;
|
||||
Position -= sizeof(uint);
|
||||
header = ReadObject<MachOHeader>();
|
||||
|
||||
// 64-bit files have an extra 4 bytes after the header
|
||||
bool is64 = false;
|
||||
is64 = false;
|
||||
if (magic == MachO.MH_MAGIC_64) {
|
||||
is64 = true;
|
||||
ReadUInt32();
|
||||
@@ -75,21 +75,23 @@ namespace Il2CppInspector
|
||||
|
||||
if ((MachO)loadCommand.Command == MachO.LC_SEGMENT) {
|
||||
var segment = ReadObject<MachOSegmentCommand>();
|
||||
if (segment.Name == "__TEXT") {
|
||||
if (segment.Name == "__TEXT" || segment.Name == "__DATA") {
|
||||
for (int s = 0; s < segment.NumSections; s++) {
|
||||
var section = ReadObject<MachOSection>();
|
||||
sections.Add(section);
|
||||
if (section.Name == "__text")
|
||||
GlobalOffset = section.ImageOffset - section.Address + fatIndex;
|
||||
GlobalOffset = section.Address - section.ImageOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((MachO)loadCommand.Command == MachO.LC_SEGMENT_64) {
|
||||
var segment = ReadObject<MachOSegmentCommand64>();
|
||||
if (segment.Name == "__TEXT") {
|
||||
if (segment.Name == "__TEXT" || segment.Name == "__DATA") {
|
||||
for (int s = 0; s < segment.NumSections; s++) {
|
||||
var section = ReadObject<MachOSection64>();
|
||||
if (section.Name == "__text")
|
||||
GlobalOffset = section.ImageOffset - (uint)section.Address + fatIndex;
|
||||
var section64 = ReadObject<MachOSection64>();
|
||||
sections64.Add(section64);
|
||||
if (section64.Name == "__text")
|
||||
GlobalOffset = (uint)section64.Address - section64.ImageOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,7 +108,7 @@ namespace Il2CppInspector
|
||||
if (functionStarts == null)
|
||||
return false;
|
||||
|
||||
pFuncTable = functionStarts.Offset + fatIndex;
|
||||
pFuncTable = functionStarts.Offset;
|
||||
sFuncTable = functionStarts.Size;
|
||||
return true;
|
||||
}
|
||||
@@ -131,20 +133,25 @@ namespace Il2CppInspector
|
||||
if (previous == 0)
|
||||
result &= 0xffffffc;
|
||||
previous += result;
|
||||
functionPointers.Add(previous + fatIndex);
|
||||
functionPointers.Add(previous);
|
||||
}
|
||||
}
|
||||
return functionPointers.ToArray();
|
||||
}
|
||||
|
||||
public override uint MapVATR(uint uiAddr) {
|
||||
return uiAddr + GlobalOffset;
|
||||
}
|
||||
|
||||
public override void FinalizeInit(Il2CppReader il2cpp) {
|
||||
// Mach-O function pointers have an annoying habit of being 1-off
|
||||
il2cpp.PtrCodeRegistration.methodPointers =
|
||||
il2cpp.PtrCodeRegistration.methodPointers.Select(x => x - 1).ToArray();
|
||||
}
|
||||
|
||||
public override uint MapVATR(uint uiAddr) {
|
||||
if (!is64) {
|
||||
var section = sections.First(x => uiAddr >= x.Address && uiAddr <= (x.Address + x.Size));
|
||||
return uiAddr - (section.Address - section.ImageOffset);
|
||||
}
|
||||
var section64 = sections64.First(x => uiAddr >= x.Address && uiAddr <= (x.Address + x.Size));
|
||||
return uiAddr - ((uint)section64.Address - section64.ImageOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
36
Il2CppInspector/UBHeaders.cs
Normal file
36
Il2CppInspector/UBHeaders.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Copyright 2017 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
// Structures and enums: https://cocoaintheshell.whine.fr/2009/07/universal-binary-mach-o-format/
|
||||
|
||||
public enum UB : uint
|
||||
{
|
||||
FAT_MAGIC = 0xcafebabe
|
||||
}
|
||||
|
||||
// Big-endian
|
||||
internal class FatHeader
|
||||
{
|
||||
public uint Magic;
|
||||
public uint NumArch;
|
||||
}
|
||||
|
||||
// Big-endian
|
||||
internal class FatArch
|
||||
{
|
||||
public uint CPUType;
|
||||
public uint CPUSubType;
|
||||
public uint Offset;
|
||||
public uint Size;
|
||||
public uint Align;
|
||||
}
|
||||
}
|
||||
47
Il2CppInspector/UBReader.cs
Normal file
47
Il2CppInspector/UBReader.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 2017 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
internal class UBReader : FileFormatReader<UBReader>
|
||||
{
|
||||
private FatHeader header;
|
||||
|
||||
public UBReader(Stream stream) : base(stream) { }
|
||||
|
||||
protected override bool Init() {
|
||||
// Fat headers are always big-endian regardless of architectures
|
||||
Endianness = Endianness.Big;
|
||||
|
||||
header = ReadObject<FatHeader>();
|
||||
|
||||
if ((UB) header.Magic != UB.FAT_MAGIC)
|
||||
return false;
|
||||
|
||||
NumImages = header.NumArch;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override IFileFormatReader this[uint index] {
|
||||
get {
|
||||
Position = 0x8 + 0x14 * index; // sizeof(FatHeader), sizeof(FatArch)
|
||||
Endianness = Endianness.Big;
|
||||
|
||||
var arch = ReadObject<FatArch>();
|
||||
|
||||
Position = arch.Offset;
|
||||
Endianness = Endianness.Little;
|
||||
return MachOReader.Load(new MemoryStream(ReadBytes((int)arch.Size)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user