From 474faa009c36a7d87f6d294ed5afe106c67c56a7 Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Mon, 23 Oct 2017 14:03:41 +0200 Subject: [PATCH] Re-factor Metadata and file format code --- Il2CppDumper/Il2CppDumper.cs | 72 ++++--------------- .../{ => FileFormatReaders}/ElfReader.cs | 0 .../FormatLayouts/Elf.cs} | 0 .../FormatLayouts/MachO.cs} | 0 .../FormatLayouts/PE.cs} | 0 .../FormatLayouts/UB.cs} | 0 .../{ => FileFormatReaders}/MachOReader.cs | 0 .../{ => FileFormatReaders}/PEReader.cs | 0 .../{ => FileFormatReaders}/UBReader.cs | 0 Il2CppInspector/Il2CppProcessor.cs | 63 +++++++++++++++- Il2CppInspector/Metadata.cs | 55 +++++--------- .../{MetadataClass.cs => MetadataClasses.cs} | 0 12 files changed, 91 insertions(+), 99 deletions(-) rename Il2CppInspector/{ => FileFormatReaders}/ElfReader.cs (100%) rename Il2CppInspector/{ElfHeaders.cs => FileFormatReaders/FormatLayouts/Elf.cs} (100%) rename Il2CppInspector/{MachOHeaders.cs => FileFormatReaders/FormatLayouts/MachO.cs} (100%) rename Il2CppInspector/{PEHeaders.cs => FileFormatReaders/FormatLayouts/PE.cs} (100%) rename Il2CppInspector/{UBHeaders.cs => FileFormatReaders/FormatLayouts/UB.cs} (100%) rename Il2CppInspector/{ => FileFormatReaders}/MachOReader.cs (100%) rename Il2CppInspector/{ => FileFormatReaders}/PEReader.cs (100%) rename Il2CppInspector/{ => FileFormatReaders}/UBReader.cs (100%) rename Il2CppInspector/{MetadataClass.cs => MetadataClasses.cs} (100%) diff --git a/Il2CppDumper/Il2CppDumper.cs b/Il2CppDumper/Il2CppDumper.cs index 930e396..8e46e1e 100644 --- a/Il2CppDumper/Il2CppDumper.cs +++ b/Il2CppDumper/Il2CppDumper.cs @@ -20,11 +20,11 @@ namespace Il2CppInspector for (int imageIndex = 0; imageIndex < metadata.Images.Length; imageIndex++) { var imageDef = metadata.Images[imageIndex]; - writer.Write($"// Image {imageIndex}: {metadata.GetImageName(imageDef)} - {imageDef.typeStart}\n"); + writer.Write($"// Image {imageIndex}: {metadata.Strings[imageDef.nameIndex]} - {imageDef.typeStart}\n"); } for (int idx = 0; idx < metadata.Types.Length; ++idx) { var typeDef = metadata.Types[idx]; - writer.Write($"// Namespace: {metadata.GetTypeNamespace(typeDef)}\n"); + writer.Write($"// Namespace: {metadata.Strings[typeDef.namespaceIndex]}\n"); if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_SERIALIZABLE) != 0) writer.Write("[Serializable]\n"); if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_VISIBILITY_MASK) == @@ -38,13 +38,12 @@ namespace Il2CppInspector writer.Write("interface "); else writer.Write("class "); - writer.Write($"{metadata.GetTypeName(typeDef)} // TypeDefIndex: {idx}\n{{\n"); + writer.Write($"{metadata.Strings[typeDef.nameIndex]} // TypeDefIndex: {idx}\n{{\n"); writer.Write("\t// Fields\n"); var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (int i = typeDef.fieldStart; i < fieldEnd; ++i) { var pField = metadata.Fields[i]; var pType = il2cpp.GetTypeFromTypeIndex(pField.typeIndex); - var pDefault = metadata.GetFieldDefaultFromIndex(i); writer.Write("\t"); if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_PRIVATE) == DefineConstants.FIELD_ATTRIBUTE_PRIVATE) @@ -56,59 +55,12 @@ namespace Il2CppInspector writer.Write("static "); if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_INIT_ONLY) != 0) writer.Write("readonly "); - writer.Write($"{il2cpp.GetTypeName(pType)} {metadata.GetString(pField.nameIndex)}"); - if (pDefault != null && pDefault.dataIndex != -1) { - var pointer = metadata.GetDefaultValueFromIndex(pDefault.dataIndex); - Il2CppType pTypeToUse = il2cpp.GetTypeFromTypeIndex(pDefault.typeIndex); - if (pointer > 0) { - metadata.Position = pointer; - object multi = null; - switch (pTypeToUse.type) { - case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: - multi = metadata.ReadBoolean(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_U1: - case Il2CppTypeEnum.IL2CPP_TYPE_I1: - multi = metadata.ReadByte(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: - multi = metadata.ReadChar(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_U2: - multi = metadata.ReadUInt16(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_I2: - multi = metadata.ReadInt16(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_U4: - multi = metadata.ReadUInt32(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_I4: - multi = metadata.ReadInt32(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_U8: - multi = metadata.ReadUInt64(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_I8: - multi = metadata.ReadInt64(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_R4: - multi = metadata.ReadSingle(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_R8: - multi = metadata.ReadDouble(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_STRING: - var uiLen = metadata.ReadInt32(); - multi = Encoding.UTF8.GetString(metadata.ReadBytes(uiLen)); - break; - } - if (multi is string) - writer.Write($" = \"{multi}\""); - else if (multi != null) - writer.Write($" = {multi}"); - } - } + writer.Write($"{il2cpp.GetTypeName(pType)} {metadata.Strings[pField.nameIndex]}"); + object multi = il2cpp.GetDefaultValueForField(i); + if (multi is string) + writer.Write($" = \"{multi}\""); + else if (multi != null) + writer.Write($" = {multi}"); writer.Write("; // 0x{0:x}\n", il2cpp.GetFieldOffsetFromIndex(idx, i - typeDef.fieldStart)); } @@ -129,10 +81,10 @@ namespace Il2CppInspector if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_STATIC) != 0) writer.Write("static "); - writer.Write($"{il2cpp.GetTypeName(pReturnType)} {metadata.GetString(methodDef.nameIndex)}("); + writer.Write($"{il2cpp.GetTypeName(pReturnType)} {metadata.Strings[methodDef.nameIndex]}("); for (int j = 0; j < methodDef.parameterCount; ++j) { - Il2CppParameterDefinition pParam = metadata.parameterDefs[methodDef.parameterStart + j]; - string szParamName = metadata.GetString(pParam.nameIndex); + Il2CppParameterDefinition pParam = metadata.Params[methodDef.parameterStart + j]; + string szParamName = metadata.Strings[pParam.nameIndex]; Il2CppType pType = il2cpp.GetTypeFromTypeIndex(pParam.typeIndex); string szTypeName = il2cpp.GetTypeName(pType); if ((pType.attrs & DefineConstants.PARAM_ATTRIBUTE_OPTIONAL) != 0) diff --git a/Il2CppInspector/ElfReader.cs b/Il2CppInspector/FileFormatReaders/ElfReader.cs similarity index 100% rename from Il2CppInspector/ElfReader.cs rename to Il2CppInspector/FileFormatReaders/ElfReader.cs diff --git a/Il2CppInspector/ElfHeaders.cs b/Il2CppInspector/FileFormatReaders/FormatLayouts/Elf.cs similarity index 100% rename from Il2CppInspector/ElfHeaders.cs rename to Il2CppInspector/FileFormatReaders/FormatLayouts/Elf.cs diff --git a/Il2CppInspector/MachOHeaders.cs b/Il2CppInspector/FileFormatReaders/FormatLayouts/MachO.cs similarity index 100% rename from Il2CppInspector/MachOHeaders.cs rename to Il2CppInspector/FileFormatReaders/FormatLayouts/MachO.cs diff --git a/Il2CppInspector/PEHeaders.cs b/Il2CppInspector/FileFormatReaders/FormatLayouts/PE.cs similarity index 100% rename from Il2CppInspector/PEHeaders.cs rename to Il2CppInspector/FileFormatReaders/FormatLayouts/PE.cs diff --git a/Il2CppInspector/UBHeaders.cs b/Il2CppInspector/FileFormatReaders/FormatLayouts/UB.cs similarity index 100% rename from Il2CppInspector/UBHeaders.cs rename to Il2CppInspector/FileFormatReaders/FormatLayouts/UB.cs diff --git a/Il2CppInspector/MachOReader.cs b/Il2CppInspector/FileFormatReaders/MachOReader.cs similarity index 100% rename from Il2CppInspector/MachOReader.cs rename to Il2CppInspector/FileFormatReaders/MachOReader.cs diff --git a/Il2CppInspector/PEReader.cs b/Il2CppInspector/FileFormatReaders/PEReader.cs similarity index 100% rename from Il2CppInspector/PEReader.cs rename to Il2CppInspector/FileFormatReaders/PEReader.cs diff --git a/Il2CppInspector/UBReader.cs b/Il2CppInspector/FileFormatReaders/UBReader.cs similarity index 100% rename from Il2CppInspector/UBReader.cs rename to Il2CppInspector/FileFormatReaders/UBReader.cs diff --git a/Il2CppInspector/Il2CppProcessor.cs b/Il2CppInspector/Il2CppProcessor.cs index 6b68355..b250092 100644 --- a/Il2CppInspector/Il2CppProcessor.cs +++ b/Il2CppInspector/Il2CppProcessor.cs @@ -7,6 +7,8 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Text; namespace Il2CppInspector { @@ -75,12 +77,12 @@ namespace Il2CppInspector string ret; if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE) { Il2CppTypeDefinition klass = Metadata.Types[pType.data.klassIndex]; - ret = Metadata.GetString(klass.nameIndex); + ret = Metadata.Strings[klass.nameIndex]; } else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) { Il2CppGenericClass generic_class = Code.Image.ReadMappedObject(pType.data.generic_class); Il2CppTypeDefinition pMainDef = Metadata.Types[generic_class.typeDefinitionIndex]; - ret = Metadata.GetString(pMainDef.nameIndex); + ret = Metadata.Strings[pMainDef.nameIndex]; var typeNames = new List(); Il2CppGenericInst pInst = Code.Image.ReadMappedObject(generic_class.context.class_inst); var pointers = Code.Image.ReadMappedArray(pInst.type_argv, (int)pInst.type_argc); @@ -136,6 +138,63 @@ namespace Il2CppInspector return Code.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 = GetTypeFromTypeIndex(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; + } + private readonly string[] szTypeString = { "END", diff --git a/Il2CppInspector/Metadata.cs b/Il2CppInspector/Metadata.cs index 00591b2..2cb61f2 100644 --- a/Il2CppInspector/Metadata.cs +++ b/Il2CppInspector/Metadata.cs @@ -6,8 +6,8 @@ */ using System; +using System.Collections.Generic; using System.IO; -using System.Linq; using System.Reflection; using NoisyCowStudios.Bin2Object; @@ -15,18 +15,15 @@ namespace Il2CppInspector { public class Metadata : BinaryObjectReader { - private Il2CppGlobalMetadataHeader pMetadataHdr; + public Il2CppGlobalMetadataHeader Header; public Il2CppImageDefinition[] Images { get; } public Il2CppTypeDefinition[] Types { get; } public Il2CppMethodDefinition[] Methods { get; } - public Il2CppParameterDefinition[] parameterDefs; + public Il2CppParameterDefinition[] Params { get; } public Il2CppFieldDefinition[] Fields { get; } - public Il2CppFieldDefaultValue[] fieldDefaultValues; - - public string GetImageName(Il2CppImageDefinition image) => GetString(image.nameIndex); - public string GetTypeNamespace(Il2CppTypeDefinition type) => GetString(type.namespaceIndex); - public string GetTypeName(Il2CppTypeDefinition type) => GetString(type.nameIndex); + public Il2CppFieldDefaultValue[] FieldDefaultValues { get; } + public Dictionary Strings { get; } = new Dictionary(); public Metadata(Stream stream) : base(stream) { @@ -40,40 +37,24 @@ namespace Il2CppInspector // Rewind and read metadata header in full Position -= 8; - pMetadataHdr = ReadObject(); + Header = ReadObject(); if (Version != 21 && Version != 22 && Version != 23) { - throw new Exception($"ERROR: Metadata file supplied is not a supported version ({pMetadataHdr.version})."); + throw new Exception($"ERROR: Metadata file supplied is not a supported version ({Header.version})."); } - var uiImageCount = pMetadataHdr.imagesCount / Sizeof(typeof(Il2CppImageDefinition)); - var uiNumTypes = pMetadataHdr.typeDefinitionsCount / Sizeof(typeof(Il2CppTypeDefinition)); - Images = ReadArray(pMetadataHdr.imagesOffset, uiImageCount); - //GetTypeDefFromIndex - Types = ReadArray(pMetadataHdr.typeDefinitionsOffset, uiNumTypes); - //GetMethodDefinition - Methods = ReadArray(pMetadataHdr.methodsOffset, pMetadataHdr.methodsCount / Sizeof(typeof(Il2CppMethodDefinition))); - //GetParameterFromIndex - parameterDefs = ReadArray(pMetadataHdr.parametersOffset, pMetadataHdr.parametersCount / Sizeof(typeof(Il2CppParameterDefinition))); - //GetFieldDefFromIndex - Fields = ReadArray(pMetadataHdr.fieldsOffset, pMetadataHdr.fieldsCount / Sizeof(typeof(Il2CppFieldDefinition))); - //GetFieldDefaultFromIndex - fieldDefaultValues = ReadArray(pMetadataHdr.fieldDefaultValuesOffset, pMetadataHdr.fieldDefaultValuesCount / Sizeof(typeof(Il2CppFieldDefaultValue))); - } + // Load all the relevant metadata using offsets provided in the header + Images = ReadArray(Header.imagesOffset, Header.imagesCount / Sizeof(typeof(Il2CppImageDefinition))); + Types = ReadArray(Header.typeDefinitionsOffset, Header.typeDefinitionsCount / Sizeof(typeof(Il2CppTypeDefinition))); + Methods = ReadArray(Header.methodsOffset, Header.methodsCount / Sizeof(typeof(Il2CppMethodDefinition))); + Params = ReadArray(Header.parametersOffset, Header.parametersCount / Sizeof(typeof(Il2CppParameterDefinition))); + Fields = ReadArray(Header.fieldsOffset, Header.fieldsCount / Sizeof(typeof(Il2CppFieldDefinition))); + FieldDefaultValues = ReadArray(Header.fieldDefaultValuesOffset, Header.fieldDefaultValuesCount / Sizeof(typeof(Il2CppFieldDefaultValue))); + // TODO: Events, Properties, ParameterDefaultValue, GenericParameters, ParameterConstraints, GenericContainers, Interfaces, MetadataUsage, CustomAttributes - public Il2CppFieldDefaultValue GetFieldDefaultFromIndex(int idx) - { - return fieldDefaultValues.FirstOrDefault(x => x.fieldIndex == idx); - } - - public int GetDefaultValueFromIndex(int idx) - { - return pMetadataHdr.fieldAndParameterDefaultValueDataOffset + idx; - } - - public string GetString(int idx) - { - return ReadNullTerminatedString(pMetadataHdr.stringOffset + idx); + Position = Header.stringOffset; + while (Position < Header.stringOffset + Header.stringCount) + Strings.Add((int)Position - Header.stringOffset, ReadNullTerminatedString()); } private int Sizeof(Type type) diff --git a/Il2CppInspector/MetadataClass.cs b/Il2CppInspector/MetadataClasses.cs similarity index 100% rename from Il2CppInspector/MetadataClass.cs rename to Il2CppInspector/MetadataClasses.cs