public LoadVirtualFunctionPointerAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { regReadFrom = Utils.GetRegisterNameNew(instruction.MemoryBase); var inReg = context.GetOperandInRegister(regReadFrom); if (!(inReg is ConstantDefinition cons) || !(cons.Value is Il2CppClassIdentifier klass)) { return; } classReadFrom = klass.backingType; var readOffset = instruction.MemoryDisplacement; methodPointerRead = Utils.GetMethodFromReadKlassOffset((int)readOffset); if (methodPointerRead == null) { return; } var regPutInto = Utils.GetRegisterNameNew(instruction.Op0Register); if (regPutInto == "rsp") { //todo how do we handle this kind of instruction - does it even exist? // var stackOffset = Utils.GetOperandMemoryOffset(instruction.Operands[0]); // context.PushToStack(context.MakeConstant(typeof(MethodDefinition), methodPointerRead), stackOffset); } else { destinationConstant = context.MakeConstant(typeof(MethodDefinition), methodPointerRead, reg: regPutInto); } }
private int GetFieldOffset(Il2Cpp il2Cpp, Metadata metadata, Il2CppExecutor executor, string classname, string membername) { int typeDefIndex = 0; Il2CppTypeDefinition typeDef = FindClassEntry(metadata, executor, classname, out typeDefIndex); if (typeDef == null) { return(0); } var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { var isStatic = false; var fieldDef = metadata.fieldDefs[i]; var fieldType = il2Cpp.types[fieldDef.typeIndex]; if ((fieldType.attrs & FIELD_ATTRIBUTE_STATIC) != 0) { isStatic = true; } string memberName = metadata.GetStringFromIndex(fieldDef.nameIndex); if (memberName == membername) { return(il2Cpp.GetFieldOffsetFromIndex(typeDefIndex, i - typeDef.fieldStart, i, typeDef.IsValueType, isStatic)); } } throw new Exception("Field " + membername + " not found in " + classname); }
internal static Il2CppTypeReflectionData WrapType(Il2CppTypeDefinition what) { return(new Il2CppTypeReflectionData { baseType = what, genericParams = new Il2CppTypeReflectionData[0], isGenericType = false, isType = true, }); }
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); }
internal void WriteEnum(StreamWriter writer, Il2CppTypeDefinition typeDef, string pad = "") { writer.Write("\n"); writer.Write(pad + $"enum {metadata.GetTypeName(typeDef)} {{\n"); var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (int i = typeDef.fieldStart + 1; i < fieldEnd; ++i) { var pField = metadata.Fields[i]; var defaultValue = this.GetDefaultValue(i); writer.Write(pad + $"\t{metadata.GetString(pField.nameIndex)} = {defaultValue};\n"); } writer.Write(pad + "}\n"); }
internal void WriteFields(StreamWriter writer, Il2CppTypeDefinition typeDef) { if (typeDef.field_count <= 0) { return; } writer.Write("\t\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.Code.GetTypeFromTypeIndex(pField.typeIndex); var defaultValue = this.GetDefaultValue(i); WriteAttribute(writer, pField.customAttributeIndex, "\t\t"); if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_PINVOKE_IMPL) != 0) { writer.Write("// pinvoke\n"); } writer.Write("\t\t"); if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_PRIVATE) == DefineConstants.FIELD_ATTRIBUTE_PRIVATE) { writer.Write("private "); } if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_PUBLIC) == DefineConstants.FIELD_ATTRIBUTE_PUBLIC) { writer.Write("public "); } if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_STATIC) != 0) { writer.Write("static "); } if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_INIT_ONLY) != 0) { writer.Write("readonly "); } writer.Write($"{il2cpp.GetFullTypeName(pType)} {metadata.GetString(pField.nameIndex)}"); if (defaultValue != null) { writer.Write($" = {defaultValue}"); } writer.Write(";\n"); } }
internal void WriteFields(StreamWriter writer, Il2CppTypeDefinition typeDef) { if (typeDef.field_count <= 0) { return; } var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (int i = typeDef.fieldStart; i < fieldEnd; ++i) { var pField = metadata.Fields[i]; var pType = il2cpp.Code.GetTypeFromTypeIndex(pField.typeIndex); if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_STATIC) == 0) { var fieldname = metadata.GetString(pField.nameIndex); string typename = ""; if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE) { var fieldTypeDef = metadata.Types[pType.klassIndex]; if (fieldTypeDef.parentIndex == enumIdx) { typename = "int"; } else if ((fieldTypeDef.flags & DefineConstants.TYPE_ATTRIBUTE_INTERFACE) != 0) { typename = "void *"; } else { typename = this.GetStructType(il2cpp.GetTypeName(pType)); } } else { typename = this.GetStructType(il2cpp.GetTypeName(pType)); } writer.Write($"\t{typename} {fieldname};\n"); if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) { this.AddTypeToDump(pType); } } } }
public static int GetTypeIndexFromType(Il2CppTypeDefinition typeDefinition) { if (LibCpp2IlMain.TheMetadata == null) { return(-1); } for (var i = 0; i < LibCpp2IlMain.TheMetadata.typeDefs.Length; i++) { if (LibCpp2IlMain.TheMetadata.typeDefs[i] == typeDefinition) { return(i); } } return(-1); }
internal void WriteEnum(StreamWriter writer, Il2CppTypeDefinition typeDef) { writer.Write("\t"); if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_VISIBILITY_MASK) == DefineConstants.TYPE_ATTRIBUTE_PUBLIC) { writer.Write("public "); } writer.Write("enum {\n"); var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (int i = typeDef.fieldStart + 1; i < fieldEnd; ++i) { var pField = metadata.Fields[i]; var defaultValue = this.GetDefaultValue(i); writer.Write($"\t\t{metadata.GetString(pField.nameIndex)} = {defaultValue}\n"); } writer.Write("\t}\n\n"); }
internal void WriteType(StreamWriter writer, Il2CppTypeDefinition typeDef) { if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_INTERFACE) != 0) { return; } var nameSpace = metadata.GetTypeNamespace(typeDef); if (nameSpace.Length > 0) { nameSpace += "."; } var typeName = metadata.GetTypeName(typeDef); writer.Write($"struct {typeName}"); if (typeDef.parentIndex >= 0) { var pType = il2cpp.Code.GetTypeFromTypeIndex(typeDef.parentIndex); var name = il2cpp.GetTypeName(pType); if (name == "object") { writer.Write($" : public Il2CppObject"); } else if (name != "ValueType") { writer.Write($" : public {name}"); } } writer.Write("\n{\n"); this.WriteFields(writer, typeDef); writer.Write("}\n\n"); }
internal void WriteType(StreamWriter writer, Il2CppTypeDefinition typeDef) { if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_SERIALIZABLE) != 0) { writer.Write("\t[Serializable]\n"); } writer.Write("\t"); if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_VISIBILITY_MASK) == DefineConstants.TYPE_ATTRIBUTE_PUBLIC) { writer.Write("public "); } if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_ABSTRACT) != 0) { writer.Write("abstract "); } if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_SEALED) != 0) { writer.Write("sealed "); } if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_INTERFACE) != 0) { writer.Write("interface "); } else { writer.Write("class "); } var nameSpace = metadata.GetTypeNamespace(typeDef); if (nameSpace.Length > 0) { nameSpace += "."; } writer.Write($"{nameSpace}{metadata.GetTypeName(typeDef)}"); var yes = typeDef.vtable_count == typeDef.method_count; yes.ToString(); // class implements an interface //if (typeDef.interfaces_count > 0) //{ // var maxInterface = typeDef.interfacesStart + typeDef.interfaces_count; // for (var i = typeDef.interfacesStart; i < maxInterface; i++) // { // var pInterface = metadata.Interfaces[i]; // //var pType = il2cpp.Code.GetTypeFromTypeIndex(pInterface.); // //var name = il2cpp.GetTypeName(pType); // var name = metadata.GetString(pInterface.nameIndex); // writer.Write($" implements {name}"); // } //} // class extenss another type if (typeDef.parentIndex >= 0) { var pType = il2cpp.Code.GetTypeFromTypeIndex(typeDef.parentIndex); var name = il2cpp.GetTypeName(pType); if (name != "object") { writer.Write($" extends {name}"); } } writer.Write("\n\t{\n"); this.WriteFields(writer, typeDef); this.WriteMethods(writer, typeDef); writer.Write("\t}\n\n"); }
internal void WriteMethods(StreamWriter writer, Il2CppTypeDefinition typeDef) { if (typeDef.method_count <= 0) { return; } writer.Write("\t\t// Methods\n"); var methodEnd = typeDef.methodStart + typeDef.method_count; for (int i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.Methods[i]; if (methodDef.methodIndex >= 0) { var ptr = il2cpp.Code.MethodPointers[methodDef.methodIndex]; writer.Write("\t\t// Offset: 0x{0:x}\n", ptr); } else { writer.Write("\t\t// Offset: ?\n"); } writer.Write("\t\t"); var pReturnType = il2cpp.Code.GetTypeFromTypeIndex(methodDef.returnType); if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == DefineConstants.METHOD_ATTRIBUTE_PRIVATE) { writer.Write("private "); } if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == DefineConstants.METHOD_ATTRIBUTE_PUBLIC) { writer.Write("public "); } if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_VIRTUAL) != 0) { writer.Write("virtual "); } if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_STATIC) != 0) { writer.Write("static "); } var methodName = metadata.GetString(methodDef.nameIndex); writer.Write($"{il2cpp.GetTypeName(pReturnType)} {methodName}("); for (int j = 0; j < methodDef.parameterCount; ++j) { Il2CppParameterDefinition pParam = metadata.parameterDefs[methodDef.parameterStart + j]; string szParamName = metadata.GetString(pParam.nameIndex); var pType = il2cpp.Code.GetTypeFromTypeIndex(pParam.typeIndex); string szTypeName = il2cpp.GetTypeName(pType); if ((pType.attrs & DefineConstants.PARAM_ATTRIBUTE_OPTIONAL) != 0) { writer.Write("optional "); } if ((pType.attrs & DefineConstants.PARAM_ATTRIBUTE_OUT) != 0) { writer.Write("out "); } if (j != methodDef.parameterCount - 1) { writer.Write($"{szTypeName} {szParamName}, "); } else { writer.Write($"{szTypeName} {szParamName}"); } } writer.Write(");\n"); } }
private void WriteType(StreamWriter writer, Il2CppTypeDefinition typeDef) { }
internal static string GetTypeName(Il2CppMetadata metadata, PE.PE cppAssembly, Il2CppTypeDefinition typeDef) { var ret = String.Empty; if (typeDef.declaringTypeIndex != -1) { ret += GetTypeName(metadata, cppAssembly, cppAssembly.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 static List <CppMethodData> ProcessTypeContents(Il2CppMetadata metadata, PE.PE cppAssembly, Il2CppTypeDefinition cppTypeDefinition, TypeDefinition ilTypeDefinition) { var typeMetaText = new StringBuilder(); typeMetaText.Append($"Type: {ilTypeDefinition.FullName}:") .Append($"\n\tBase Class: \n\t\t{ilTypeDefinition.BaseType}\n") .Append("\n\tInterfaces:\n"); foreach (var iface in ilTypeDefinition.Interfaces) { typeMetaText.Append($"\t\t{iface.InterfaceType.FullName}\n"); } //field var fields = new List <FieldInType>(); var baseFields = new List <FieldDefinition>(); var current = ilTypeDefinition; while (current.BaseType != null) { var targetName = current.BaseType.FullName; if (targetName.Contains("<")) // types with generic parameters (Type'1<T>) are stored as Type'1, so I just removed the part that causes trouble and called it a day { targetName = targetName.Substring(0, targetName.IndexOf("<")); } current = SharedState.AllTypeDefinitions.Find(t => t.FullName == targetName); if (current == null) { typeMetaText.Append("WARN: Type " + targetName + " is not defined yet\n"); break; } baseFields.InsertRange(0, current.Fields.Where(f => !f.IsStatic)); // each loop we go one inheritage level deeper, so these "new" fields should be inserted before the previous ones } //Handle base fields var fieldOffset = baseFields.Aggregate((ulong)(ilTypeDefinition.MetadataType == MetadataType.Class ? 0x10 : 0x0), (currentOffset, baseField) => HandleField(baseField.FieldType, currentOffset, baseField.Name, baseField, ref fields, typeMetaText)); var lastFieldIdx = cppTypeDefinition.firstFieldIdx + cppTypeDefinition.field_count; for (var fieldIdx = cppTypeDefinition.firstFieldIdx; fieldIdx < lastFieldIdx; ++fieldIdx) { var fieldDef = metadata.fieldDefs[fieldIdx]; var fieldType = cppAssembly.types[fieldDef.typeIndex]; var fieldName = metadata.GetStringFromIndex(fieldDef.nameIndex); var fieldTypeRef = Utils.ImportTypeInto(ilTypeDefinition, fieldType, cppAssembly, metadata); var fieldDefinition = new FieldDefinition(fieldName, (FieldAttributes)fieldType.attrs, fieldTypeRef); ilTypeDefinition.Fields.Add(fieldDefinition); //Field default values if (fieldDefinition.HasDefault) { var fieldDefault = metadata.GetFieldDefaultValueFromIndex(fieldIdx); if (fieldDefault != null && fieldDefault.dataIndex != -1) { fieldDefinition.Constant = Utils.GetDefaultValue(fieldDefault.dataIndex, fieldDefault.typeIndex, metadata, cppAssembly); } } if (!fieldDefinition.IsStatic) { fieldOffset = HandleField(fieldTypeRef, fieldOffset, fieldName, fieldDefinition, ref fields, typeMetaText); } } fields.Sort(); //By offset SharedState.FieldsByType[ilTypeDefinition] = fields; //Methods var lastMethodId = cppTypeDefinition.firstMethodId + cppTypeDefinition.method_count; var typeMethods = new List <CppMethodData>(); Il2CppGenericContainer genericContainer; for (var methodId = cppTypeDefinition.firstMethodId; methodId < lastMethodId; ++methodId) { var methodDef = metadata.methodDefs[methodId]; var methodReturnType = cppAssembly.types[methodDef.returnType]; var methodName = metadata.GetStringFromIndex(methodDef.nameIndex); var methodDefinition = new MethodDefinition(methodName, (MethodAttributes)methodDef.flags, ilTypeDefinition.Module.ImportReference(typeof(void))); //TODO: For Unity 2019 we'll need to fix the imageindex param from 0 to the actual index var offsetInRam = cppAssembly.GetMethodPointer(methodDef.methodIndex, methodId, 0, methodDef.token); long offsetInFile = offsetInRam == 0 ? 0 : cppAssembly.MapVirtualAddressToRaw(offsetInRam); typeMetaText.Append($"\n\tMethod: {methodName}:\n") .Append($"\t\tFile Offset 0x{offsetInFile:X8}\n") .Append($"\t\tRam Offset 0x{offsetInRam:x8}\n") .Append($"\t\tVirtual Method Slot: {methodDef.slot}\n"); var bytes = new List <byte>(); var offset = offsetInFile; while (true) { var b = cppAssembly.raw[offset]; if (b == 0xC3 && cppAssembly.raw[offset + 1] == 0xCC) { break; } if (b == 0xCC && bytes.Count > 0 && (bytes.Last() == 0xcc || bytes.Last() == 0xc3)) { break; } bytes.Add(b); offset++; } typeMetaText.Append($"\t\tMethod Length: {bytes.Count} bytes\n"); typeMethods.Add(new CppMethodData { MethodName = methodName, MethodId = methodId, MethodBytes = bytes.ToArray(), MethodOffsetRam = offsetInRam }); ilTypeDefinition.Methods.Add(methodDefinition); methodDefinition.ReturnType = Utils.ImportTypeInto(methodDefinition, methodReturnType, cppAssembly, metadata); if (methodDefinition.HasBody && ilTypeDefinition.BaseType?.FullName != "System.MulticastDelegate") { var ilprocessor = methodDefinition.Body.GetILProcessor(); ilprocessor.Append(ilprocessor.Create(OpCodes.Nop)); } SharedState.MethodsByIndex.Add(methodId, methodDefinition); //Method Params for (var paramIdx = 0; paramIdx < methodDef.parameterCount; ++paramIdx) { var parameterDef = metadata.parameterDefs[methodDef.parameterStart + paramIdx]; var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex); var parameterType = cppAssembly.types[parameterDef.typeIndex]; var parameterTypeRef = Utils.ImportTypeInto(methodDefinition, parameterType, cppAssembly, metadata); var parameterDefinition = new ParameterDefinition(parameterName, (ParameterAttributes)parameterType.attrs, parameterTypeRef); methodDefinition.Parameters.Add(parameterDefinition); //Default values for params if (parameterDefinition.HasDefault) { var parameterDefault = metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + paramIdx); if (parameterDefault != null && parameterDefault.dataIndex != -1) { parameterDefinition.Constant = Utils.GetDefaultValue(parameterDefault.dataIndex, parameterDefault.typeIndex, metadata, cppAssembly); } } typeMetaText.Append($"\n\t\tParameter {paramIdx}:\n") .Append($"\t\t\tName: {parameterName}\n") .Append($"\t\t\tType: {(parameterTypeRef.Namespace == "" ? "<None>" : parameterTypeRef.Namespace)}.{parameterTypeRef.Name}\n") .Append($"\t\t\tDefault Value: {parameterDefinition.Constant}"); } if (methodDef.genericContainerIndex >= 0) { genericContainer = metadata.genericContainers[methodDef.genericContainerIndex]; if (genericContainer.type_argc > methodDefinition.GenericParameters.Count) { for (var j = 0; j < genericContainer.type_argc; j++) { var genericParameterIndex = genericContainer.genericParameterStart + j; var param = metadata.genericParameters[genericParameterIndex]; var genericName = metadata.GetStringFromIndex(param.nameIndex); if (!SharedState.GenericParamsByIndex.TryGetValue(genericParameterIndex, out var genericParameter)) { genericParameter = new GenericParameter(genericName, methodDefinition); methodDefinition.GenericParameters.Add(genericParameter); SharedState.GenericParamsByIndex.Add(genericParameterIndex, genericParameter); } else { if (!methodDefinition.GenericParameters.Contains(genericParameter)) { methodDefinition.GenericParameters.Add(genericParameter); } } } } } if (methodDef.slot < ushort.MaxValue) { SharedState.VirtualMethodsBySlot[methodDef.slot] = methodDefinition; } SharedState.MethodsByAddress[offsetInRam] = methodDefinition; } //Properties var lastPropertyId = cppTypeDefinition.firstPropertyId + cppTypeDefinition.propertyCount; for (var propertyId = cppTypeDefinition.firstPropertyId; propertyId < lastPropertyId; ++propertyId) { var propertyDef = metadata.propertyDefs[propertyId]; var propertyName = metadata.GetStringFromIndex(propertyDef.nameIndex); TypeReference propertyType = null; MethodDefinition getter = null; MethodDefinition setter = null; if (propertyDef.get >= 0) { getter = SharedState.MethodsByIndex[cppTypeDefinition.firstMethodId + propertyDef.get]; propertyType = getter.ReturnType; } if (propertyDef.set >= 0) { setter = SharedState.MethodsByIndex[cppTypeDefinition.firstMethodId + propertyDef.set]; if (propertyType == null) { propertyType = setter.Parameters[0].ParameterType; } } var propertyDefinition = new PropertyDefinition(propertyName, (PropertyAttributes)propertyDef.attrs, propertyType) { GetMethod = getter, SetMethod = setter }; ilTypeDefinition.Properties.Add(propertyDefinition); } //Events var lastEventId = cppTypeDefinition.firstEventId + cppTypeDefinition.eventCount; for (var eventId = cppTypeDefinition.firstEventId; eventId < lastEventId; ++eventId) { var eventDef = metadata.eventDefs[eventId]; var eventName = metadata.GetStringFromIndex(eventDef.nameIndex); var eventType = cppAssembly.types[eventDef.typeIndex]; var eventTypeRef = Utils.ImportTypeInto(ilTypeDefinition, eventType, cppAssembly, metadata); var eventDefinition = new EventDefinition(eventName, (EventAttributes)eventType.attrs, eventTypeRef); if (eventDef.add >= 0) { eventDefinition.AddMethod = SharedState.MethodsByIndex[cppTypeDefinition.firstMethodId + eventDef.add]; } if (eventDef.remove >= 0) { eventDefinition.RemoveMethod = SharedState.MethodsByIndex[cppTypeDefinition.firstMethodId + eventDef.remove]; } if (eventDef.raise >= 0) { eventDefinition.InvokeMethod = SharedState.MethodsByIndex[cppTypeDefinition.firstMethodId + eventDef.raise]; } ilTypeDefinition.Events.Add(eventDefinition); } File.WriteAllText(Path.Combine(Path.GetFullPath("cpp2il_out"), "types", ilTypeDefinition.Module.Assembly.Name.Name, ilTypeDefinition.Name.Replace("<", "_").Replace(">", "_") + "_metadata.txt"), typeMetaText.ToString()); if (cppTypeDefinition.genericContainerIndex < 0) { return(typeMethods); //Finished processing if not generic } genericContainer = metadata.genericContainers[cppTypeDefinition.genericContainerIndex]; if (genericContainer.type_argc <= ilTypeDefinition.GenericParameters.Count) { return(typeMethods); //Finished processing } for (var i = 0; i < genericContainer.type_argc; i++) { var genericParameterIndex = genericContainer.genericParameterStart + i; var param = metadata.genericParameters[genericParameterIndex]; var genericName = metadata.GetStringFromIndex(param.nameIndex); if (!SharedState.GenericParamsByIndex.TryGetValue(genericParameterIndex, out var genericParameter)) { genericParameter = new GenericParameter(genericName, ilTypeDefinition); ilTypeDefinition.GenericParameters.Add(genericParameter); SharedState.GenericParamsByIndex.Add(genericParameterIndex, genericParameter); } else { if (ilTypeDefinition.GenericParameters.Contains(genericParameter)) { continue; } ilTypeDefinition.GenericParameters.Add(genericParameter); } } return(typeMethods); }
internal void WriteType(StreamWriter writer, Il2CppTypeDefinition typeDef) { if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_SERIALIZABLE) != 0) { writer.Write("\t[Serializable]\n"); } WriteAttribute(writer, typeDef.customAttributeIndex, "\t"); var isStruct = false; string parent = null; if (typeDef.parentIndex >= 0) { var pType = il2cpp.Code.GetTypeFromTypeIndex(typeDef.parentIndex); var name = il2cpp.GetTypeName(pType); if (name == "ValueType") { isStruct = true; } else if (name != "object") { parent = name; } } writer.Write("\t"); if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_VISIBILITY_MASK) == DefineConstants.TYPE_ATTRIBUTE_PUBLIC) { writer.Write("public "); } if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_ABSTRACT) != 0) { writer.Write("abstract "); } if (!isStruct && (typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_SEALED) != 0) { writer.Write("sealed "); } if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_INTERFACE) != 0) { writer.Write("interface "); } else if (isStruct) { writer.Write("struct "); } else { writer.Write("class "); } var nameSpace = metadata.GetTypeNamespace(typeDef); if (nameSpace.Length > 0) { nameSpace += "."; } writer.Write($"{nameSpace}{metadata.GetTypeName(typeDef)}"); var yes = typeDef.vtable_count == typeDef.method_count; yes.ToString(); // class extenss another type if (parent != null) { writer.Write($" : {parent}"); } writer.Write("\n\t{\n"); this.WriteFields(writer, typeDef); this.WriteMethods(writer, typeDef); writer.Write("\t}\n\n"); }
internal void WriteType(StreamWriter writer, Il2CppTypeDefinition typeDef, string pad = "") { if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_ABSTRACT) != 0) { return; } var typesToDump = new List <GenericIl2CppType>(); writer.Write("\n"); writer.Write(pad + $"message {metadata.GetTypeName(typeDef)} {{\n"); var methodsReturn = new Dictionary <string, GenericIl2CppType>(); var methodEnd = typeDef.methodStart + typeDef.method_count; for (int i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.Methods[i]; var name = metadata.GetString(methodDef.nameIndex); var pReturnType = il2cpp.Code.GetTypeFromTypeIndex(methodDef.returnType); methodsReturn[name] = pReturnType; } var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (int i = typeDef.fieldStart; i < fieldEnd; ++i) { var pField = metadata.Fields[i]; var fieldName = metadata.GetString(pField.nameIndex); if (fieldName.EndsWith("FieldNumber")) { var realName = fieldName.Substring(0, fieldName.Length - "FieldNumber".Length); var protoIndex = this.GetDefaultValue(i); var getter = "get_" + realName; var pType = methodsReturn[getter]; realName = this.ToSnakeCase(realName); var realType = this.GetProtoType(il2cpp.GetTypeName(methodsReturn[getter]), realName); writer.Write(pad + $"\t{realType} {realName} = {protoIndex};\n"); if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) { typesToDump.Add(pType); } } } foreach (var pType in typesToDump) { var realType = pType; if (realType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) { realType = il2cpp.GetTypeFromGeneric(realType); } var subtypeDef = metadata.Types[realType.klassIndex]; if (realType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE || realType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS) { if (!holoTypes.Any(t => t.nameIndex == subtypeDef.nameIndex)) { if (subtypeDef.parentIndex == enumIdx) { this.WriteEnum(writer, subtypeDef, pad + "\t"); } else { this.WriteType(writer, subtypeDef, pad + "\t"); } } } } writer.Write(pad + "}\n"); }
internal void WriteType(StreamWriter writer, Il2CppTypeDefinition typeDef) { if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_SERIALIZABLE) != 0) { writer.Write("\t[Serializable]\n"); } WriteAttribute(writer, typeDef.customAttributeIndex, "\t"); var isStruct = false; string parent = null; if (typeDef.parentIndex >= 0) { var pType = il2cpp.Code.GetTypeFromTypeIndex(typeDef.parentIndex); var name = il2cpp.GetTypeName(pType); if (name == "ValueType") { isStruct = true; } else if (name != "object") { if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS) { var klass = metadata.Types[pType.klassIndex]; var parentNameSpace = metadata.GetTypeNamespace(klass); if (parentNameSpace.Length > 0) { parentNameSpace += "."; } parent = parentNameSpace + name; } else { parent = name; } } } writer.Write("\t"); if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_VISIBILITY_MASK) == DefineConstants.TYPE_ATTRIBUTE_PUBLIC) { writer.Write("public "); } if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_ABSTRACT) != 0) { writer.Write("abstract "); } if (!isStruct && (typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_SEALED) != 0) { writer.Write("sealed "); } if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_INTERFACE) != 0) { writer.Write("interface "); } else if (isStruct) { writer.Write("struct "); } else { writer.Write("class "); } var nameSpace = metadata.GetTypeNamespace(typeDef); if (nameSpace.Length > 0) { nameSpace += "."; } writer.Write($"{nameSpace}{metadata.GetTypeName(typeDef)}"); // class extends another type if (parent != null) { writer.Write($" : {parent}"); } writer.Write("\n\t{\n"); if (this.IncludeOffsets && typeDef.delegateWrapperFromManagedToNativeIndex >= 0) { var nativeIdx = typeDef.delegateWrapperFromManagedToNativeIndex; var ptr = il2cpp.Code.ManagedToNative[nativeIdx]; writer.Write("\t\t// Native method : 0x{0:x}\n", ptr); } this.WriteFields(writer, typeDef); this.WriteMethods(writer, typeDef); writer.Write("\t}\n\n"); }