From 227eb83b63c3ec93027e522877c835834766c294 Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Sun, 20 Oct 2019 18:59:59 +0200 Subject: [PATCH] Recognize v24 metadata from later Unity 2018 versions ("24.1") --- Il2CppInspector/Il2CppBinary.cs | 10 +++++----- Il2CppInspector/Il2CppBinaryClasses.cs | 14 +++++++------- Il2CppInspector/Il2CppInspector.cs | 2 +- Il2CppInspector/Metadata.cs | 23 +++++++++++++++++------ Il2CppInspector/MetadataClasses.cs | 23 ++++++++++++----------- Il2CppInspector/Reflection/Assembly.cs | 2 +- Il2CppInspector/Reflection/MethodInfo.cs | 2 +- 7 files changed, 44 insertions(+), 32 deletions(-) diff --git a/Il2CppInspector/Il2CppBinary.cs b/Il2CppInspector/Il2CppBinary.cs index a0b4bb1..0b08c9d 100644 --- a/Il2CppInspector/Il2CppBinary.cs +++ b/Il2CppInspector/Il2CppBinary.cs @@ -18,7 +18,7 @@ namespace Il2CppInspector public Il2CppCodeRegistration CodeRegistration { get; protected set; } public Il2CppMetadataRegistration MetadataRegistration { get; protected set; } - // Only for <=v24.0 + // Only for <=v24.1 public uint[] GlobalMethodPointers { get; set; } // NOTE: In versions <21 and earlier releases of v21, this array has the format: @@ -30,7 +30,7 @@ namespace Il2CppInspector // Every defined type public List Types { get; private set; } - // From later versions of v24 onwards, this structure is stored for each module (image) + // From v24.2 onwards, this structure is stored for each module (image) // One assembly may contain multiple modules public Dictionary Modules { get; private set; } @@ -71,12 +71,12 @@ namespace Il2CppInspector CodeRegistration = image.ReadMappedObject(codeRegistration); MetadataRegistration = image.ReadMappedObject(metadataRegistration); - // The global method pointer list was deprecated in later versions of v24 in favour of Il2CppCodeGenModule - if (Image.Stream.Version <= 24.0) + // The global method pointer list was deprecated in v24.2 in favour of Il2CppCodeGenModule + if (Image.Stream.Version <= 24.1) GlobalMethodPointers = image.ReadMappedArray(CodeRegistration.pmethodPointers, (int) CodeRegistration.methodPointersCount); // After v24 method pointers and RGCTX data were stored in Il2CppCodeGenModules - if (Image.Stream.Version >= 24.1) { + if (Image.Stream.Version >= 24.2) { Modules = new Dictionary(); // Array of pointers to Il2CppCodeGenModule diff --git a/Il2CppInspector/Il2CppBinaryClasses.cs b/Il2CppInspector/Il2CppBinaryClasses.cs index b2bfa35..e4a30bb 100644 --- a/Il2CppInspector/Il2CppBinaryClasses.cs +++ b/Il2CppInspector/Il2CppBinaryClasses.cs @@ -12,10 +12,10 @@ namespace Il2CppInspector // From class-internals.h / il2cpp-class-internals.h public class Il2CppCodeRegistration { - // Moved to Il2CppCodeGenModule in later versions of v24 - [Version(Max = 24.0)] + // Moved to Il2CppCodeGenModule in v24.2 + [Version(Max = 24.1)] public uint methodPointersCount; - [Version(Max = 24.0)] + [Version(Max = 24.1)] public uint pmethodPointers; public uint reversePInvokeWrapperCount; // (was renamed from delegateWrappersFromNativeToManagedCount in v22) @@ -60,14 +60,14 @@ namespace Il2CppInspector [Version(Min = 23)] public uint interopData; - // Added in later versions of metadata v24 - [Version(Min = 24.1)] + // Added in metadata v24.2 to replace methodPointers and methodPointersCount + [Version(Min = 24.2)] public uint codeGenModulesCount; - [Version(Min = 24.1)] + [Version(Min = 24.2)] public uint pcodeGenModules; } - // Introduced in metadata v24.1 (replaces method pointers in Il2CppCodeRegistration) + // Introduced in metadata v24.2 (replaces method pointers in Il2CppCodeRegistration) public class Il2CppCodeGenModule { public uint moduleName; diff --git a/Il2CppInspector/Il2CppInspector.cs b/Il2CppInspector/Il2CppInspector.cs index 5c5c04a..ba92e94 100644 --- a/Il2CppInspector/Il2CppInspector.cs +++ b/Il2CppInspector/Il2CppInspector.cs @@ -34,7 +34,7 @@ namespace Il2CppInspector public List FieldOffsets { get; } public List TypeUsages => Binary.Types; public Dictionary Modules => Binary.Modules; - public uint[] GlobalMethodPointers => Binary.GlobalMethodPointers; // <=v24.0 only + public uint[] GlobalMethodPointers => Binary.GlobalMethodPointers; // <=v24.1 only // TODO: Finish all file access in the constructor and eliminate the need for this public IFileFormatReader BinaryImage => Binary.Image; diff --git a/Il2CppInspector/Metadata.cs b/Il2CppInspector/Metadata.cs index 385ee1c..1f800ac 100644 --- a/Il2CppInspector/Metadata.cs +++ b/Il2CppInspector/Metadata.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; using NoisyCowStudios.Bin2Object; @@ -52,14 +53,15 @@ namespace Il2CppInspector // with each block always coming directly after the previous block, 4-byte aligned. We can use this to check the integrity of the data and // detect sub-versions. - // For metadata v24, the header can either be either 0x108 (24.0) or 0x110 (24.1) bytes long. Since 'stringLiteralOffset' is the first thing + // For metadata v24, the header can either be either 0x110 (24.0, 24.1) or 0x108 (24.2) bytes long. Since 'stringLiteralOffset' is the first thing // in the header after the sanity and version fields, and since it will always point directly to the first byte after the end of the header, - // we can use this value to determine the actual header length and therefore the IL2CPP metadata sub-version used. + // we can use this value to determine the actual header length and therefore narrow down the metadata version to 24.0/24.1 or 24.2. var realHeaderLength = Header.stringLiteralOffset; + if (realHeaderLength != Sizeof(typeof(Il2CppGlobalMetadataHeader))) { if (Version == 24.0) { - Version = 24.1; + Version = 24.2; Header = ReadObject(0); } } @@ -72,9 +74,18 @@ namespace Il2CppInspector Images = ReadArray(Header.imagesOffset, Header.imagesCount / Sizeof(typeof(Il2CppImageDefinition))); // As an additional sanity check, all images in the metadata should have Mono.Cecil.MetadataToken == 1 - foreach (var i in Images) - if (i.token != 1) - throw new Exception("ERROR: Could not verify the integrity of the metadata file image list"); + // In metadata v24.1, two extra fields were added which will cause the below test to fail. + // In that case, we can then adjust the version number and reload + if (Images.Any(x => x.token != 1)) + if (Version == 24.0) { + Version = 24.1; + + // No need to re-read the header, it's the same for both sub-versions + Images = ReadArray(Header.imagesOffset, Header.imagesCount / Sizeof(typeof(Il2CppImageDefinition))); + } + + if (Images.Any(x => x.token != 1)) + throw new Exception("ERROR: Could not verify the integrity of the metadata file image list"); Types = ReadArray(Header.typeDefinitionsOffset, Header.typeDefinitionsCount / Sizeof(typeof(Il2CppTypeDefinition))); Methods = ReadArray(Header.methodsOffset, Header.methodsCount / Sizeof(typeof(Il2CppMethodDefinition))); diff --git a/Il2CppInspector/MetadataClasses.cs b/Il2CppInspector/MetadataClasses.cs index 9783111..aa78b6b 100644 --- a/Il2CppInspector/MetadataClasses.cs +++ b/Il2CppInspector/MetadataClasses.cs @@ -12,7 +12,8 @@ namespace Il2CppInspector // Unity 5.6.2p3 -> v23 // Unity 5.6.4f1 -> v23 // Unity 2017.2f3 -> v24 - // Unity 2019.2.8f1 -> v24.1 + // Unity 2018.3.0f2 -> v24.1 + // Unity 2019.2.8f1 -> v24.2 // From il2cpp-metadata.h #pragma warning disable CS0649 @@ -62,9 +63,9 @@ namespace Il2CppInspector public int typeDefinitionsOffset; // Il2CppTypeDefinition public int typeDefinitionsCount; - [Version(Max = 24.0)] + [Version(Max = 24.1)] public int rgctxEntriesOffset; // Il2CppRGCTXDefinition - [Version(Max = 24.0)] + [Version(Max = 24.1)] public int rgctxEntriesCount; public int imagesOffset; // Il2CppImageDefinition @@ -135,7 +136,7 @@ namespace Il2CppInspector public int nameIndex; public int namespaceIndex; - // Removed in later versions of metadata v24 + // Removed in metadata v24.1 [Version(Max = 24.0)] public int customAttributeIndex; @@ -146,9 +147,9 @@ namespace Il2CppInspector public int parentIndex; public int elementTypeIndex; // we can probably remove this one. Only used for enums - [Version(Max = 24.0)] + [Version(Max = 24.1)] public int rgctxStartIndex; - [Version(Max = 24.0)] + [Version(Max = 24.1)] public int rgctxCount; public int genericContainerIndex; @@ -207,15 +208,15 @@ namespace Il2CppInspector public int genericContainerIndex; - [Version(Max = 24.0)] + [Version(Max = 24.1)] public int methodIndex; - [Version(Max = 24.0)] + [Version(Max = 24.1)] public int invokerIndex; - [Version(Max = 24.0)] + [Version(Max = 24.1)] public int reversePInvokeWrapperIndex; // (was renamed from delegateWrapperIndex in v22) - [Version(Max = 24.0)] + [Version(Max = 24.1)] public int rgctxStartIndex; - [Version(Max = 24.0)] + [Version(Max = 24.1)] public int rgctxCount; public uint token; diff --git a/Il2CppInspector/Reflection/Assembly.cs b/Il2CppInspector/Reflection/Assembly.cs index 2987aa1..4eb9619 100644 --- a/Il2CppInspector/Reflection/Assembly.cs +++ b/Il2CppInspector/Reflection/Assembly.cs @@ -43,7 +43,7 @@ namespace Il2CppInspector.Reflection { } // Find corresponding module (we'll need this for method pointers) - if (Model.Package.Version >= 24.1) + if (Model.Package.Version >= 24.2) Module = Model.Package.Modules[FullName]; // Generate types in DefinedTypes from typeStart to typeStart+typeCount-1 diff --git a/Il2CppInspector/Reflection/MethodInfo.cs b/Il2CppInspector/Reflection/MethodInfo.cs index c034e73..5772ef6 100644 --- a/Il2CppInspector/Reflection/MethodInfo.cs +++ b/Il2CppInspector/Reflection/MethodInfo.cs @@ -39,7 +39,7 @@ namespace Il2CppInspector.Reflection if (Definition.methodIndex >= 0) { // Global method pointer array - if (pkg.Version < 24.1) { + if (pkg.Version <= 24.1) { VirtualAddress = pkg.GlobalMethodPointers[Definition.methodIndex]; }