Formats: Add option for multiple load strategies per sub-image

This commit is contained in:
Katy Coe
2020-12-14 02:52:57 +01:00
parent 14f4e034b0
commit 7878193f74
3 changed files with 30 additions and 16 deletions

View File

@@ -21,15 +21,16 @@ namespace Il2CppInspector
long Length { get; } long Length { get; }
uint NumImages { get; } uint NumImages { get; }
string DefaultFilename { get; } string DefaultFilename { get; }
bool IsModified { get; } bool IsModified { get; }
IEnumerable<IFileFormatReader> Images { get; } IEnumerable<IFileFormatReader> Images { get; } // Each child image of this object (eg. 32/64-bit versions in Fat MachO file)
IFileFormatReader this[uint index] { get; } IFileFormatReader this[uint index] { get; } // With no additional override, one object = one file, this[0] == this
long Position { get; set; } long Position { get; set; }
string Format { get; } string Format { get; }
string Arch { get; } string Arch { get; }
int Bits { get; } int Bits { get; }
ulong GlobalOffset { get; } // The virtual address where the code section (.text) would be loaded in memory 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) ulong ImageBase { get; } // The virtual address of where the image would be loaded in memory (same as GlobalOffset except for PE)
IEnumerable<IFileFormatReader> TryNextLoadStrategy(); // Some images can be loaded multiple ways, eg. default, packed
Dictionary<string, Symbol> GetSymbolTable(); Dictionary<string, Symbol> GetSymbolTable();
uint[] GetFunctionTable(); uint[] GetFunctionTable();
IEnumerable<Export> GetExports(); IEnumerable<Export> GetExports();
@@ -184,9 +185,12 @@ namespace Il2CppInspector
// Confirm file is valid and set up RVA mappings // Confirm file is valid and set up RVA mappings
protected virtual bool Init() => throw new NotImplementedException(); 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"); 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<IFileFormatReader> TryNextLoadStrategy() { yield return this; }
// Find search locations in the symbol table for Il2Cpp data // Find search locations in the symbol table for Il2Cpp data
public virtual Dictionary<string, Symbol> GetSymbolTable() => new Dictionary<string, Symbol>(); public virtual Dictionary<string, Symbol> GetSymbolTable() => new Dictionary<string, Symbol>();

View File

@@ -95,12 +95,16 @@ namespace Il2CppInspector
protected Il2CppBinary(IFileFormatReader stream, EventHandler<string> statusCallback = null) { protected Il2CppBinary(IFileFormatReader stream, EventHandler<string> statusCallback = null) {
Image = stream; Image = stream;
OnStatusUpdate = statusCallback; OnStatusUpdate = statusCallback;
StatusUpdate($"Analyzing IL2CPP data for {Image.Format}/{Image.Arch} image");
DiscoverAPIExports(); DiscoverAPIExports();
} }
protected Il2CppBinary(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration, EventHandler<string> statusCallback = null) { protected Il2CppBinary(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration, EventHandler<string> statusCallback = null) {
Image = stream; Image = stream;
OnStatusUpdate = statusCallback; OnStatusUpdate = statusCallback;
StatusUpdate($"Analyzing IL2CPP data for {Image.Format}/{Image.Arch} image");
DiscoverAPIExports(); DiscoverAPIExports();
PrepareMetadata(codeRegistration, metadataRegistration); PrepareMetadata(codeRegistration, metadataRegistration);
} }
@@ -123,8 +127,12 @@ namespace Il2CppInspector
// Load binary without a global-metadata.dat available // Load binary without a global-metadata.dat available
public static Il2CppBinary Load(IFileFormatReader stream, double metadataVersion, EventHandler<string> statusCallback = null) { public static Il2CppBinary Load(IFileFormatReader stream, double metadataVersion, EventHandler<string> statusCallback = null) {
var inst = LoadImpl(stream, statusCallback); foreach (var loadedImage in stream.TryNextLoadStrategy()) {
return inst.FindRegistrationStructs(metadataVersion) ? inst : null; var inst = LoadImpl(stream, statusCallback);
if (inst.FindRegistrationStructs(metadataVersion))
return inst;
}
return null;
} }
// Load binary with a global-metadata.dat available // 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 // 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 // If it is not specified, data analysis will not be performed
public static Il2CppBinary Load(IFileFormatReader stream, Metadata metadata, EventHandler<string> statusCallback = null) { public static Il2CppBinary Load(IFileFormatReader stream, Metadata metadata, EventHandler<string> statusCallback = null) {
var inst = LoadImpl(stream, statusCallback); foreach (var loadedImage in stream.TryNextLoadStrategy()) {
return inst.FindRegistrationStructs(metadata) ? inst : null; var inst = LoadImpl(stream, statusCallback);
if (inst.FindRegistrationStructs(metadata))
return inst;
}
return null;
} }
// Save binary to file, overwriting if necessary // Save binary to file, overwriting if necessary
@@ -146,24 +158,24 @@ namespace Il2CppInspector
} }
// Initialize binary without a global-metadata.dat available // Initialize binary without a global-metadata.dat available
public bool FindRegistrationStructs(double metadataVersion, EventHandler<string> statusCallback = null) { public bool FindRegistrationStructs(double metadataVersion) {
Image.Version = metadataVersion; Image.Version = metadataVersion;
if (!((FindMetadataFromSymbols() ?? FindMetadataFromCode()) is var ptrs)) if (!((FindMetadataFromSymbols() ?? FindMetadataFromCode()) is (ulong code, ulong meta)))
return false; return false;
PrepareMetadata(ptrs.Value.Item1, ptrs.Value.Item2); PrepareMetadata(code, meta);
return true; return true;
} }
// Initialize binary with a global-metadata.dat available // Initialize binary with a global-metadata.dat available
public bool FindRegistrationStructs(Metadata metadata, EventHandler<string> statusCallback = null) { public bool FindRegistrationStructs(Metadata metadata) {
Image.Version = metadata.Version; Image.Version = metadata.Version;
if (!((FindMetadataFromSymbols() ?? FindMetadataFromCode() ?? FindMetadataFromData(metadata)) is var ptrs)) if (!((FindMetadataFromSymbols() ?? FindMetadataFromCode() ?? FindMetadataFromData(metadata)) is (ulong code, ulong meta)))
return false; return false;
PrepareMetadata(ptrs.Value.Item1, ptrs.Value.Item2, metadata); PrepareMetadata(code, meta);
return true; return true;
} }

View File

@@ -124,8 +124,6 @@ namespace Il2CppInspectorGUI
// Multi-image binaries may contain more than one Il2Cpp image // Multi-image binaries may contain more than one Il2Cpp image
AppModels.Clear(); AppModels.Clear();
foreach (var image in stream.Images) { foreach (var image in stream.Images) {
OnStatusUpdate?.Invoke(this, $"Analyzing IL2CPP data for {image.Format}/{image.Arch} image");
// Architecture-agnostic load attempt // Architecture-agnostic load attempt
try { try {
// If we can't load the IL2CPP data here, it's probably packed or obfuscated; ignore it // If we can't load the IL2CPP data here, it's probably packed or obfuscated; ignore it