private void AddParents(Il2CppTypeDefinition typeDef, StructInfo structInfo) { if (!typeDef.IsValueType && !typeDef.IsEnum) { if (typeDef.parentIndex >= 0) { var parent = il2Cpp.types[typeDef.parentIndex]; var parentDef = GetTypeDefinition(parent); if (parentDef != null) { AddParents(parentDef, structInfo); if (parentDef.field_count > 0) { var fieldEnd = parentDef.fieldStart + parentDef.field_count; for (var i = parentDef.fieldStart; i < fieldEnd; ++i) { var fieldDef = metadata.fieldDefs[i]; var fieldType = il2Cpp.types[fieldDef.typeIndex]; if ((fieldType.attrs & FIELD_ATTRIBUTE_LITERAL) == 0 && (fieldType.attrs & FIELD_ATTRIBUTE_STATIC) == 0) { structInfo.Parents.Add(GetIl2CppStructName(parent)); break; } } } } } } }
private string GetTypeDefName(Il2CppTypeDefinition typeDef, bool generic = true) { var prefix = string.Empty; if (typeDef.declaringTypeIndex != -1) { prefix = GetTypeName(il2Cpp.types[typeDef.declaringTypeIndex]) + "."; } var typeName = metadata.GetStringFromIndex(typeDef.nameIndex); if (typeDef.genericContainerIndex >= 0) { var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex]; typeName = typeName.Replace($"`{genericContainer.type_argc}", ""); if (generic) { var genericParameterNames = new List <string>(); for (int i = 0; i < genericContainer.type_argc; i++) { var genericParameterIndex = genericContainer.genericParameterStart + i; var param = metadata.genericParameters[genericParameterIndex]; genericParameterNames.Add(metadata.GetStringFromIndex(param.nameIndex)); } typeName += $"<{string.Join(", ", genericParameterNames)}>"; } } return(prefix + typeName); }
public string GetTypeDefName(Il2CppTypeDefinition typeDef, bool addNamespace, bool genericParameter) { var prefix = string.Empty; if (typeDef.declaringTypeIndex != -1) { prefix = GetTypeName(il2Cpp.types[typeDef.declaringTypeIndex], addNamespace, true) + "."; } else if (addNamespace) { var @namespace = metadata.GetStringFromIndex(typeDef.namespaceIndex); if (@namespace != "") { prefix = @namespace + "."; } } var typeName = metadata.GetStringFromIndex(typeDef.nameIndex); if (typeDef.genericContainerIndex >= 0) { var index = typeName.IndexOf("`"); if (index != -1) { typeName = typeName.Substring(0, index); } if (genericParameter) { var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex]; typeName += GetGenericContainerParams(genericContainer); } } return(prefix + typeName); }
private void AddVTableMethod(StructInfo structInfo, Il2CppTypeDefinition typeDef) { var dic = new SortedDictionary <int, Il2CppMethodDefinition>(); for (int i = 0; i < typeDef.vtable_count; i++) { var vTableIndex = typeDef.vtableStart + i; var encodedMethodIndex = metadata.vtableMethods[vTableIndex]; var usage = metadata.GetEncodedIndexType(encodedMethodIndex); var index = metadata.GetDecodedMethodIndex(encodedMethodIndex); Il2CppMethodDefinition methodDef; if (usage == 6) //kIl2CppMetadataUsageMethodRef { var methodSpec = il2Cpp.methodSpecs[index]; methodDef = metadata.methodDefs[methodSpec.methodDefinitionIndex]; } else { methodDef = metadata.methodDefs[index]; } dic[methodDef.slot] = methodDef; } foreach (var i in dic) { var methodInfo = new StructVTableMethodInfo(); structInfo.VTableMethod.Add(methodInfo); var methodDef = i.Value; methodInfo.MethodName = $"_{methodDef.slot}_{FixName(metadata.GetStringFromIndex(methodDef.nameIndex))}"; } }
public string GetTypeName(Il2CppTypeDefinition typeDef) { var ret = string.Empty; if (typeDef.declaringTypeIndex != -1) { ret += GetTypeName(il2Cpp.types[typeDef.declaringTypeIndex]) + "."; } ret += metadata.GetStringFromIndex(typeDef.nameIndex); var names = new List <string>(); if (typeDef.genericContainerIndex >= 0) { var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex]; for (int i = 0; i < genericContainer.type_argc; i++) { var genericParameterIndex = genericContainer.genericParameterStart + i; var param = metadata.genericParameters[genericParameterIndex]; names.Add(metadata.GetStringFromIndex(param.nameIndex)); } ret = ret.Replace($"`{genericContainer.type_argc}", ""); ret += $"<{string.Join(", ", names)}>"; } return(ret); }
private void AddFields(Il2CppTypeDefinition typeDef, StructInfo structInfo, Il2CppGenericContext context) { if (typeDef.field_count > 0) { var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { var fieldDef = metadata.fieldDefs[i]; var fieldType = il2Cpp.types[fieldDef.typeIndex]; if ((fieldType.attrs & FIELD_ATTRIBUTE_LITERAL) != 0) { continue; } var structFieldInfo = new StructFieldInfo(); structFieldInfo.FieldTypeName = ParseType(fieldType, context); var fieldName = FixName(metadata.GetStringFromIndex(fieldDef.nameIndex)); structFieldInfo.FieldName = fieldName; structFieldInfo.IsValueType = IsValueType(fieldType, context); if ((fieldType.attrs & FIELD_ATTRIBUTE_STATIC) != 0) { structInfo.StaticFields.Add(structFieldInfo); } else { structInfo.Fields.Add(structFieldInfo); } } } }
private void CreateStructNameDic(Il2CppTypeDefinition typeDef) { var typeName = executor.GetTypeDefName(typeDef, true, true); var typeStructName = FixName(typeName); var uniqueName = GetUniqueName(typeStructName); structNameDic.Add(typeDef, uniqueName); }
private void DumpMethod(StreamWriter writer, StreamWriter scriptwriter, Il2CppTypeDefinition typeDef, string typeName) { writer.Write("\t// Methods\n"); var methodEnd = typeDef.methodStart + typeDef.method_count; for (var i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.methodDefs[i]; writer.Write(GetCustomAttribute(methodDef.customAttributeIndex, "\t")); writer.Write("\t"); writer.Write(GetModifiers(methodDef)); var methodReturnType = il2cpp.types[methodDef.returnType]; var methodName = metadata.GetStringFromIndex(methodDef.nameIndex); writer.Write($"{GetTypeName(methodReturnType)} {methodName}("); var parameterStrs = new List <string>(); for (var j = 0; j < methodDef.parameterCount; ++j) { var parameterStr = ""; var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j]; var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex); var parameterType = il2cpp.types[parameterDef.typeIndex]; var parameterTypeName = GetTypeName(parameterType); if ((parameterType.attrs & PARAM_ATTRIBUTE_OPTIONAL) != 0) { parameterStr += "optional "; } if ((parameterType.attrs & PARAM_ATTRIBUTE_OUT) != 0) { parameterStr += "out "; } parameterStr += $"{parameterTypeName} {parameterName}"; parameterStrs.Add(parameterStr); } writer.Write(string.Join(", ", parameterStrs)); ulong methodPointer; if (methodDef.methodIndex >= 0) { methodPointer = il2cpp.methodPointers[methodDef.methodIndex]; } else { il2cpp.genericMethoddDictionary.TryGetValue(i, out methodPointer); } if (methodPointer > 0) { writer.Write("); // 0x{0:X}\n", methodPointer); if (scriptwriter != null) { var name = ToEscapedString(Regex.Replace(typeName, @"`\d", "") + "$$" + methodName); scriptwriter.WriteLine($"SetMethod(0x{methodPointer:X}, '{name}')"); } } else { writer.Write("); // -1\n"); } } }
private void AddFields(Il2CppTypeDefinition typeDef, List <StructFieldInfo> fields, List <StructFieldInfo> staticFields, Il2CppGenericContext context, bool isParent) { if (!typeDef.IsValueType && !typeDef.IsEnum) { if (typeDef.parentIndex >= 0) { var parent = il2Cpp.types[typeDef.parentIndex]; ParseParent(parent, out var parentDef, out var parentContext); if (parentDef != null) { AddFields(parentDef, fields, staticFields, parentContext, true); } } } if (typeDef.field_count > 0) { var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { var fieldDef = metadata.fieldDefs[i]; var fieldType = il2Cpp.types[fieldDef.typeIndex]; if ((fieldType.attrs & FIELD_ATTRIBUTE_LITERAL) != 0) { continue; } var structFieldInfo = new StructFieldInfo(); structFieldInfo.FieldTypeName = ParseType(fieldType, context); var fieldName = FixName(metadata.GetStringFromIndex(fieldDef.nameIndex)); structFieldInfo.FieldName = fieldName; structFieldInfo.IsValueType = IsValueType(fieldType, context); if ((fieldType.attrs & FIELD_ATTRIBUTE_STATIC) != 0) { if (!isParent) { staticFields.Add(structFieldInfo); } } else { if (isParent) { var access = fieldType.attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK; if (access == FIELD_ATTRIBUTE_PRIVATE) { structFieldInfo.FieldName = $"{FixName(metadata.GetStringFromIndex(typeDef.nameIndex))}_{fieldName}"; } } if (fields.Any(x => x.FieldName == structFieldInfo.FieldName)) { structFieldInfo.FieldName = $"{FixName(metadata.GetStringFromIndex(typeDef.nameIndex))}_{structFieldInfo.FieldName}"; } fields.Add(structFieldInfo); } } } }
private void AddStruct(Il2CppTypeDefinition typeDef) { var structInfo = new StructInfo(); structInfoList.Add(structInfo); structInfo.TypeName = structNameDic[typeDef]; structInfo.IsValueType = typeDef.IsValueType; AddFields(typeDef, structInfo.Fields, structInfo.StaticFields, null, false); AddVTableMethod(structInfo, typeDef); }
private static string GetTypeName(Il2CppTypeDefinition typeDef) { var ret = string.Empty; if (typeDef.declaringTypeIndex != -1) { ret += GetTypeName(il2cpp.types[typeDef.declaringTypeIndex]) + "."; } ret += metadata.GetStringFromIndex(typeDef.nameIndex); return(ret); }
private Il2CppTypeDefinitionInfo AddStruct(Il2CppTypeDefinition typeDef, TypeDefinitionMetadata metadata, Il2CppGenericClass genericClass = null) { var typeInfo = executor.GetTypeDefInfo(typeDef, genericClass); typeInfo.ImageName = metadata.ImageName; if (typeDefToAddress.ContainsKey(typeDef)) { typeInfo.Type.Address = typeDefToAddress[typeDef]; } TypeInfoList.Add(typeInfo); return(typeInfo); }
public string GetName(Il2CppTypeDefinition typeDef, string originalName) { Il2CppExecutor executor; if (!_executor.TryGetTarget(out executor)) { throw new InvalidOperationException("Cannot be used with disposed executor!"); } var il2CppType = executor.GetIl2CppTypeFromTypeDefinition(typeDef); return(GetName(executor, typeDef, il2CppType, originalName)); }
private void AddStruct(Il2CppTypeDefinition typeDef) { var structInfo = new StructInfo(); structInfoList.Add(structInfo); structInfo.TypeName = structNameDic[typeDef]; structInfo.IsValueType = typeDef.IsValueType; AddParents(typeDef, structInfo); AddFields(typeDef, structInfo, null); AddVTableMethod(structInfo, typeDef); AddRGCTX(structInfo, typeDef); }
private static string get_type_name(Il2CppType pType) { string ret; if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE) { Il2CppTypeDefinition klass = metadata.typeDefs[pType.data.klassIndex]; ret = metadata.GetString(klass.nameIndex); } else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) { Il2CppGenericClass generic_class = il2cpp.MapVATR <Il2CppGenericClass>(pType.data.generic_class); Il2CppTypeDefinition pMainDef = metadata.typeDefs[generic_class.typeDefinitionIndex]; ret = metadata.GetString(pMainDef.nameIndex); var typeNames = new List <string>(); Il2CppGenericInst pInst = il2cpp.MapVATR <Il2CppGenericInst>(generic_class.context.class_inst); var pointers = il2cpp.MapVATR <uint>(pInst.type_argv, (int)pInst.type_argc); for (int i = 0; i < pInst.type_argc; ++i) { var pOriType = il2cpp.MapVATR <Il2CppType>(pointers[i]); pOriType.Init(); typeNames.Add(get_type_name(pOriType)); } ret += $"<{string.Join(", ", typeNames)}>"; } else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_ARRAY) { Il2CppArrayType arrayType = il2cpp.MapVATR <Il2CppArrayType>(pType.data.array); var type = il2cpp.MapVATR <Il2CppType>(arrayType.etype); type.Init(); ret = $"{get_type_name(type)}[]"; } else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY) { var type = il2cpp.MapVATR <Il2CppType>(pType.data.type); type.Init(); ret = $"{get_type_name(type)}[]"; } else { if ((int)pType.type >= szTypeString.Length) { ret = "unknow"; } else { ret = szTypeString[(int)pType.type]; } } return(ret); }
public string GetTypeDefName(Il2CppTypeDefinition typeDef, bool addNamespace, bool genericParameter, bool generic_decl = false) { var prefix = string.Empty; if (typeDef.declaringTypeIndex != -1) { prefix = GetTypeName(il2Cpp.types[typeDef.declaringTypeIndex], addNamespace, true) + "_"; } else if (addNamespace) { var @namespace = metadata.GetStringFromIndex(typeDef.namespaceIndex); @namespace = @namespace.Replace(".", "::"); if (@namespace != "") { prefix = @namespace + "::"; } } var typeName = metadata.GetStringFromIndex(typeDef.nameIndex); if (typeDef.genericContainerIndex >= 0) { var index = typeName.IndexOf("`"); if (index != -1) { typeName = typeName.Substring(0, index); typeName = typeName.Replace("<", "_"); typeName = typeName.Replace(">", "_"); } if (genericParameter) { var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex]; typeName += GetGenericContainerParams(genericContainer, generic_decl); if (generic_decl) { return("template " + GetGenericContainerParams(genericContainer, generic_decl)); } } } else { typeName = typeName.Replace("<", "_"); typeName = typeName.Replace(">", "_"); } //typeName = Il2CppDecompiler.deobfu(typeName); return(Il2CppDecompiler.deobfu(prefix + typeName)); }
private void IndexTypeMetadata() { // build type -> image reverse lookup for (int imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++) { Il2CppImageDefinition imageDef = metadata.imageDefs[imageIndex]; string imageName = metadata.GetStringFromIndex(imageDef.nameIndex); long typeEnd = imageDef.typeStart + imageDef.typeCount; foreach (int typeIndex in imageDef.TypeRange) { Il2CppTypeDefinition typeDef = metadata.typeDefs[typeIndex]; string typeName = executor.GetTypeDefName(typeDef, true, true); TypeMetadata.Add(typeDef, new TypeDefinitionMetadata(imageIndex, typeIndex, imageName, null, typeName)); } } }
public Il2CppRGCTXDefinition[] GetRGCTXDefinition(string imageName, Il2CppTypeDefinition typeDef) { Il2CppRGCTXDefinition[] collection = null; if (il2Cpp.Version >= 24.2) { il2Cpp.rgctxsDictionary[imageName].TryGetValue(typeDef.token, out collection); } else { if (typeDef.rgctxCount > 0) { collection = new Il2CppRGCTXDefinition[typeDef.rgctxCount]; Array.Copy(metadata.rgctxEntries, typeDef.rgctxStartIndex, collection, 0, typeDef.rgctxCount); } } return(collection); }
private string GetName(Il2CppExecutor executor, Il2CppTypeDefinition typeDef, Il2CppType il2CppType, string originalName) { if (_typeDefToName.ContainsKey(il2CppType)) { return(_typeDefToName[il2CppType].Split('|')[1]); } var uniqueTypeNamePair = $"{typeDef.namespaceIndex}|{originalName}"; int n = 0; while (_uniqueNames.Contains(uniqueTypeNamePair)) { uniqueTypeNamePair = $"{typeDef.namespaceIndex}|_{++n}_{originalName}"; } _uniqueNames.Add(uniqueTypeNamePair); _typeDefToName[il2CppType] = uniqueTypeNamePair; return(uniqueTypeNamePair.Split('|')[1]); }
public string GetTypeDefName(Il2CppTypeDefinition typeDef, bool addNamespace, bool genericParameter) { var prefix = string.Empty; if (typeDef.declaringTypeIndex != -1) { prefix = GetTypeName(il2Cpp.types[typeDef.declaringTypeIndex], addNamespace, true) + "."; } else if (addNamespace) { var @namespace = metadata.GetStringFromIndex(typeDef.namespaceIndex); if (@namespace != "") { prefix = @namespace + "."; } } var typeName = metadata.GetStringFromIndex(typeDef.nameIndex); if (typeDef.genericContainerIndex >= 0) { var index = typeName.IndexOf("`"); if (index != -1) { typeName = typeName.Substring(0, index); } if (genericParameter) { var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex]; var genericParameterNames = new List <string>(); for (int i = 0; i < genericContainer.type_argc; i++) { var genericParameterIndex = genericContainer.genericParameterStart + i; var param = metadata.genericParameters[genericParameterIndex]; genericParameterNames.Add(metadata.GetStringFromIndex(param.nameIndex)); } typeName += $"<{string.Join(", ", genericParameterNames)}>"; } } return(prefix + typeName); }
private void AddRGCTX(StructInfo structInfo, Il2CppTypeDefinition typeDef) { var imageIndex = typeDefImageIndices[typeDef]; var collection = executor.GetTypeRGCTXDefinition(typeDef, imageIndex); if (collection != null) { foreach (var definitionData in collection) { var structRGCTXInfo = new StructRGCTXInfo(); structInfo.RGCTXs.Add(structRGCTXInfo); structRGCTXInfo.Type = definitionData.type; switch (definitionData.type) { case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_TYPE: { var il2CppType = il2Cpp.types[definitionData.data.typeIndex]; structRGCTXInfo.TypeName = FixName(executor.GetTypeName(il2CppType, true, false)); break; } case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_CLASS: { var il2CppType = il2Cpp.types[definitionData.data.typeIndex]; structRGCTXInfo.ClassName = FixName(executor.GetTypeName(il2CppType, true, false)); break; } case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_METHOD: { var methodSpec = il2Cpp.methodSpecs[definitionData.data.methodIndex]; (var methodSpecTypeName, var methodSpecMethodName) = executor.GetMethodSpecName(methodSpec, true); structRGCTXInfo.MethodName = FixName(methodSpecTypeName + "." + methodSpecMethodName); break; } } } } }
private void DumpProperty(StreamWriter writer, Il2CppTypeDefinition typeDef) { writer.Write("\t// Properties\n"); var propertyEnd = typeDef.propertyStart + typeDef.property_count; for (var i = typeDef.propertyStart; i < propertyEnd; ++i) { var propertyDef = metadata.propertyDefs[i]; writer.Write(GetCustomAttribute(propertyDef.customAttributeIndex, "\t")); writer.Write("\t"); if (propertyDef.get >= 0) { var methodDef = metadata.methodDefs[typeDef.methodStart + propertyDef.get]; writer.Write(GetModifiers(methodDef)); var propertyType = il2cpp.types[methodDef.returnType]; writer.Write($"{GetTypeName(propertyType)} {metadata.GetStringFromIndex(propertyDef.nameIndex)} {{ "); } else if (propertyDef.set > 0) { var methodDef = metadata.methodDefs[typeDef.methodStart + propertyDef.set]; writer.Write(GetModifiers(methodDef)); var parameterDef = metadata.parameterDefs[methodDef.parameterStart]; var propertyType = il2cpp.types[parameterDef.typeIndex]; writer.Write($"{GetTypeName(propertyType)} {metadata.GetStringFromIndex(propertyDef.nameIndex)} {{ "); } if (propertyDef.get >= 0) { writer.Write("get; "); } if (propertyDef.set >= 0) { writer.Write("set; "); } writer.Write("}"); writer.Write("\n"); } writer.Write("\n"); }
private void ParseParent(Il2CppType il2CppType, out Il2CppTypeDefinition typeDef, out Il2CppGenericContext context) { context = null; switch (il2CppType.type) { case Il2CppTypeEnum.IL2CPP_TYPE_CLASS: case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE: typeDef = metadata.typeDefs[il2CppType.data.klassIndex]; break; case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST: var genericClass = il2Cpp.MapVATR <Il2CppGenericClass>(il2CppType.data.generic_class); context = genericClass.context; typeDef = metadata.typeDefs[genericClass.typeDefinitionIndex]; break; case Il2CppTypeEnum.IL2CPP_TYPE_OBJECT: typeDef = null; break; default: throw new NotSupportedException(); } }
private (Il2CppTypeDefinition, int) ReadCustomAttributeNamedArgumentClassAndIndex(Il2CppTypeDefinition typeDef) { var memberIndex = this.ReadCompressedInt32(); if (memberIndex >= 0) { return(typeDef, memberIndex); } memberIndex = -(memberIndex + 1); var typeIndex = this.ReadCompressedUInt32(); var declaringClass = metadata.typeDefs[typeIndex]; return(declaringClass, memberIndex); }
private void DumpField(StreamWriter writer, Il2CppTypeDefinition typeDef, int idx) { writer.Write("\t// Fields\n"); var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { var fieldDef = metadata.fieldDefs[i]; var fieldType = il2cpp.types[fieldDef.typeIndex]; var fieldDefault = metadata.GetFieldDefaultValueFromIndex(i); writer.Write(GetCustomAttribute(fieldDef.customAttributeIndex, "\t")); writer.Write("\t"); var access = fieldType.attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK; switch (access) { case FIELD_ATTRIBUTE_PRIVATE: writer.Write("private "); break; case FIELD_ATTRIBUTE_PUBLIC: writer.Write("public "); break; case FIELD_ATTRIBUTE_FAMILY: writer.Write("protected "); break; case FIELD_ATTRIBUTE_ASSEMBLY: case FIELD_ATTRIBUTE_FAM_AND_ASSEM: writer.Write("internal "); break; case FIELD_ATTRIBUTE_FAM_OR_ASSEM: writer.Write("protected internal "); break; } if ((fieldType.attrs & FIELD_ATTRIBUTE_LITERAL) != 0) { writer.Write("const "); } else { if ((fieldType.attrs & FIELD_ATTRIBUTE_STATIC) != 0) { writer.Write("static "); } if ((fieldType.attrs & FIELD_ATTRIBUTE_INIT_ONLY) != 0) { writer.Write("readonly "); } } writer.Write($"{GetTypeName(fieldType)} {metadata.GetStringFromIndex(fieldDef.nameIndex)}"); if (fieldDefault != null && fieldDefault.dataIndex != -1) { var pointer = metadata.GetDefaultValueFromIndex(fieldDefault.dataIndex); if (pointer > 0) { var pTypeToUse = il2cpp.types[fieldDefault.typeIndex]; metadata.Position = pointer; object multi = null; switch (pTypeToUse.type) { case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: multi = metadata.ReadBoolean(); break; case Il2CppTypeEnum.IL2CPP_TYPE_U1: multi = metadata.ReadByte(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I1: multi = metadata.ReadSByte(); break; case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: multi = BitConverter.ToChar(metadata.ReadBytes(2), 0); 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 str) { writer.Write($" = \"{ToEscapedString(str)}\""); } else if (multi is char c) { var v = (int)c; writer.Write($" = '\\x{v:x}'"); } else if (multi != null) { writer.Write($" = {multi}"); } } } if (config.DumpFieldOffset) { writer.Write("; // 0x{0:X}\n", il2cpp.GetFieldOffsetFromIndex(idx, i - typeDef.fieldStart, i)); } else { writer.Write(";\n"); } } writer.Write("\n"); }