diff --git a/Il2CppInspector.CLI/Program.cs b/Il2CppInspector.CLI/Program.cs index e8e23bc..d2244cb 100644 --- a/Il2CppInspector.CLI/Program.cs +++ b/Il2CppInspector.CLI/Program.cs @@ -190,7 +190,7 @@ namespace Il2CppInspector.CLI using (new Benchmark("Analyze IL2CPP data")) { try { - il2cppInspectors = Il2CppInspector.LoadFromPackage(options.BinaryFiles); + il2cppInspectors = Il2CppInspector.LoadFromPackage(options.BinaryFiles); // TODO: loadOptions isExtractedFromPackage = true; } catch (Exception ex) { @@ -207,7 +207,7 @@ namespace Il2CppInspector.CLI } try { - il2cppInspectors = Il2CppInspector.LoadFromFile(options.BinaryFiles.First(), options.MetadataFile); + il2cppInspectors = Il2CppInspector.LoadFromFile(options.BinaryFiles.First(), options.MetadataFile); // TODO: loadOptions } catch (Exception ex) { Console.Error.WriteLine(ex.Message); diff --git a/Il2CppInspector.Common/FileFormatReaders/AABReader.cs b/Il2CppInspector.Common/FileFormatReaders/AABReader.cs index b96de2c..c863f5b 100644 --- a/Il2CppInspector.Common/FileFormatReaders/AABReader.cs +++ b/Il2CppInspector.Common/FileFormatReaders/AABReader.cs @@ -58,14 +58,14 @@ namespace Il2CppInspector // ZipArchiveEntry does not support seeking so we have to close and re-open for each possible load format var binary = binaryFiles[index].Open(); - loaded = ElfReader32.Load(binary, OnStatusUpdate); + loaded = ElfReader32.Load(binary, LoadOptions, OnStatusUpdate); binary.Close(); if (loaded != null) return loaded; binary = binaryFiles[index].Open(); - loaded = ElfReader64.Load(binary, OnStatusUpdate); + loaded = ElfReader64.Load(binary, LoadOptions, OnStatusUpdate); binary.Close(); return loaded; diff --git a/Il2CppInspector.Common/FileFormatReaders/APKReader.cs b/Il2CppInspector.Common/FileFormatReaders/APKReader.cs index 9837e77..4093e6f 100644 --- a/Il2CppInspector.Common/FileFormatReaders/APKReader.cs +++ b/Il2CppInspector.Common/FileFormatReaders/APKReader.cs @@ -58,14 +58,14 @@ namespace Il2CppInspector // ZipArchiveEntry does not support seeking so we have to close and re-open for each possible load format var binary = binaryFiles[index].Open(); - loaded = ElfReader32.Load(binary, OnStatusUpdate); + loaded = ElfReader32.Load(binary, LoadOptions, OnStatusUpdate); binary.Close(); if (loaded != null) return loaded; binary = binaryFiles[index].Open(); - loaded = ElfReader64.Load(binary, OnStatusUpdate); + loaded = ElfReader64.Load(binary, LoadOptions, OnStatusUpdate); binary.Close(); return loaded; diff --git a/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs b/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs index 2dd7baa..889e063 100644 --- a/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs +++ b/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs @@ -97,17 +97,18 @@ namespace Il2CppInspector 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, EventHandler statusCallback = null) => Load(new FileStream(filename, FileMode.Open, FileAccess.Read), statusCallback); + public static IFileFormatReader Load(string filename, LoadOptions loadOptions = null, EventHandler statusCallback = null) + => Load(new FileStream(filename, FileMode.Open, FileAccess.Read), loadOptions, statusCallback); - public static IFileFormatReader Load(Stream stream, EventHandler statusCallback = null) { + public static IFileFormatReader Load(Stream stream, LoadOptions loadOptions = null, EventHandler statusCallback = null) { var types = Assembly.GetExecutingAssembly().DefinedTypes .Where(x => x.ImplementedInterfaces.Contains(typeof(IFileFormatReader)) && !x.IsGenericTypeDefinition); foreach (var type in types) { try { if (type.GetMethod("Load", BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public, - null, new[] {typeof(Stream), typeof(EventHandler)}, null) - .Invoke(null, new object[] {stream, statusCallback}) is IFileFormatReader loaded) + null, new[] {typeof(Stream), typeof(LoadOptions), typeof(EventHandler)}, null) + .Invoke(null, new object[] {stream, loadOptions, statusCallback}) is IFileFormatReader loaded) return loaded; } catch (TargetInvocationException ex) { @@ -142,6 +143,9 @@ namespace Il2CppInspector public virtual int Bits => throw new NotImplementedException(); + // Extra parameters to be passed to a loader + protected LoadOptions LoadOptions; + public EventHandler OnStatusUpdate { get; set; } protected void StatusUpdate(string status) => OnStatusUpdate?.Invoke(this, status); @@ -153,12 +157,12 @@ namespace Il2CppInspector } } - public static T Load(string filename, EventHandler statusCallback = null) { + public static T Load(string filename, LoadOptions loadOptions = null, EventHandler statusCallback = null) { using var stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); - return Load(stream, statusCallback); + return Load(stream, loadOptions, statusCallback); } - public static T Load(Stream stream, EventHandler statusCallback = null) { + public static T Load(Stream stream, LoadOptions loadOptions = null, EventHandler statusCallback = null) { // Copy the original stream in case we modify it var ms = new MemoryStream(); @@ -168,10 +172,11 @@ namespace Il2CppInspector ms.Position = 0; var pe = (T) Activator.CreateInstance(typeof(T), ms); - return pe.InitImpl(statusCallback) ? pe : null; + return pe.InitImpl(loadOptions, statusCallback) ? pe : null; } - private bool InitImpl(EventHandler statusCallback = null) { + private bool InitImpl(LoadOptions loadOptions, EventHandler statusCallback) { + LoadOptions = loadOptions; OnStatusUpdate = statusCallback; return Init(); } diff --git a/Il2CppInspector.Common/FileFormatReaders/LoadOptions.cs b/Il2CppInspector.Common/FileFormatReaders/LoadOptions.cs new file mode 100644 index 0000000..06283b9 --- /dev/null +++ b/Il2CppInspector.Common/FileFormatReaders/LoadOptions.cs @@ -0,0 +1,15 @@ +/* + Copyright 2017-2020 Katy Coe - http://www.djkaty.com - https://github.com/djkaty + + All rights reserved. +*/ + +namespace Il2CppInspector +{ + // Modifiers for use when loading binary files + public class LoadOptions + { + // For dumped ELF files, the virtual address to which we should rebase - ignored for other file types + public ulong? ImageBase; + } +} \ No newline at end of file diff --git a/Il2CppInspector.Common/FileFormatReaders/UBReader.cs b/Il2CppInspector.Common/FileFormatReaders/UBReader.cs index 36b8dfa..17d91cd 100644 --- a/Il2CppInspector.Common/FileFormatReaders/UBReader.cs +++ b/Il2CppInspector.Common/FileFormatReaders/UBReader.cs @@ -41,7 +41,7 @@ namespace Il2CppInspector Endianness = Endianness.Little; using var s = new MemoryStream(ReadBytes((int) arch.Size)); - return (IFileFormatReader) MachOReader32.Load(s, OnStatusUpdate) ?? MachOReader64.Load(s, OnStatusUpdate); + return (IFileFormatReader) MachOReader32.Load(s, LoadOptions, OnStatusUpdate) ?? MachOReader64.Load(s, LoadOptions, OnStatusUpdate); } } } diff --git a/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs b/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs index 54d2857..1f1fb0c 100644 --- a/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs +++ b/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs @@ -515,22 +515,22 @@ namespace Il2CppInspector } // Load from an AAB, IPA or one or more APK files - public static List LoadFromPackage(IEnumerable packageFiles, bool silent = false) { + public static List LoadFromPackage(IEnumerable packageFiles, LoadOptions loadOptions = null, bool silent = false) { var streams = GetStreamsFromPackage(packageFiles, silent); if (!streams.HasValue) return null; - return LoadFromStream(streams.Value.Binary, streams.Value.Metadata, silent: silent); + return LoadFromStream(streams.Value.Binary, streams.Value.Metadata, loadOptions, silent: silent); } // Load from a binary file and metadata file - public static List LoadFromFile(string binaryFile, string metadataFile, bool silent = false) + public static List LoadFromFile(string binaryFile, string metadataFile, LoadOptions loadOptions = null, bool silent = false) => LoadFromStream(new FileStream(binaryFile, FileMode.Open, FileAccess.Read, FileShare.Read), new MemoryStream(File.ReadAllBytes(metadataFile)), - silent: silent); + loadOptions, 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, MemoryStream metadataStream, EventHandler statusCallback = null, bool silent = false) { + public static List LoadFromStream(Stream binaryStream, MemoryStream metadataStream, LoadOptions loadOptions = null, EventHandler statusCallback = null, bool silent = false) { // Silent operation if requested var stdout = Console.Out; @@ -553,7 +553,7 @@ namespace Il2CppInspector // Load the il2cpp code file (try all available file formats) IFileFormatReader stream; try { - stream = FileFormatReader.Load(binaryStream, statusCallback); + stream = FileFormatReader.Load(binaryStream, loadOptions, statusCallback); if (stream == null) throw new InvalidOperationException("Unsupported executable file format"); diff --git a/Il2CppInspector.GUI/App.xaml.cs b/Il2CppInspector.GUI/App.xaml.cs index f54f7ca..d879a4a 100644 --- a/Il2CppInspector.GUI/App.xaml.cs +++ b/Il2CppInspector.GUI/App.xaml.cs @@ -44,7 +44,7 @@ namespace Il2CppInspectorGUI private void StatusUpdate(object sender, string status) => OnStatusUpdate?.Invoke(sender, status); // Attempt to load an IL2CPP application package (APK or IPA) - public async Task LoadPackageAsync(IEnumerable packageFiles) { + public async Task LoadPackageAsync(IEnumerable packageFiles, LoadOptions loadOptions) { IsExtractedFromPackage = false; try { @@ -54,7 +54,7 @@ namespace Il2CppInspectorGUI if (streams == null) throw new InvalidOperationException("The supplied package is not an APK or IPA file, or does not contain a complete IL2CPP application"); - IsExtractedFromPackage = await LoadMetadataAsync(streams.Value.Metadata) && await LoadBinaryAsync(streams.Value.Binary); + IsExtractedFromPackage = await LoadMetadataAsync(streams.Value.Metadata) && await LoadBinaryAsync(streams.Value.Binary, loadOptions); return IsExtractedFromPackage; } catch (Exception ex) { @@ -85,18 +85,18 @@ namespace Il2CppInspectorGUI }); // Attempt to load an IL2CPP binary file - public async Task LoadBinaryAsync(string binaryFile) { + public async Task LoadBinaryAsync(string binaryFile, LoadOptions loadOptions) { var stream = new MemoryStream(await File.ReadAllBytesAsync(binaryFile)); - return await LoadBinaryAsync(stream); + return await LoadBinaryAsync(stream, loadOptions); } - public Task LoadBinaryAsync(Stream binaryStream) => + public Task LoadBinaryAsync(Stream binaryStream, LoadOptions loadOptions) => Task.Run(() => { try { OnStatusUpdate?.Invoke(this, "Processing binary"); // This may throw other exceptions from the individual loaders as well - IFileFormatReader stream = FileFormatReader.Load(binaryStream, StatusUpdate); + IFileFormatReader stream = FileFormatReader.Load(binaryStream, loadOptions, StatusUpdate); if (stream == null) { throw new InvalidOperationException("Could not determine the binary file format"); } diff --git a/Il2CppInspector.GUI/MainWindow.xaml.cs b/Il2CppInspector.GUI/MainWindow.xaml.cs index 5783b94..ca15900 100644 --- a/Il2CppInspector.GUI/MainWindow.xaml.cs +++ b/Il2CppInspector.GUI/MainWindow.xaml.cs @@ -114,19 +114,19 @@ namespace Il2CppInspectorGUI }; if (openFileDialog.ShowDialog() == true) { - await LoadBinaryAsync(openFileDialog.FileName); + await LoadBinaryAsync(openFileDialog.FileName, null); // TODO: loadOptions } } // Load the binary file - private async Task LoadBinaryAsync(string filename) { + private async Task LoadBinaryAsync(string filename, LoadOptions loadOptions) { var app = (App) Application.Current; areaBusyIndicator.Visibility = Visibility.Visible; btnSelectBinaryFile.Visibility = Visibility.Hidden; // Load the binary file - if (await app.LoadBinaryAsync(filename)) { + if (await app.LoadBinaryAsync(filename, loadOptions)) { // Binary loaded successfully areaBusyIndicator.Visibility = Visibility.Hidden; @@ -151,20 +151,20 @@ namespace Il2CppInspectorGUI }; if (openFileDialog.ShowDialog() == true) { - await LoadPackageAsync(openFileDialog.FileNames); + await LoadPackageAsync(openFileDialog.FileNames, null); // TODO: loadOptions } } // Load the package file - private async Task LoadPackageAsync(string filename) => await LoadPackageAsync(new[] { filename }); - private async Task LoadPackageAsync(IEnumerable filenames) { + private async Task LoadPackageAsync(string filename, LoadOptions loadOptions) => await LoadPackageAsync(new[] { filename }, loadOptions); + private async Task LoadPackageAsync(IEnumerable filenames, LoadOptions loadOptions) { var app = (App) Application.Current; areaBusyIndicator.Visibility = Visibility.Visible; grdFirstPage.Visibility = Visibility.Hidden; // Load the package - if (await app.LoadPackageAsync(filenames)) { + if (await app.LoadPackageAsync(filenames, loadOptions)) { // Package loaded successfully areaBusyIndicator.Visibility = Visibility.Hidden; @@ -594,7 +594,7 @@ namespace Il2CppInspectorGUI break; case var s when s.EndsWith(".apk") || s.EndsWith(".aab") || s.EndsWith(".ipa") || s.EndsWith(".xapk") || s.EndsWith(".zip"): - await LoadPackageAsync(s); + await LoadPackageAsync(s, null); // TODO: loadOptions break; } } @@ -607,17 +607,17 @@ namespace Il2CppInspectorGUI // Only load binary if metadata was successful if (btnSelectBinaryFile.Visibility == Visibility.Visible) - await LoadBinaryAsync(files[binaryIndex]); + await LoadBinaryAsync(files[binaryIndex], null); // TODO: loadOptions } // Split APK (files.Length >= 2) else { - await LoadPackageAsync(files); + await LoadPackageAsync(files, null); // TODO: loadOptions } } // Binary (on 2nd page) else if (btnSelectBinaryFile.Visibility == Visibility.Visible) if (files.Length == 1) - await LoadBinaryAsync(files[0]); + await LoadBinaryAsync(files[0], null); // TODO: loadOptions } }