From 7878193f7449797cbb9d6f14e7645d269d5c6292 Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Mon, 14 Dec 2020 02:52:57 +0100 Subject: [PATCH] Formats: Add option for multiple load strategies per sub-image --- .../FileFormatReaders/FileFormatReader.cs | 12 ++++--- Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs | 32 +++++++++++++------ Il2CppInspector.GUI/App.xaml.cs | 2 -- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs b/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs index 889e063..f7cc9f8 100644 --- a/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs +++ b/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs @@ -21,15 +21,16 @@ namespace Il2CppInspector long Length { get; } uint NumImages { get; } string DefaultFilename { get; } - bool IsModified { get; } - IEnumerable Images { get; } - IFileFormatReader this[uint index] { get; } + bool IsModified { get; } + IEnumerable Images { get; } // Each child image of this object (eg. 32/64-bit versions in Fat MachO file) + IFileFormatReader this[uint index] { get; } // With no additional override, one object = one file, this[0] == this long Position { get; set; } string Format { get; } string Arch { get; } int Bits { get; } ulong GlobalOffset { get; } // The virtual address where the code section (.text) would be loaded in memory ulong ImageBase { get; } // The virtual address of where the image would be loaded in memory (same as GlobalOffset except for PE) + IEnumerable TryNextLoadStrategy(); // Some images can be loaded multiple ways, eg. default, packed Dictionary GetSymbolTable(); uint[] GetFunctionTable(); IEnumerable GetExports(); @@ -184,9 +185,12 @@ 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 + // Choose an image within the file for multi-architecture binaries public virtual IFileFormatReader this[uint index] => (index == 0)? this : throw new IndexOutOfRangeException("Binary image index out of bounds"); + // For images that can be loaded and then tested with Il2CppBinary in multiple ways, get the next possible version of the image + public virtual IEnumerable TryNextLoadStrategy() { yield return this; } + // Find search locations in the symbol table for Il2Cpp data public virtual Dictionary GetSymbolTable() => new Dictionary(); diff --git a/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs b/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs index 327ebbf..6626be7 100644 --- a/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs +++ b/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs @@ -95,12 +95,16 @@ namespace Il2CppInspector protected Il2CppBinary(IFileFormatReader stream, EventHandler statusCallback = null) { Image = stream; OnStatusUpdate = statusCallback; + + StatusUpdate($"Analyzing IL2CPP data for {Image.Format}/{Image.Arch} image"); DiscoverAPIExports(); } protected Il2CppBinary(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration, EventHandler statusCallback = null) { Image = stream; OnStatusUpdate = statusCallback; + + StatusUpdate($"Analyzing IL2CPP data for {Image.Format}/{Image.Arch} image"); DiscoverAPIExports(); PrepareMetadata(codeRegistration, metadataRegistration); } @@ -123,8 +127,12 @@ namespace Il2CppInspector // Load binary without a global-metadata.dat available public static Il2CppBinary Load(IFileFormatReader stream, double metadataVersion, EventHandler statusCallback = null) { - var inst = LoadImpl(stream, statusCallback); - return inst.FindRegistrationStructs(metadataVersion) ? inst : null; + foreach (var loadedImage in stream.TryNextLoadStrategy()) { + var inst = LoadImpl(stream, statusCallback); + if (inst.FindRegistrationStructs(metadataVersion)) + return inst; + } + return null; } // Load binary with a global-metadata.dat available @@ -133,8 +141,12 @@ namespace Il2CppInspector // Metadata will be used to try to find the required structures with data analysis // If it is not specified, data analysis will not be performed public static Il2CppBinary Load(IFileFormatReader stream, Metadata metadata, EventHandler statusCallback = null) { - var inst = LoadImpl(stream, statusCallback); - return inst.FindRegistrationStructs(metadata) ? inst : null; + foreach (var loadedImage in stream.TryNextLoadStrategy()) { + var inst = LoadImpl(stream, statusCallback); + if (inst.FindRegistrationStructs(metadata)) + return inst; + } + return null; } // Save binary to file, overwriting if necessary @@ -146,24 +158,24 @@ namespace Il2CppInspector } // Initialize binary without a global-metadata.dat available - public bool FindRegistrationStructs(double metadataVersion, EventHandler statusCallback = null) { + public bool FindRegistrationStructs(double metadataVersion) { Image.Version = metadataVersion; - if (!((FindMetadataFromSymbols() ?? FindMetadataFromCode()) is var ptrs)) + if (!((FindMetadataFromSymbols() ?? FindMetadataFromCode()) is (ulong code, ulong meta))) return false; - PrepareMetadata(ptrs.Value.Item1, ptrs.Value.Item2); + PrepareMetadata(code, meta); return true; } // Initialize binary with a global-metadata.dat available - public bool FindRegistrationStructs(Metadata metadata, EventHandler statusCallback = null) { + public bool FindRegistrationStructs(Metadata metadata) { Image.Version = metadata.Version; - if (!((FindMetadataFromSymbols() ?? FindMetadataFromCode() ?? FindMetadataFromData(metadata)) is var ptrs)) + if (!((FindMetadataFromSymbols() ?? FindMetadataFromCode() ?? FindMetadataFromData(metadata)) is (ulong code, ulong meta))) return false; - PrepareMetadata(ptrs.Value.Item1, ptrs.Value.Item2, metadata); + PrepareMetadata(code, meta); return true; } diff --git a/Il2CppInspector.GUI/App.xaml.cs b/Il2CppInspector.GUI/App.xaml.cs index c4f876b..4d45162 100644 --- a/Il2CppInspector.GUI/App.xaml.cs +++ b/Il2CppInspector.GUI/App.xaml.cs @@ -124,8 +124,6 @@ namespace Il2CppInspectorGUI // Multi-image binaries may contain more than one Il2Cpp image AppModels.Clear(); foreach (var image in stream.Images) { - OnStatusUpdate?.Invoke(this, $"Analyzing IL2CPP data for {image.Format}/{image.Arch} image"); - // Architecture-agnostic load attempt try { // If we can't load the IL2CPP data here, it's probably packed or obfuscated; ignore it