API: Allow passing of load options to binary loaders
This commit is contained in:
@@ -190,7 +190,7 @@ namespace Il2CppInspector.CLI
|
|||||||
using (new Benchmark("Analyze IL2CPP data")) {
|
using (new Benchmark("Analyze IL2CPP data")) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
il2cppInspectors = Il2CppInspector.LoadFromPackage(options.BinaryFiles);
|
il2cppInspectors = Il2CppInspector.LoadFromPackage(options.BinaryFiles); // TODO: loadOptions
|
||||||
isExtractedFromPackage = true;
|
isExtractedFromPackage = true;
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
@@ -207,7 +207,7 @@ namespace Il2CppInspector.CLI
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
il2cppInspectors = Il2CppInspector.LoadFromFile(options.BinaryFiles.First(), options.MetadataFile);
|
il2cppInspectors = Il2CppInspector.LoadFromFile(options.BinaryFiles.First(), options.MetadataFile); // TODO: loadOptions
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
Console.Error.WriteLine(ex.Message);
|
Console.Error.WriteLine(ex.Message);
|
||||||
|
|||||||
@@ -58,14 +58,14 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
// ZipArchiveEntry does not support seeking so we have to close and re-open for each possible load format
|
// ZipArchiveEntry does not support seeking so we have to close and re-open for each possible load format
|
||||||
var binary = binaryFiles[index].Open();
|
var binary = binaryFiles[index].Open();
|
||||||
loaded = ElfReader32.Load(binary, OnStatusUpdate);
|
loaded = ElfReader32.Load(binary, LoadOptions, OnStatusUpdate);
|
||||||
binary.Close();
|
binary.Close();
|
||||||
|
|
||||||
if (loaded != null)
|
if (loaded != null)
|
||||||
return loaded;
|
return loaded;
|
||||||
|
|
||||||
binary = binaryFiles[index].Open();
|
binary = binaryFiles[index].Open();
|
||||||
loaded = ElfReader64.Load(binary, OnStatusUpdate);
|
loaded = ElfReader64.Load(binary, LoadOptions, OnStatusUpdate);
|
||||||
binary.Close();
|
binary.Close();
|
||||||
|
|
||||||
return loaded;
|
return loaded;
|
||||||
|
|||||||
@@ -58,14 +58,14 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
// ZipArchiveEntry does not support seeking so we have to close and re-open for each possible load format
|
// ZipArchiveEntry does not support seeking so we have to close and re-open for each possible load format
|
||||||
var binary = binaryFiles[index].Open();
|
var binary = binaryFiles[index].Open();
|
||||||
loaded = ElfReader32.Load(binary, OnStatusUpdate);
|
loaded = ElfReader32.Load(binary, LoadOptions, OnStatusUpdate);
|
||||||
binary.Close();
|
binary.Close();
|
||||||
|
|
||||||
if (loaded != null)
|
if (loaded != null)
|
||||||
return loaded;
|
return loaded;
|
||||||
|
|
||||||
binary = binaryFiles[index].Open();
|
binary = binaryFiles[index].Open();
|
||||||
loaded = ElfReader64.Load(binary, OnStatusUpdate);
|
loaded = ElfReader64.Load(binary, LoadOptions, OnStatusUpdate);
|
||||||
binary.Close();
|
binary.Close();
|
||||||
|
|
||||||
return loaded;
|
return loaded;
|
||||||
|
|||||||
@@ -97,17 +97,18 @@ namespace Il2CppInspector
|
|||||||
public class FileFormatReader
|
public class FileFormatReader
|
||||||
{
|
{
|
||||||
// Helper method to try all defined file formats when the contents of the binary is unknown
|
// Helper method to try all defined file formats when the contents of the binary is unknown
|
||||||
public static IFileFormatReader Load(string filename, EventHandler<string> statusCallback = null) => Load(new FileStream(filename, FileMode.Open, FileAccess.Read), statusCallback);
|
public static IFileFormatReader Load(string filename, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null)
|
||||||
|
=> Load(new FileStream(filename, FileMode.Open, FileAccess.Read), loadOptions, statusCallback);
|
||||||
|
|
||||||
public static IFileFormatReader Load(Stream stream, EventHandler<string> statusCallback = null) {
|
public static IFileFormatReader Load(Stream stream, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) {
|
||||||
var types = Assembly.GetExecutingAssembly().DefinedTypes
|
var types = Assembly.GetExecutingAssembly().DefinedTypes
|
||||||
.Where(x => x.ImplementedInterfaces.Contains(typeof(IFileFormatReader)) && !x.IsGenericTypeDefinition);
|
.Where(x => x.ImplementedInterfaces.Contains(typeof(IFileFormatReader)) && !x.IsGenericTypeDefinition);
|
||||||
|
|
||||||
foreach (var type in types) {
|
foreach (var type in types) {
|
||||||
try {
|
try {
|
||||||
if (type.GetMethod("Load", BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public,
|
if (type.GetMethod("Load", BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public,
|
||||||
null, new[] {typeof(Stream), typeof(EventHandler<string>)}, null)
|
null, new[] {typeof(Stream), typeof(LoadOptions), typeof(EventHandler<string>)}, null)
|
||||||
.Invoke(null, new object[] {stream, statusCallback}) is IFileFormatReader loaded)
|
.Invoke(null, new object[] {stream, loadOptions, statusCallback}) is IFileFormatReader loaded)
|
||||||
return loaded;
|
return loaded;
|
||||||
}
|
}
|
||||||
catch (TargetInvocationException ex) {
|
catch (TargetInvocationException ex) {
|
||||||
@@ -142,6 +143,9 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
public virtual int Bits => throw new NotImplementedException();
|
public virtual int Bits => throw new NotImplementedException();
|
||||||
|
|
||||||
|
// Extra parameters to be passed to a loader
|
||||||
|
protected LoadOptions LoadOptions;
|
||||||
|
|
||||||
public EventHandler<string> OnStatusUpdate { get; set; }
|
public EventHandler<string> OnStatusUpdate { get; set; }
|
||||||
|
|
||||||
protected void StatusUpdate(string status) => OnStatusUpdate?.Invoke(this, status);
|
protected void StatusUpdate(string status) => OnStatusUpdate?.Invoke(this, status);
|
||||||
@@ -153,12 +157,12 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T Load(string filename, EventHandler<string> statusCallback = null) {
|
public static T Load(string filename, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) {
|
||||||
using var stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
|
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<string> statusCallback = null) {
|
public static T Load(Stream stream, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) {
|
||||||
// Copy the original stream in case we modify it
|
// Copy the original stream in case we modify it
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
|
|
||||||
@@ -168,10 +172,11 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
var pe = (T) Activator.CreateInstance(typeof(T), ms);
|
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<string> statusCallback = null) {
|
private bool InitImpl(LoadOptions loadOptions, EventHandler<string> statusCallback) {
|
||||||
|
LoadOptions = loadOptions;
|
||||||
OnStatusUpdate = statusCallback;
|
OnStatusUpdate = statusCallback;
|
||||||
return Init();
|
return Init();
|
||||||
}
|
}
|
||||||
|
|||||||
15
Il2CppInspector.Common/FileFormatReaders/LoadOptions.cs
Normal file
15
Il2CppInspector.Common/FileFormatReaders/LoadOptions.cs
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@ namespace Il2CppInspector
|
|||||||
Endianness = Endianness.Little;
|
Endianness = Endianness.Little;
|
||||||
|
|
||||||
using var s = new MemoryStream(ReadBytes((int) arch.Size));
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -515,22 +515,22 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load from an AAB, IPA or one or more APK files
|
// Load from an AAB, IPA or one or more APK files
|
||||||
public static List<Il2CppInspector> LoadFromPackage(IEnumerable<string> packageFiles, bool silent = false) {
|
public static List<Il2CppInspector> LoadFromPackage(IEnumerable<string> packageFiles, LoadOptions loadOptions = null, bool silent = false) {
|
||||||
var streams = GetStreamsFromPackage(packageFiles, silent);
|
var streams = GetStreamsFromPackage(packageFiles, silent);
|
||||||
if (!streams.HasValue)
|
if (!streams.HasValue)
|
||||||
return null;
|
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
|
// Load from a binary file and metadata file
|
||||||
public static List<Il2CppInspector> LoadFromFile(string binaryFile, string metadataFile, bool silent = false)
|
public static List<Il2CppInspector> LoadFromFile(string binaryFile, string metadataFile, LoadOptions loadOptions = null, bool silent = false)
|
||||||
=> LoadFromStream(new FileStream(binaryFile, FileMode.Open, FileAccess.Read, FileShare.Read),
|
=> LoadFromStream(new FileStream(binaryFile, FileMode.Open, FileAccess.Read, FileShare.Read),
|
||||||
new MemoryStream(File.ReadAllBytes(metadataFile)),
|
new MemoryStream(File.ReadAllBytes(metadataFile)),
|
||||||
silent: silent);
|
loadOptions, silent: silent);
|
||||||
|
|
||||||
// Load from a binary stream and metadata stream
|
// Load from a binary stream and metadata stream
|
||||||
// Must be a seekable stream otherwise we catch a System.IO.NotSupportedException
|
// Must be a seekable stream otherwise we catch a System.IO.NotSupportedException
|
||||||
public static List<Il2CppInspector> LoadFromStream(Stream binaryStream, MemoryStream metadataStream, EventHandler<string> statusCallback = null, bool silent = false) {
|
public static List<Il2CppInspector> LoadFromStream(Stream binaryStream, MemoryStream metadataStream, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null, bool silent = false) {
|
||||||
|
|
||||||
// Silent operation if requested
|
// Silent operation if requested
|
||||||
var stdout = Console.Out;
|
var stdout = Console.Out;
|
||||||
@@ -553,7 +553,7 @@ namespace Il2CppInspector
|
|||||||
// Load the il2cpp code file (try all available file formats)
|
// Load the il2cpp code file (try all available file formats)
|
||||||
IFileFormatReader stream;
|
IFileFormatReader stream;
|
||||||
try {
|
try {
|
||||||
stream = FileFormatReader.Load(binaryStream, statusCallback);
|
stream = FileFormatReader.Load(binaryStream, loadOptions, statusCallback);
|
||||||
|
|
||||||
if (stream == null)
|
if (stream == null)
|
||||||
throw new InvalidOperationException("Unsupported executable file format");
|
throw new InvalidOperationException("Unsupported executable file format");
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ namespace Il2CppInspectorGUI
|
|||||||
private void StatusUpdate(object sender, string status) => OnStatusUpdate?.Invoke(sender, status);
|
private void StatusUpdate(object sender, string status) => OnStatusUpdate?.Invoke(sender, status);
|
||||||
|
|
||||||
// Attempt to load an IL2CPP application package (APK or IPA)
|
// Attempt to load an IL2CPP application package (APK or IPA)
|
||||||
public async Task<bool> LoadPackageAsync(IEnumerable<string> packageFiles) {
|
public async Task<bool> LoadPackageAsync(IEnumerable<string> packageFiles, LoadOptions loadOptions) {
|
||||||
IsExtractedFromPackage = false;
|
IsExtractedFromPackage = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -54,7 +54,7 @@ namespace Il2CppInspectorGUI
|
|||||||
if (streams == null)
|
if (streams == null)
|
||||||
throw new InvalidOperationException("The supplied package is not an APK or IPA file, or does not contain a complete IL2CPP application");
|
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;
|
return IsExtractedFromPackage;
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
@@ -85,18 +85,18 @@ namespace Il2CppInspectorGUI
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Attempt to load an IL2CPP binary file
|
// Attempt to load an IL2CPP binary file
|
||||||
public async Task<bool> LoadBinaryAsync(string binaryFile) {
|
public async Task<bool> LoadBinaryAsync(string binaryFile, LoadOptions loadOptions) {
|
||||||
var stream = new MemoryStream(await File.ReadAllBytesAsync(binaryFile));
|
var stream = new MemoryStream(await File.ReadAllBytesAsync(binaryFile));
|
||||||
return await LoadBinaryAsync(stream);
|
return await LoadBinaryAsync(stream, loadOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<bool> LoadBinaryAsync(Stream binaryStream) =>
|
public Task<bool> LoadBinaryAsync(Stream binaryStream, LoadOptions loadOptions) =>
|
||||||
Task.Run(() => {
|
Task.Run(() => {
|
||||||
try {
|
try {
|
||||||
OnStatusUpdate?.Invoke(this, "Processing binary");
|
OnStatusUpdate?.Invoke(this, "Processing binary");
|
||||||
|
|
||||||
// This may throw other exceptions from the individual loaders as well
|
// 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) {
|
if (stream == null) {
|
||||||
throw new InvalidOperationException("Could not determine the binary file format");
|
throw new InvalidOperationException("Could not determine the binary file format");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,19 +114,19 @@ namespace Il2CppInspectorGUI
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (openFileDialog.ShowDialog() == true) {
|
if (openFileDialog.ShowDialog() == true) {
|
||||||
await LoadBinaryAsync(openFileDialog.FileName);
|
await LoadBinaryAsync(openFileDialog.FileName, null); // TODO: loadOptions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the binary file
|
// Load the binary file
|
||||||
private async Task LoadBinaryAsync(string filename) {
|
private async Task LoadBinaryAsync(string filename, LoadOptions loadOptions) {
|
||||||
var app = (App) Application.Current;
|
var app = (App) Application.Current;
|
||||||
|
|
||||||
areaBusyIndicator.Visibility = Visibility.Visible;
|
areaBusyIndicator.Visibility = Visibility.Visible;
|
||||||
btnSelectBinaryFile.Visibility = Visibility.Hidden;
|
btnSelectBinaryFile.Visibility = Visibility.Hidden;
|
||||||
|
|
||||||
// Load the binary file
|
// Load the binary file
|
||||||
if (await app.LoadBinaryAsync(filename)) {
|
if (await app.LoadBinaryAsync(filename, loadOptions)) {
|
||||||
// Binary loaded successfully
|
// Binary loaded successfully
|
||||||
areaBusyIndicator.Visibility = Visibility.Hidden;
|
areaBusyIndicator.Visibility = Visibility.Hidden;
|
||||||
|
|
||||||
@@ -151,20 +151,20 @@ namespace Il2CppInspectorGUI
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (openFileDialog.ShowDialog() == true) {
|
if (openFileDialog.ShowDialog() == true) {
|
||||||
await LoadPackageAsync(openFileDialog.FileNames);
|
await LoadPackageAsync(openFileDialog.FileNames, null); // TODO: loadOptions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the package file
|
// Load the package file
|
||||||
private async Task LoadPackageAsync(string filename) => await LoadPackageAsync(new[] { filename });
|
private async Task LoadPackageAsync(string filename, LoadOptions loadOptions) => await LoadPackageAsync(new[] { filename }, loadOptions);
|
||||||
private async Task LoadPackageAsync(IEnumerable<string> filenames) {
|
private async Task LoadPackageAsync(IEnumerable<string> filenames, LoadOptions loadOptions) {
|
||||||
var app = (App) Application.Current;
|
var app = (App) Application.Current;
|
||||||
|
|
||||||
areaBusyIndicator.Visibility = Visibility.Visible;
|
areaBusyIndicator.Visibility = Visibility.Visible;
|
||||||
grdFirstPage.Visibility = Visibility.Hidden;
|
grdFirstPage.Visibility = Visibility.Hidden;
|
||||||
|
|
||||||
// Load the package
|
// Load the package
|
||||||
if (await app.LoadPackageAsync(filenames)) {
|
if (await app.LoadPackageAsync(filenames, loadOptions)) {
|
||||||
// Package loaded successfully
|
// Package loaded successfully
|
||||||
areaBusyIndicator.Visibility = Visibility.Hidden;
|
areaBusyIndicator.Visibility = Visibility.Hidden;
|
||||||
|
|
||||||
@@ -594,7 +594,7 @@ namespace Il2CppInspectorGUI
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case var s when s.EndsWith(".apk") || s.EndsWith(".aab") || s.EndsWith(".ipa") || s.EndsWith(".xapk") || s.EndsWith(".zip"):
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -607,17 +607,17 @@ namespace Il2CppInspectorGUI
|
|||||||
|
|
||||||
// Only load binary if metadata was successful
|
// Only load binary if metadata was successful
|
||||||
if (btnSelectBinaryFile.Visibility == Visibility.Visible)
|
if (btnSelectBinaryFile.Visibility == Visibility.Visible)
|
||||||
await LoadBinaryAsync(files[binaryIndex]);
|
await LoadBinaryAsync(files[binaryIndex], null); // TODO: loadOptions
|
||||||
}
|
}
|
||||||
// Split APK (files.Length >= 2)
|
// Split APK (files.Length >= 2)
|
||||||
else {
|
else {
|
||||||
await LoadPackageAsync(files);
|
await LoadPackageAsync(files, null); // TODO: loadOptions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Binary (on 2nd page)
|
// Binary (on 2nd page)
|
||||||
else if (btnSelectBinaryFile.Visibility == Visibility.Visible)
|
else if (btnSelectBinaryFile.Visibility == Visibility.Visible)
|
||||||
if (files.Length == 1)
|
if (files.Length == 1)
|
||||||
await LoadBinaryAsync(files[0]);
|
await LoadBinaryAsync(files[0], null); // TODO: loadOptions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user