IL2CPP: Change metadata and binary to derive from BinaryObjectStream
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user