From 755a8ec88c7264900d7930d13cfcc28f2c00aef9 Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Sun, 9 Feb 2020 04:11:16 +0100 Subject: [PATCH] GUI: Show progress messages in busy indicator --- .../FileFormatReaders/ElfReader.cs | 5 ++++ .../FileFormatReaders/FileFormatReader.cs | 28 +++++++++++++------ Il2CppInspector.GUI/App.xaml.cs | 10 ++++++- Il2CppInspector.GUI/MainWindow.xaml | 4 +-- Il2CppInspector.GUI/MainWindow.xaml.cs | 5 ++++ 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/Il2CppInspector.Common/FileFormatReaders/ElfReader.cs b/Il2CppInspector.Common/FileFormatReaders/ElfReader.cs index bd6aba5..a6d0f9d 100644 --- a/Il2CppInspector.Common/FileFormatReaders/ElfReader.cs +++ b/Il2CppInspector.Common/FileFormatReaders/ElfReader.cs @@ -125,6 +125,8 @@ namespace Il2CppInspector public override int Bits => (elf_header.m_arch == (uint) Elf.ELFCLASS64) ? 64 : 32; + //public override event EventHandler OnStatusUpdate; + private elf_shdr getSection(Elf sectionIndex) => section_header_table.FirstOrDefault(x => x.sh_type == (uint) sectionIndex); private IEnumerable> getSections(Elf sectionIndex) => section_header_table.Where(x => x.sh_type == (uint) sectionIndex); private TPHdr getProgramHeader(Elf programIndex) => program_header_table.FirstOrDefault(x => x.p_type == (uint) programIndex); @@ -167,6 +169,8 @@ namespace Il2CppInspector // Find all relocations; target address => (rela header (rels are converted to rela), symbol table base address, is rela?) var rels = new HashSet(); + StatusUpdate("Processing relocations"); + // Two types: add value from offset in image, and add value from specified addend foreach (var relSection in getSections(Elf.SHT_REL)) rels.UnionWith( @@ -253,6 +257,7 @@ namespace Il2CppInspector var xorKey = rodataFirstBytes.GroupBy(b => b).OrderByDescending(f => f.Count()).First().Key; if (xorKey != 0x00) { + StatusUpdate("Decrypting"); Console.WriteLine($"Performing trivial XOR decryption (key: 0x{xorKey:X2})"); xorSection(".text", xorKey); diff --git a/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs b/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs index dd2492c..e56747c 100644 --- a/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs +++ b/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs @@ -47,28 +47,29 @@ namespace Il2CppInspector U ReadObject() where U : new(); string ReadMappedNullTerminatedString(ulong uiAddr); List ReadMappedObjectPointerArray(ulong uiAddr, int count) where U : new(); + event EventHandler OnStatusUpdate; } public class FileFormatReader { // Helper method to try all defined file formats when the contents of the binary is unknown - public static IFileFormatReader Load(string filename) => Load(new FileStream(filename, FileMode.Open, FileAccess.Read)); + public static IFileFormatReader Load(string filename, EventHandler statusCallback = null) => Load(new FileStream(filename, FileMode.Open, FileAccess.Read), statusCallback); - public static IFileFormatReader Load(Stream stream) { + public static IFileFormatReader Load(Stream stream, EventHandler statusCallback = null) { var types = Assembly.GetExecutingAssembly().DefinedTypes .Where(x => x.ImplementedInterfaces.Contains(typeof(IFileFormatReader)) && !x.IsGenericTypeDefinition); foreach (var type in types) { if (type.GetMethod("Load", BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public, - null, new [] {typeof(Stream)}, null) - .Invoke(null, new object[] { stream }) is IFileFormatReader loaded) + null, new [] {typeof(Stream), typeof(EventHandler)}, null) + .Invoke(null, new object[] { stream, statusCallback }) is IFileFormatReader loaded) return loaded; } return null; } } - public class FileFormatReader : BinaryObjectReader, IFileFormatReader where T : FileFormatReader + public abstract class FileFormatReader : BinaryObjectReader, IFileFormatReader where T : FileFormatReader { public FileFormatReader(Stream stream) : base(stream) { } @@ -86,6 +87,10 @@ namespace Il2CppInspector public virtual int Bits => throw new NotImplementedException(); + public event EventHandler OnStatusUpdate; + + protected void StatusUpdate(string status) => OnStatusUpdate?.Invoke(this, status); + public IEnumerable Images { get { for (uint i = 0; i < NumImages; i++) @@ -93,12 +98,12 @@ namespace Il2CppInspector } } - public static T Load(string filename) { + public static T Load(string filename, EventHandler statusCallback = null) { using var stream = new FileStream(filename, FileMode.Open, FileAccess.Read); - return Load(stream); + return Load(stream, statusCallback); } - public static T Load(Stream stream) { + public static T Load(Stream stream, EventHandler statusCallback = null) { // Copy the original stream in case we modify it var ms = new MemoryStream(); stream.Position = 0; @@ -106,7 +111,12 @@ namespace Il2CppInspector ms.Position = 0; var pe = (T) Activator.CreateInstance(typeof(T), ms); - return pe.Init() ? pe : null; + return pe.InitImpl(statusCallback) ? pe : null; + } + + private bool InitImpl(EventHandler statusCallback = null) { + OnStatusUpdate += statusCallback; + return Init(); } // Confirm file is valid and set up RVA mappings diff --git a/Il2CppInspector.GUI/App.xaml.cs b/Il2CppInspector.GUI/App.xaml.cs index 76d4d8d..840e840 100644 --- a/Il2CppInspector.GUI/App.xaml.cs +++ b/Il2CppInspector.GUI/App.xaml.cs @@ -21,6 +21,11 @@ namespace Il2CppInspectorGUI public Exception LastException { get; private set; } + // Event to indicate current work status + public event EventHandler OnStatusUpdate; + + private void StatusUpdate(object sender, string status) => OnStatusUpdate?.Invoke(sender, status); + // Attempt to load an IL2CPP metadata file public Task LoadMetadataAsync(string metadataFile) => Task.Run(() => { @@ -38,7 +43,7 @@ namespace Il2CppInspectorGUI Task.Run(() => { try { // This may throw other exceptions from the individual loaders as well - IFileFormatReader stream = FileFormatReader.Load(binaryFile); + IFileFormatReader stream = FileFormatReader.Load(binaryFile, StatusUpdate); if (stream == null) { throw new InvalidOperationException("Could not determine the binary file format"); } @@ -49,6 +54,8 @@ namespace Il2CppInspectorGUI // Multi-image binaries may contain more than one Il2Cpp image Il2CppModels.Clear(); foreach (var image in stream.Images) { + OnStatusUpdate?.Invoke(this, "Analyzing IL2CPP data"); + // Architecture-agnostic load attempt try { // If we can't load the IL2CPP data here, it's probably packed or obfuscated; ignore it @@ -56,6 +63,7 @@ namespace Il2CppInspectorGUI var inspector = new Inspector(binary, metadata); // Build type model + OnStatusUpdate?.Invoke(this, "Building type model"); Il2CppModels.Add(new Il2CppModel(inspector)); } } diff --git a/Il2CppInspector.GUI/MainWindow.xaml b/Il2CppInspector.GUI/MainWindow.xaml index 2e2f10f..2bbbb38 100644 --- a/Il2CppInspector.GUI/MainWindow.xaml +++ b/Il2CppInspector.GUI/MainWindow.xaml @@ -152,9 +152,9 @@ - + - Getting things ready... + Getting things ready... diff --git a/Il2CppInspector.GUI/MainWindow.xaml.cs b/Il2CppInspector.GUI/MainWindow.xaml.cs index 7d52e2b..7762a2d 100644 --- a/Il2CppInspector.GUI/MainWindow.xaml.cs +++ b/Il2CppInspector.GUI/MainWindow.xaml.cs @@ -26,8 +26,13 @@ namespace Il2CppInspectorGUI { public MainWindow() { InitializeComponent(); + + // Subscribe to status update events + ((App) Application.Current).OnStatusUpdate += OnStatusUpdate; } + private void OnStatusUpdate(object sender, string e) => txtBusyStatus.Dispatcher.Invoke(() => txtBusyStatus.Text = e + "..."); + /// /// Select global metadata file ///