From 138c2cec487d3351f8b2bbd90e62780bf4ba4d84 Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Wed, 8 Nov 2017 00:24:19 +0100 Subject: [PATCH] Merge GetFieldOffsetFromIndex into Il2CppInspector ctor --- Il2CppInspector/Il2CppBinary.cs | 10 ++++-- Il2CppInspector/Il2CppInspector.cs | 56 ++++++++++++++++++------------ Il2CppInspector/Metadata.cs | 1 + 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/Il2CppInspector/Il2CppBinary.cs b/Il2CppInspector/Il2CppBinary.cs index a15d219..7e1001d 100644 --- a/Il2CppInspector/Il2CppBinary.cs +++ b/Il2CppInspector/Il2CppBinary.cs @@ -17,7 +17,13 @@ namespace Il2CppInspector public Il2CppMetadataRegistration MetadataRegistration { get; protected set; } public uint[] MethodPointers { get; set; } - public int[] FieldOffsets { get; private set; } + + // NOTE: In versions <21 and earlier releases of v21, this array has the format: + // global field index => field offset + // In versions >=22 and later releases of v21, this array has the format: + // type index => RVA in image where the list of field offsets for the type start (4 bytes per field) + public int[] FieldOffsetData { get; private set; } + public List Types { get; } = new List(); protected Il2CppBinary(IFileFormatReader stream) { @@ -53,7 +59,7 @@ namespace Il2CppInspector CodeRegistration = image.ReadMappedObject(codeRegistration); MetadataRegistration = image.ReadMappedObject(metadataRegistration); MethodPointers = image.ReadMappedArray(CodeRegistration.pmethodPointers, (int) CodeRegistration.methodPointersCount); - FieldOffsets = image.ReadMappedArray(MetadataRegistration.pfieldOffsets, MetadataRegistration.fieldOffsetsCount); + FieldOffsetData = image.ReadMappedArray(MetadataRegistration.pfieldOffsets, MetadataRegistration.fieldOffsetsCount); var types = image.ReadMappedArray(MetadataRegistration.ptypes, MetadataRegistration.typesCount); for (int i = 0; i < MetadataRegistration.typesCount; i++) Types.Add(image.ReadMappedObject(types[i])); diff --git a/Il2CppInspector/Il2CppInspector.cs b/Il2CppInspector/Il2CppInspector.cs index d4f9627..d13c8c1 100644 --- a/Il2CppInspector/Il2CppInspector.cs +++ b/Il2CppInspector/Il2CppInspector.cs @@ -19,10 +19,10 @@ namespace Il2CppInspector // Shortcuts public Dictionary Strings => Metadata.Strings; - public Il2CppTypeDefinition[] TypeDefinitions => Metadata.Types; public List TypeUsages => Binary.Types; public Dictionary FieldDefaultValue { get; } = new Dictionary(); + public List FieldOffsets { get; } public Il2CppInspector(Il2CppBinary binary, Metadata metadata) { // Store stream representations @@ -91,6 +91,39 @@ namespace Il2CppInspector } FieldDefaultValue.Add(fdv.fieldIndex, value); } + + // Get all field offsets + + // Versions from 22 onwards use an array of pointers in Binary.FieldOffsetData + bool fieldOffsetsArePointers = (Metadata.Version >= 22); + + // Some variants of 21 also use an array of pointers + if (Metadata.Version == 21) { + var f = Binary.FieldOffsetData; + // We detect this by relying on the fact Module, Object, ValueType, Attribute, _Attribute and Int32 + // are always the first six defined types, and that all but Int32 have no fields + fieldOffsetsArePointers = (f[0] == 0 && f[1] == 0 && f[2] == 0 && f[3] == 0 && f[4] == 0 && f[5] > 0); + } + + // All older versions use values directly in the array + if (!fieldOffsetsArePointers) { + FieldOffsets = Binary.FieldOffsetData.ToList(); + } + // Convert pointer list into fields + else { + var offsets = new Dictionary(); + for (var i = 0; i < TypeDefinitions.Length; i++) { + var def = TypeDefinitions[i]; + var pFieldOffsets = Binary.FieldOffsetData[i]; + if (pFieldOffsets != 0) { + Binary.Image.Stream.Position = Binary.Image.MapVATR((uint) pFieldOffsets); + + for (var f = 0; f < def.field_count; f++) + offsets.Add(def.fieldStart + f, Binary.Image.Stream.ReadInt32()); + } + } + FieldOffsets = offsets.OrderBy(x => x.Key).Select(x => x.Value).ToList(); + } } public static List LoadFromFile(string codeFile, string metadataFile) { @@ -182,26 +215,5 @@ namespace Il2CppInspector } return ret; } - - public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType) { - // Versions from 22 onwards use an array of pointers in fieldOffsets - bool fieldOffsetsArePointers = (Metadata.Version >= 22); - - // Some variants of 21 also use an array of pointers - if (Metadata.Version == 21) { - var f = Binary.FieldOffsets; - fieldOffsetsArePointers = (f[0] == 0 && f[1] == 0 && f[2] == 0 && f[3] == 0 && f[4] == 0 && f[5] > 0); - } - - // All older versions use values directly in the array - if (!fieldOffsetsArePointers) { - var typeDef = TypeDefinitions[typeIndex]; - return Binary.FieldOffsets[typeDef.fieldStart + fieldIndexInType]; - } - - var ptr = Binary.FieldOffsets[typeIndex]; - Binary.Image.Stream.Position = Binary.Image.MapVATR((uint) ptr) + 4 * fieldIndexInType; - return Binary.Image.Stream.ReadInt32(); - } } } diff --git a/Il2CppInspector/Metadata.cs b/Il2CppInspector/Metadata.cs index 63efe69..293b4d6 100644 --- a/Il2CppInspector/Metadata.cs +++ b/Il2CppInspector/Metadata.cs @@ -53,6 +53,7 @@ namespace Il2CppInspector FieldDefaultValues = ReadArray(Header.fieldDefaultValuesOffset, Header.fieldDefaultValuesCount / Sizeof(typeof(Il2CppFieldDefaultValue))); // TODO: Events, Properties, ParameterDefaultValue, GenericParameters, ParameterConstraints, GenericContainers, Interfaces, MetadataUsage, CustomAttributes + // Get all string literals Position = Header.stringOffset; while (Position < Header.stringOffset + Header.stringCount) Strings.Add((int)Position - Header.stringOffset, ReadNullTerminatedString());