From 2a2617674a22bd1cbb512e65a20410f3b0260a42 Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Tue, 7 Nov 2017 07:04:46 +0100 Subject: [PATCH] Collect field defaults into Il2CppInspector.FieldDefaultValue on load --- Il2CppInspector/Il2CppInspector.cs | 156 +++++++++++++----------- Il2CppInspector/Metadata.cs | 1 + Il2CppInspector/Reflection/Assembly.cs | 2 +- Il2CppInspector/Reflection/FieldInfo.cs | 4 +- Il2CppInspector/Reflection/TypeInfo.cs | 6 +- 5 files changed, 93 insertions(+), 76 deletions(-) diff --git a/Il2CppInspector/Il2CppInspector.cs b/Il2CppInspector/Il2CppInspector.cs index f92c516..d4f9627 100644 --- a/Il2CppInspector/Il2CppInspector.cs +++ b/Il2CppInspector/Il2CppInspector.cs @@ -17,9 +17,80 @@ namespace Il2CppInspector public Il2CppBinary Binary { get; } public Metadata Metadata { get; } + // Shortcuts + public Dictionary Strings => Metadata.Strings; + + public Il2CppTypeDefinition[] TypeDefinitions => Metadata.Types; + public List TypeUsages => Binary.Types; + public Dictionary FieldDefaultValue { get; } = new Dictionary(); + public Il2CppInspector(Il2CppBinary binary, Metadata metadata) { + // Store stream representations Binary = binary; Metadata = metadata; + + // Get all field default values + foreach (var fdv in Metadata.FieldDefaultValues) { + // No default + if (fdv.dataIndex == -1) { + FieldDefaultValue.Add(fdv.fieldIndex, null); + continue; + } + + // Get pointer in binary to default value + var pValue = Metadata.Header.fieldAndParameterDefaultValueDataOffset + fdv.dataIndex; + var type = TypeUsages[fdv.typeIndex]; + + // Default value is null + if (pValue == 0) { + FieldDefaultValue.Add(fdv.fieldIndex, null); + continue; + } + + object value = null; + Metadata.Position = pValue; + switch (type.type) { + case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: + value = Metadata.ReadBoolean(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_U1: + case Il2CppTypeEnum.IL2CPP_TYPE_I1: + value = Metadata.ReadByte(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: + value = Metadata.ReadChar(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_U2: + value = Metadata.ReadUInt16(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_I2: + value = Metadata.ReadInt16(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_U4: + value = Metadata.ReadUInt32(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_I4: + value = Metadata.ReadInt32(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_U8: + value = Metadata.ReadUInt64(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_I8: + value = Metadata.ReadInt64(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_R4: + value = Metadata.ReadSingle(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_R8: + value = Metadata.ReadDouble(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_STRING: + var uiLen = Metadata.ReadInt32(); + value = Encoding.UTF8.GetString(Metadata.ReadBytes(uiLen)); + break; + } + FieldDefaultValue.Add(fdv.fieldIndex, value); + } } public static List LoadFromFile(string codeFile, string metadataFile) { @@ -37,9 +108,9 @@ namespace Il2CppInspector var memoryStream = new MemoryStream(File.ReadAllBytes(codeFile)); IFileFormatReader stream = (((IFileFormatReader) ElfReader.Load(memoryStream) ?? - PEReader.Load(memoryStream)) ?? - MachOReader.Load(memoryStream)) ?? - UBReader.Load(memoryStream); + PEReader.Load(memoryStream)) ?? + MachOReader.Load(memoryStream)) ?? + UBReader.Load(memoryStream); if (stream == null) { Console.Error.WriteLine("Unsupported executable file format"); return null; @@ -77,16 +148,17 @@ namespace Il2CppInspector public string GetTypeName(Il2CppType pType) { string ret; if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE) { - Il2CppTypeDefinition klass = Metadata.Types[pType.datapoint]; - ret = Metadata.Strings[klass.nameIndex]; + Il2CppTypeDefinition klass = TypeDefinitions[pType.datapoint]; + ret = Strings[klass.nameIndex]; } else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) { Il2CppGenericClass generic_class = Binary.Image.ReadMappedObject(pType.datapoint); - Il2CppTypeDefinition pMainDef = Metadata.Types[generic_class.typeDefinitionIndex]; - ret = Metadata.Strings[pMainDef.nameIndex]; + Il2CppTypeDefinition pMainDef = TypeDefinitions[generic_class.typeDefinitionIndex]; + ret = Strings[pMainDef.nameIndex]; var typeNames = new List(); - Il2CppGenericInst pInst = Binary.Image.ReadMappedObject(generic_class.context.class_inst); - var pointers = Binary.Image.ReadMappedArray(pInst.type_argv, (int)pInst.type_argc); + Il2CppGenericInst pInst = + Binary.Image.ReadMappedObject(generic_class.context.class_inst); + var pointers = Binary.Image.ReadMappedArray(pInst.type_argv, (int) pInst.type_argc); for (int i = 0; i < pInst.type_argc; ++i) { var pOriType = Binary.Image.ReadMappedObject(pointers[i]); typeNames.Add(GetTypeName(pOriType)); @@ -103,13 +175,14 @@ namespace Il2CppInspector ret = $"{GetTypeName(type)}[]"; } else { - if ((int)pType.type >= DefineConstants.CSharpTypeString.Count) + if ((int) pType.type >= DefineConstants.CSharpTypeString.Count) ret = "unknow"; else - ret = DefineConstants.CSharpTypeString[(int)pType.type]; + ret = DefineConstants.CSharpTypeString[(int) pType.type]; } 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); @@ -122,70 +195,13 @@ namespace Il2CppInspector // All older versions use values directly in the array if (!fieldOffsetsArePointers) { - var typeDef = Metadata.Types[typeIndex]; + 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; + Binary.Image.Stream.Position = Binary.Image.MapVATR((uint) ptr) + 4 * fieldIndexInType; return Binary.Image.Stream.ReadInt32(); } - - - public object GetDefaultValueForField(int fieldIndex) { - var def = Metadata.FieldDefaultValues.FirstOrDefault(x => x.fieldIndex == fieldIndex); - - if (def == null || def.dataIndex == -1) - return null; - - var pValue = Metadata.Header.fieldAndParameterDefaultValueDataOffset + def.dataIndex; - Il2CppType type = Binary.Types[def.typeIndex]; - if (pValue == 0) - return null; - - object value = null; - Metadata.Position = pValue; - switch (type.type) { - case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: - value = Metadata.ReadBoolean(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_U1: - case Il2CppTypeEnum.IL2CPP_TYPE_I1: - value = Metadata.ReadByte(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: - value = Metadata.ReadChar(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_U2: - value = Metadata.ReadUInt16(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_I2: - value = Metadata.ReadInt16(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_U4: - value = Metadata.ReadUInt32(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_I4: - value = Metadata.ReadInt32(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_U8: - value = Metadata.ReadUInt64(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_I8: - value = Metadata.ReadInt64(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_R4: - value = Metadata.ReadSingle(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_R8: - value = Metadata.ReadDouble(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_STRING: - var uiLen = Metadata.ReadInt32(); - value = Encoding.UTF8.GetString(Metadata.ReadBytes(uiLen)); - break; - } - return value; - } } } diff --git a/Il2CppInspector/Metadata.cs b/Il2CppInspector/Metadata.cs index 2cb61f2..63efe69 100644 --- a/Il2CppInspector/Metadata.cs +++ b/Il2CppInspector/Metadata.cs @@ -23,6 +23,7 @@ namespace Il2CppInspector public Il2CppParameterDefinition[] Params { get; } public Il2CppFieldDefinition[] Fields { get; } public Il2CppFieldDefaultValue[] FieldDefaultValues { get; } + public Dictionary Strings { get; } = new Dictionary(); public Metadata(Stream stream) : base(stream) diff --git a/Il2CppInspector/Reflection/Assembly.cs b/Il2CppInspector/Reflection/Assembly.cs index 83f0f00..999eb39 100644 --- a/Il2CppInspector/Reflection/Assembly.cs +++ b/Il2CppInspector/Reflection/Assembly.cs @@ -34,7 +34,7 @@ namespace Il2CppInspector.Reflection { Model = model; Definition = Model.Package.Metadata.Images[imageIndex]; Index = Definition.assemblyIndex; - FullName = Model.Package.Metadata.Strings[Definition.nameIndex]; + FullName = Model.Package.Strings[Definition.nameIndex]; if (Definition.entryPointIndex != -1) { // TODO: Generate EntryPoint method from entryPointIndex diff --git a/Il2CppInspector/Reflection/FieldInfo.cs b/Il2CppInspector/Reflection/FieldInfo.cs index 1c3afba..2acea05 100644 --- a/Il2CppInspector/Reflection/FieldInfo.cs +++ b/Il2CppInspector/Reflection/FieldInfo.cs @@ -53,9 +53,9 @@ namespace Il2CppInspector.Reflection { base(declaringType) { Definition = pkg.Metadata.Fields[fieldIndex]; Index = fieldIndex; - Name = pkg.Metadata.Strings[pkg.Metadata.Fields[fieldIndex].nameIndex]; + Name = pkg.Strings[pkg.Metadata.Fields[fieldIndex].nameIndex]; - fieldType = pkg.Binary.Types[Definition.typeIndex]; + fieldType = pkg.TypeUsages[Definition.typeIndex]; if ((fieldType.attrs & DefineConstants.FIELD_ATTRIBUTE_PRIVATE) == DefineConstants.FIELD_ATTRIBUTE_PRIVATE) Attributes |= FieldAttributes.Private; if ((fieldType.attrs & DefineConstants.FIELD_ATTRIBUTE_PUBLIC) == DefineConstants.FIELD_ATTRIBUTE_PUBLIC) diff --git a/Il2CppInspector/Reflection/TypeInfo.cs b/Il2CppInspector/Reflection/TypeInfo.cs index dc36b74..78dcf5a 100644 --- a/Il2CppInspector/Reflection/TypeInfo.cs +++ b/Il2CppInspector/Reflection/TypeInfo.cs @@ -116,10 +116,10 @@ namespace Il2CppInspector.Reflection { // Initialize from specified type index in metadata public TypeInfo(Il2CppInspector pkg, int typeIndex, Assembly owner) : base(owner) { - Definition = pkg.Metadata.Types[typeIndex]; + Definition = pkg.TypeDefinitions[typeIndex]; Index = typeIndex; - Namespace = pkg.Metadata.Strings[Definition.namespaceIndex]; - Name = pkg.Metadata.Strings[pkg.Metadata.Types[typeIndex].nameIndex]; + Namespace = pkg.Strings[Definition.namespaceIndex]; + Name = pkg.Strings[pkg.TypeDefinitions[typeIndex].nameIndex]; IsSerializable = (Definition.flags & DefineConstants.TYPE_ATTRIBUTE_SERIALIZABLE) != 0; IsPublic = (Definition.flags & DefineConstants.TYPE_ATTRIBUTE_VISIBILITY_MASK) == DefineConstants.TYPE_ATTRIBUTE_PUBLIC;