From 515365e9e904fdbff942ba519f3d7a43d1c49325 Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Sun, 6 Dec 2020 17:33:07 +0100 Subject: [PATCH] Add progress callbacks to Il2CppBinary and Il2CppInspector --- .../Architectures/Il2CppBinaryARM.cs | 5 ++-- .../Architectures/Il2CppBinaryARM64.cs | 5 ++-- .../Architectures/Il2CppBinaryX64.cs | 6 +++-- .../Architectures/Il2CppBinaryX86.cs | 6 +++-- Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs | 25 +++++++++++-------- .../IL2CPP/Il2CppInspector.cs | 12 ++++----- Il2CppInspector.Common/IL2CPP/Metadata.cs | 5 +++- Il2CppInspector.GUI/App.xaml.cs | 4 +-- 8 files changed, 41 insertions(+), 27 deletions(-) diff --git a/Il2CppInspector.Common/Architectures/Il2CppBinaryARM.cs b/Il2CppInspector.Common/Architectures/Il2CppBinaryARM.cs index 09f933d..60b19c0 100644 --- a/Il2CppInspector.Common/Architectures/Il2CppBinaryARM.cs +++ b/Il2CppInspector.Common/Architectures/Il2CppBinaryARM.cs @@ -13,9 +13,10 @@ namespace Il2CppInspector { internal class Il2CppBinaryARM : Il2CppBinary { - public Il2CppBinaryARM(IFileFormatReader stream) : base(stream) { } + public Il2CppBinaryARM(IFileFormatReader stream, EventHandler statusCallback = null) : base(stream, statusCallback) { } - public Il2CppBinaryARM(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration) : base(stream, codeRegistration, metadataRegistration) { } + public Il2CppBinaryARM(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration, EventHandler statusCallback = null) + : base(stream, codeRegistration, metadataRegistration, statusCallback) { } // ARMv7-A Architecture Reference Manual: https://static.docs.arm.com/ddi0406/c/DDI0406C_C_arm_architecture_reference_manual.pdf diff --git a/Il2CppInspector.Common/Architectures/Il2CppBinaryARM64.cs b/Il2CppInspector.Common/Architectures/Il2CppBinaryARM64.cs index c3b70ba..cca4186 100644 --- a/Il2CppInspector.Common/Architectures/Il2CppBinaryARM64.cs +++ b/Il2CppInspector.Common/Architectures/Il2CppBinaryARM64.cs @@ -12,9 +12,10 @@ namespace Il2CppInspector // A64 ISA reference: https://static.docs.arm.com/ddi0596/a/DDI_0596_ARM_a64_instruction_set_architecture.pdf internal class Il2CppBinaryARM64 : Il2CppBinary { - public Il2CppBinaryARM64(IFileFormatReader stream) : base(stream) { } + public Il2CppBinaryARM64(IFileFormatReader stream, EventHandler statusCallback = null) : base(stream, statusCallback) { } - public Il2CppBinaryARM64(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration) : base(stream, codeRegistration, metadataRegistration) { } + public Il2CppBinaryARM64(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration, EventHandler statusCallback = null) + : base(stream, codeRegistration, metadataRegistration, statusCallback) { } private (uint reg, ulong page)? getAdrp(uint inst, ulong pc) { if ((inst.Bits(24, 8) & 0b_1000_1111) != 1 << 7) diff --git a/Il2CppInspector.Common/Architectures/Il2CppBinaryX64.cs b/Il2CppInspector.Common/Architectures/Il2CppBinaryX64.cs index 6a1c2d5..7874dd2 100644 --- a/Il2CppInspector.Common/Architectures/Il2CppBinaryX64.cs +++ b/Il2CppInspector.Common/Architectures/Il2CppBinaryX64.cs @@ -13,8 +13,10 @@ namespace Il2CppInspector { internal class Il2CppBinaryX64 : Il2CppBinary { - public Il2CppBinaryX64(IFileFormatReader stream) : base(stream) { } - public Il2CppBinaryX64(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration) : base(stream, codeRegistration, metadataRegistration) { } + public Il2CppBinaryX64(IFileFormatReader stream, EventHandler statusCallback = null) : base(stream, statusCallback) { } + + public Il2CppBinaryX64(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration, EventHandler statusCallback = null) + : base(stream, codeRegistration, metadataRegistration, statusCallback) { } // Format of 64-bit LEA: // 0x48/0x4C - REX prefix signifying 64-bit mode with 64-bit operand size (REX prefix bits: Volume 2A, page 2-9) (bit 2 is register bit 3) diff --git a/Il2CppInspector.Common/Architectures/Il2CppBinaryX86.cs b/Il2CppInspector.Common/Architectures/Il2CppBinaryX86.cs index 4c086c4..e5c5393 100644 --- a/Il2CppInspector.Common/Architectures/Il2CppBinaryX86.cs +++ b/Il2CppInspector.Common/Architectures/Il2CppBinaryX86.cs @@ -11,8 +11,10 @@ namespace Il2CppInspector { internal class Il2CppBinaryX86 : Il2CppBinary { - public Il2CppBinaryX86(IFileFormatReader stream) : base(stream) { } - public Il2CppBinaryX86(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration) : base(stream, codeRegistration, metadataRegistration) { } + public Il2CppBinaryX86(IFileFormatReader stream, EventHandler statusCallback = null) : base(stream, statusCallback) { } + + public Il2CppBinaryX86(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration, EventHandler statusCallback = null) + : base(stream, codeRegistration, metadataRegistration, statusCallback) { } protected override (ulong, ulong) ConsiderCode(IFileFormatReader image, uint loc) { ulong metadata, code; diff --git a/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs b/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs index a04e6a1..6bed7a9 100644 --- a/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs +++ b/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs @@ -80,17 +80,22 @@ namespace Il2CppInspector // One assembly may contain multiple modules public Dictionary Modules { get; private set; } - protected Il2CppBinary(IFileFormatReader stream) { + private EventHandler OnStatusUpdate { get; set; } + private void StatusUpdate(string status) => OnStatusUpdate?.Invoke(this, status); + + protected Il2CppBinary(IFileFormatReader stream, EventHandler statusCallback = null) { Image = stream; + OnStatusUpdate = statusCallback; } - protected Il2CppBinary(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration) { + protected Il2CppBinary(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration, EventHandler statusCallback = null) { Image = stream; + OnStatusUpdate = statusCallback; Configure(codeRegistration, metadataRegistration); } // Load and initialize a binary of any supported architecture - private static Il2CppBinary LoadImpl(IFileFormatReader stream) { + private static Il2CppBinary LoadImpl(IFileFormatReader stream, EventHandler statusCallback) { // Get type from image architecture var type = Assembly.GetExecutingAssembly().GetType("Il2CppInspector.Il2CppBinary" + stream.Arch.ToUpper()); if (type == null) @@ -102,12 +107,12 @@ namespace Il2CppInspector stream[0].Stream.PrimitiveMappings.Add(typeof(ulong), typeof(uint)); } - return (Il2CppBinary) Activator.CreateInstance(type, stream[0]); + return (Il2CppBinary) Activator.CreateInstance(type, stream[0], statusCallback); } // Load binary without a global-metadata.dat available - public static Il2CppBinary Load(IFileFormatReader stream, double metadataVersion) { - var inst = LoadImpl(stream); + public static Il2CppBinary Load(IFileFormatReader stream, double metadataVersion, EventHandler statusCallback = null) { + var inst = LoadImpl(stream, statusCallback); return inst.Initialize(metadataVersion) ? inst : null; } @@ -116,13 +121,13 @@ namespace Il2CppInspector // If it is specified and both symbol table and function scanning fail, // 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) { - var inst = LoadImpl(stream); + public static Il2CppBinary Load(IFileFormatReader stream, Metadata metadata, EventHandler statusCallback = null) { + var inst = LoadImpl(stream, statusCallback); return inst.Initialize(metadata) ? inst : null; } // Initialize binary without a global-metadata.dat available - public bool Initialize(double metadataVersion) { + public bool Initialize(double metadataVersion, EventHandler statusCallback = null) { Image.Version = metadataVersion; if (!((FindMetadataFromSymbols() ?? FindMetadataFromCode()) is var ptrs)) @@ -133,7 +138,7 @@ namespace Il2CppInspector } // Initialize binary with a global-metadata.dat available - public bool Initialize(Metadata metadata) { + public bool Initialize(Metadata metadata, EventHandler statusCallback = null) { Image.Version = metadata.Version; if (!((FindMetadataFromSymbols() ?? FindMetadataFromCode() ?? FindMetadataFromData(metadata)) is var ptrs)) diff --git a/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs b/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs index 91e48bc..10d4089 100644 --- a/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs +++ b/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs @@ -497,18 +497,18 @@ namespace Il2CppInspector var streams = GetStreamsFromPackage(packageFiles, silent); if (!streams.HasValue) return null; - return LoadFromStream(streams.Value.Binary, streams.Value.Metadata, silent); + return LoadFromStream(streams.Value.Binary, streams.Value.Metadata, silent: silent); } // Load from a binary file and metadata file public static List LoadFromFile(string binaryFile, string metadataFile, bool silent = false) => LoadFromStream(new FileStream(binaryFile, FileMode.Open, FileAccess.Read, FileShare.Read), new MemoryStream(File.ReadAllBytes(metadataFile)), - silent); + silent: silent); // Load from a binary stream and metadata stream // Must be a seekable stream otherwise we catch a System.IO.NotSupportedException - public static List LoadFromStream(Stream binaryStream, Stream metadataStream, bool silent = false) { + public static List LoadFromStream(Stream binaryStream, Stream metadataStream, EventHandler statusCallback = null, bool silent = false) { // Silent operation if requested var stdout = Console.Out; @@ -518,7 +518,7 @@ namespace Il2CppInspector // Load the metadata file Metadata metadata; try { - metadata = new Metadata(metadataStream); + metadata = new Metadata(metadataStream, statusCallback); } catch (Exception ex) { Console.Error.WriteLine(ex.Message); @@ -531,7 +531,7 @@ namespace Il2CppInspector // Load the il2cpp code file (try all available file formats) IFileFormatReader stream; try { - stream = FileFormatReader.Load(binaryStream); + stream = FileFormatReader.Load(binaryStream, statusCallback); if (stream == null) throw new InvalidOperationException("Unsupported executable file format"); @@ -553,7 +553,7 @@ namespace Il2CppInspector // Architecture-agnostic load attempt try { - if (Il2CppBinary.Load(image, metadata) is Il2CppBinary binary) { + if (Il2CppBinary.Load(image, metadata, statusCallback) is Il2CppBinary binary) { Console.WriteLine("IL2CPP binary version " + image.Version); processors.Add(new Il2CppInspector(binary, metadata)); diff --git a/Il2CppInspector.Common/IL2CPP/Metadata.cs b/Il2CppInspector.Common/IL2CPP/Metadata.cs index 3baaa92..220aa80 100644 --- a/Il2CppInspector.Common/IL2CPP/Metadata.cs +++ b/Il2CppInspector.Common/IL2CPP/Metadata.cs @@ -45,7 +45,7 @@ namespace Il2CppInspector public Dictionary Strings { get; } = new Dictionary(); - public Metadata(Stream stream) : base(stream) + public Metadata(Stream stream, EventHandler statusCallback = null) : base(stream) { // Read magic bytes if (ReadUInt32() != 0xFAB11BAF) { @@ -170,6 +170,9 @@ namespace Il2CppInspector // Only do this if we need to because it's very slow if (stringOffsets.Except(Strings.Keys).Any()) { + Console.WriteLine("Decrypting strings..."); + statusCallback?.Invoke(this, "Decrypting strings"); + // Start again Strings.Clear(); Position = Header.stringOffset; diff --git a/Il2CppInspector.GUI/App.xaml.cs b/Il2CppInspector.GUI/App.xaml.cs index 5b16c1f..55a4a45 100644 --- a/Il2CppInspector.GUI/App.xaml.cs +++ b/Il2CppInspector.GUI/App.xaml.cs @@ -58,7 +58,7 @@ namespace Il2CppInspectorGUI try { OnStatusUpdate?.Invoke(this, "Processing metadata"); - metadata = new Metadata(metadataStream); + metadata = new Metadata(metadataStream, StatusUpdate); return true; } catch (Exception ex) { @@ -95,7 +95,7 @@ namespace Il2CppInspectorGUI // Architecture-agnostic load attempt try { // If we can't load the IL2CPP data here, it's probably packed or obfuscated; ignore it - if (Il2CppBinary.Load(image, metadata) is Il2CppBinary binary) { + if (Il2CppBinary.Load(image, metadata, StatusUpdate) is Il2CppBinary binary) { var inspector = new Inspector(binary, metadata); // Build type model