IL2CPP: Change metadata and binary to derive from BinaryObjectStream

This commit is contained in:
Katy Coe
2020-12-21 06:37:29 +01:00
parent 620d985b71
commit c00b474f33
31 changed files with 172 additions and 179 deletions

View File

@@ -17,7 +17,7 @@ namespace Il2CppInspector
{
public abstract partial class Il2CppBinary
{
public IFileFormatReader Image { get; }
public IFileFormatStream Image { get; }
// IL2CPP-only API exports with decrypted names
public Dictionary<string, ulong> APIExports { get; } = new Dictionary<string, ulong>();
@@ -92,7 +92,7 @@ namespace Il2CppInspector
private bool isModified = false;
public bool IsModified => Image.IsModified || isModified;
protected Il2CppBinary(IFileFormatReader stream, EventHandler<string> statusCallback = null) {
protected Il2CppBinary(IFileFormatStream stream, EventHandler<string> statusCallback = null) {
Image = stream;
OnStatusUpdate = statusCallback;
@@ -100,7 +100,7 @@ namespace Il2CppInspector
DiscoverAPIExports();
}
protected Il2CppBinary(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration, EventHandler<string> statusCallback = null) {
protected Il2CppBinary(IFileFormatStream stream, uint codeRegistration, uint metadataRegistration, EventHandler<string> statusCallback = null) {
Image = stream;
OnStatusUpdate = statusCallback;
@@ -110,7 +110,7 @@ namespace Il2CppInspector
}
// Load and initialize a binary of any supported architecture
private static Il2CppBinary LoadImpl(IFileFormatReader stream, EventHandler<string> statusCallback) {
private static Il2CppBinary LoadImpl(IFileFormatStream stream, EventHandler<string> statusCallback) {
// Get type from image architecture
var type = Assembly.GetExecutingAssembly().GetType("Il2CppInspector.Il2CppBinary" + stream.Arch.ToUpper());
if (type == null)
@@ -118,15 +118,15 @@ namespace Il2CppInspector
// Set width of long (convert to sizeof(int) for 32-bit files)
if (stream[0].Bits == 32) {
stream[0].Stream.PrimitiveMappings.Add(typeof(long), typeof(int));
stream[0].Stream.PrimitiveMappings.Add(typeof(ulong), typeof(uint));
stream[0].AddPrimitiveMapping(typeof(long), typeof(int));
stream[0].AddPrimitiveMapping(typeof(ulong), typeof(uint));
}
return (Il2CppBinary) Activator.CreateInstance(type, stream[0], statusCallback);
}
// Load binary without a global-metadata.dat available
public static Il2CppBinary Load(IFileFormatReader stream, double metadataVersion, EventHandler<string> statusCallback = null) {
public static Il2CppBinary Load(IFileFormatStream stream, double metadataVersion, EventHandler<string> statusCallback = null) {
foreach (var loadedImage in stream.TryNextLoadStrategy()) {
var inst = LoadImpl(stream, statusCallback);
if (inst.FindRegistrationStructs(metadataVersion))
@@ -140,7 +140,7 @@ 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, EventHandler<string> statusCallback = null) {
public static Il2CppBinary Load(IFileFormatStream stream, Metadata metadata, EventHandler<string> statusCallback = null) {
foreach (var loadedImage in stream.TryNextLoadStrategy()) {
var inst = LoadImpl(stream, statusCallback);
if (inst.FindRegistrationStructs(metadata))
@@ -154,7 +154,7 @@ namespace Il2CppInspector
public void SaveToFile(string pathname) {
Image.Position = 0;
using (var outFile = new FileStream(pathname, FileMode.Create, FileAccess.Write))
Image.Stream.BaseStream.CopyTo(outFile);
Image.CopyTo(outFile);
}
// Initialize binary without a global-metadata.dat available
@@ -244,7 +244,7 @@ namespace Il2CppInspector
}
// Architecture-specific search function
protected abstract (ulong, ulong) ConsiderCode(IFileFormatReader image, uint loc);
protected abstract (ulong, ulong) ConsiderCode(IFileFormatStream image, uint loc);
// Load all of the discovered metadata in the binary
private void PrepareMetadata(ulong codeRegistration, ulong metadataRegistration, Metadata metadata = null) {

View File

@@ -66,7 +66,7 @@ namespace Il2CppInspector
public Dictionary<Il2CppMethodSpec, int> GenericMethodInvokerIndices => Binary.GenericMethodInvokerIndices;
// TODO: Finish all file access in the constructor and eliminate the need for this
public IFileFormatReader BinaryImage => Binary.Image;
public IFileFormatStream BinaryImage => Binary.Image;
private (ulong MetadataAddress, object Value)? getDefaultValue(int typeIndex, int dataIndex) {
// No default
@@ -543,7 +543,7 @@ namespace Il2CppInspector
// Load the metadata file
Metadata metadata;
try {
metadata = new Metadata(metadataStream, statusCallback);
metadata = Metadata.FromStream(metadataStream, statusCallback);
}
catch (Exception ex) {
Console.Error.WriteLine(ex.Message);
@@ -554,9 +554,9 @@ namespace Il2CppInspector
Console.WriteLine("Detected metadata version " + metadata.Version);
// Load the il2cpp code file (try all available file formats)
IFileFormatReader stream;
IFileFormatStream stream;
try {
stream = FileFormatReader.Load(binaryStream, loadOptions, statusCallback);
stream = FileFormatStream.Load(binaryStream, loadOptions, statusCallback);
if (stream == null)
throw new InvalidOperationException("Unsupported executable file format");
@@ -571,7 +571,7 @@ namespace Il2CppInspector
var processors = new List<Il2CppInspector>();
foreach (var image in stream.Images) {
Console.WriteLine("Container format: " + image.Format);
Console.WriteLine("Container endianness: " + ((BinaryObjectReader) image).Endianness);
Console.WriteLine("Container endianness: " + ((BinaryObjectStream) image).Endianness);
Console.WriteLine("Architecture word size: {0}-bit", image.Bits);
Console.WriteLine("Instruction set: " + image.Arch);
Console.WriteLine("Global offset: 0x{0:X16}", image.GlobalOffset);

View File

@@ -14,44 +14,60 @@ using NoisyCowStudios.Bin2Object;
namespace Il2CppInspector
{
public class Metadata : BinaryObjectReader
public class Metadata : BinaryObjectStream
{
public Il2CppGlobalMetadataHeader Header { get; set; }
public Il2CppAssemblyDefinition[] Assemblies { get; }
public Il2CppImageDefinition[] Images { get; }
public Il2CppTypeDefinition[] Types { get; }
public Il2CppMethodDefinition[] Methods { get; }
public Il2CppParameterDefinition[] Params { get; }
public Il2CppFieldDefinition[] Fields { get; }
public Il2CppFieldDefaultValue[] FieldDefaultValues { get; }
public Il2CppParameterDefaultValue[] ParameterDefaultValues { get; }
public Il2CppPropertyDefinition[] Properties { get; }
public Il2CppEventDefinition[] Events { get; }
public Il2CppGenericContainer[] GenericContainers { get; }
public Il2CppGenericParameter[] GenericParameters { get; }
public Il2CppCustomAttributeTypeRange[] AttributeTypeRanges { get; }
public Il2CppInterfaceOffsetPair[] InterfaceOffsets { get; }
public Il2CppMetadataUsageList[] MetadataUsageLists { get; }
public Il2CppMetadataUsagePair[] MetadataUsagePairs { get; }
public Il2CppFieldRef[] FieldRefs { get; }
public Il2CppAssemblyDefinition[] Assemblies { get; set; }
public Il2CppImageDefinition[] Images { get; set; }
public Il2CppTypeDefinition[] Types { get; set; }
public Il2CppMethodDefinition[] Methods { get; set; }
public Il2CppParameterDefinition[] Params { get; set; }
public Il2CppFieldDefinition[] Fields { get; set; }
public Il2CppFieldDefaultValue[] FieldDefaultValues { get; set; }
public Il2CppParameterDefaultValue[] ParameterDefaultValues { get; set; }
public Il2CppPropertyDefinition[] Properties { get; set; }
public Il2CppEventDefinition[] Events { get; set; }
public Il2CppGenericContainer[] GenericContainers { get; set; }
public Il2CppGenericParameter[] GenericParameters { get; set; }
public Il2CppCustomAttributeTypeRange[] AttributeTypeRanges { get; set; }
public Il2CppInterfaceOffsetPair[] InterfaceOffsets { get; set; }
public Il2CppMetadataUsageList[] MetadataUsageLists { get; set; }
public Il2CppMetadataUsagePair[] MetadataUsagePairs { get; set; }
public Il2CppFieldRef[] FieldRefs { get; set; }
public int[] InterfaceUsageIndices { get; }
public int[] NestedTypeIndices { get; }
public int[] AttributeTypeIndices { get; }
public int[] GenericConstraintIndices { get; }
public uint[] VTableMethodIndices { get; }
public string[] StringLiterals { get; }
public int[] InterfaceUsageIndices { get; set; }
public int[] NestedTypeIndices { get; set; }
public int[] AttributeTypeIndices { get; set; }
public int[] GenericConstraintIndices { get; set; }
public uint[] VTableMethodIndices { get; set; }
public string[] StringLiterals { get; set; }
public Dictionary<int, string> Strings { get; } = new Dictionary<int, string>();
// Set if something in the metadata has been modified / decrypted
public bool IsModified { get; } = false;
public bool IsModified { get; private set; } = false;
public Metadata(MemoryStream stream, EventHandler<string> statusCallback = null) : base(stream)
// Status update callback
private EventHandler<string> OnStatusUpdate { get; set; }
private void StatusUpdate(string status) => OnStatusUpdate?.Invoke(this, status);
// Initialize metadata object from a stream
public static Metadata FromStream(MemoryStream stream, EventHandler<string> statusCallback = null) {
var metadata = new Metadata(statusCallback);
stream.Position = 0;
stream.CopyTo(metadata);
metadata.Position = 0;
metadata.Initialize();
return metadata;
}
private Metadata(EventHandler<string> statusCallback = null) : base() => OnStatusUpdate = statusCallback;
private void Initialize()
{
// Pre-processing hook
var pluginResult = PluginHooks.PreProcessMetadata(stream);
var pluginResult = PluginHooks.PreProcessMetadata(this);
IsModified = pluginResult.IsStreamModified;
// Read metadata header
@@ -185,7 +201,7 @@ namespace Il2CppInspector
if (stringOffsets.Except(Strings.Keys).Any()) {
Console.WriteLine("Decrypting strings...");
statusCallback?.Invoke(this, "Decrypting strings");
StatusUpdate("Decrypting strings");
// There may be zero-padding at the end of the last string since counts seem to be word-aligned
// Find the true location one byte after the final character of the final string
@@ -209,13 +225,10 @@ namespace Il2CppInspector
}
// Write changes back in case the user wants to save the metadata file
using (var sw = new BinaryObjectWriter(BaseStream, Endianness, leaveOpen: true)) {
sw.Version = Version;
sw.Position = Header.stringOffset;
foreach (var str in Strings.OrderBy(s => s.Key))
sw.WriteNullTerminatedString(str.Value);
sw.Flush();
}
Position = Header.stringOffset;
foreach (var str in Strings.OrderBy(s => s.Key))
WriteNullTerminatedString(str.Value);
Flush();
IsModified = true;
}
@@ -235,7 +248,7 @@ namespace Il2CppInspector
public void SaveToFile(string pathname) {
Position = 0;
using (var outFile = new FileStream(pathname, FileMode.Create, FileAccess.Write))
BaseStream.CopyTo(outFile);
CopyTo(outFile);
}
internal int Sizeof(Type type) => Sizeof(type, Version);

View File

@@ -801,17 +801,9 @@ namespace Il2CppInspector
MetadataRegistration.methodReferences = 0;
// Write changes to stream
using var sw = new BinaryObjectWriter(Image.Stream.BaseStream, Image.Stream.Endianness, true);
sw.Version = Image.Version;
// Set width of long (convert to sizeof(int) for 32-bit files)
if (Image.Bits == 32) {
sw.PrimitiveMappings.Add(typeof(long), typeof(int));
sw.PrimitiveMappings.Add(typeof(ulong), typeof(uint));
}
sw.WriteObject(Image.MapVATR(CodeRegistrationPointer), CodeRegistration);
sw.WriteObject(Image.MapVATR(MetadataRegistrationPointer), MetadataRegistration);
Image.WriteObject(Image.MapVATR(CodeRegistrationPointer), CodeRegistration);
Image.WriteObject(Image.MapVATR(MetadataRegistrationPointer), MetadataRegistration);
isModified = true;
StatusUpdate("Analyzing IL2CPP image");