public EventInfo(Il2CppInspector pkg, int eventIndex, TypeInfo declaringType) : base(declaringType) { Definition = pkg.Metadata.Events[eventIndex]; Index = eventIndex; Name = pkg.Strings[Definition.nameIndex]; eventType = pkg.TypeUsages[Definition.typeIndex]; if ((eventType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_SPECIAL_NAME) == Il2CppConstants.FIELD_ATTRIBUTE_SPECIAL_NAME) { Attributes |= EventAttributes.SpecialName; } // NOTE: This relies on methods being added to TypeInfo.DeclaredMethods in the same order they are defined in the Il2Cpp metadata // add, remove and raise are method indices from the first method of the declaring type if (Definition.add >= 0) { AddMethod = declaringType.DeclaredMethods[Definition.add]; } if (Definition.remove >= 0) { RemoveMethod = declaringType.DeclaredMethods[Definition.remove]; } if (Definition.raise >= 0) { RaiseMethod = declaringType.DeclaredMethods[Definition.raise]; } }
public FieldInfo(Il2CppInspector pkg, int fieldIndex, TypeInfo declaringType) : base(declaringType) { Definition = pkg.Fields[fieldIndex]; MetadataToken = (int)Definition.token; Index = fieldIndex; Name = pkg.Strings[Definition.nameIndex]; rawOffset = pkg.FieldOffsets[fieldIndex]; rootDefinition = this; fieldTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.typeIndex); var fieldType = pkg.TypeReferences[Definition.typeIndex]; // Copy attributes Attributes = (FieldAttributes)fieldType.attrs; // Default initialization value if present if (pkg.FieldDefaultValue.TryGetValue(fieldIndex, out (ulong address, object variant)value)) { DefaultValue = value.variant; DefaultValueMetadataAddress = value.address; } }
public EventInfo(Il2CppInspector pkg, int eventIndex, TypeInfo declaringType) : base(declaringType) { Definition = pkg.Events[eventIndex]; Index = eventIndex; Name = pkg.Strings[Definition.nameIndex]; rootDefinition = this; eventTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.typeIndex); var eventType = pkg.TypeReferences[Definition.typeIndex]; if ((eventType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_SPECIAL_NAME) == Il2CppConstants.FIELD_ATTRIBUTE_SPECIAL_NAME) { Attributes |= EventAttributes.SpecialName; } // NOTE: This relies on methods being added to TypeInfo.DeclaredMethods in the same order they are defined in the Il2Cpp metadata // add, remove and raise are method indices from the first method of the declaring type if (Definition.add >= 0) { AddMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.add); } if (Definition.remove >= 0) { RemoveMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.remove); } if (Definition.raise >= 0) { RaiseMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.raise); } }
public static MetadataUsage FromEncodedIndex(Il2CppInspector package, uint encodedIndex, ulong virtualAddress = 0) { uint index; MetadataUsageType usageType; if (package.Version < 19) { /* These encoded indices appear only in vtables, and are decoded by IsGenericMethodIndex/GetDecodedMethodIndex */ var isGeneric = encodedIndex & 0x80000000; index = package.Binary.VTableMethodReferences[encodedIndex & 0x7FFFFFFF]; usageType = (isGeneric != 0) ? MetadataUsageType.MethodRef : MetadataUsageType.MethodDef; } else { /* These encoded indices appear in metadata usages, and are decoded by GetEncodedIndexType/GetDecodedMethodIndex */ var encodedType = encodedIndex & 0xE0000000; usageType = (MetadataUsageType)(encodedType >> 29); index = encodedIndex & 0x1FFFFFFF; // From v27 the bottom bit is set to indicate the usage token hasn't been replaced with a pointer at runtime yet if (package.Version >= 27) { index >>= 1; } } return(new MetadataUsage(usageType, (int)index, virtualAddress)); }
public EventInfo(Il2CppInspector pkg, int eventIndex, TypeInfo declaringType) : base(declaringType) { Definition = pkg.Events[eventIndex]; MetadataToken = (int)Definition.token; Index = eventIndex; Name = pkg.Strings[Definition.nameIndex]; rootDefinition = this; eventTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.typeIndex); var eventType = pkg.TypeReferences[Definition.typeIndex]; // Copy attributes Attributes = (EventAttributes)eventType.attrs; // NOTE: This relies on methods being added to TypeInfo.DeclaredMethods in the same order they are defined in the Il2Cpp metadata // add, remove and raise are method indices from the first method of the declaring type if (Definition.add >= 0) { AddMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.add); } if (Definition.remove >= 0) { RemoveMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.remove); } if (Definition.raise >= 0) { RaiseMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.raise); } }
public Il2CppReflector(Il2CppInspector package) { Package = package; // Create Assembly objects from Il2Cpp package for (var image = 0; image < package.Metadata.Images.Length; image++) { Assemblies.Add(new Assembly(this, image)); } }
public Il2CppModel(Il2CppInspector package) { Package = package; TypesByDefinitionIndex = new TypeInfo[package.TypeDefinitions.Length]; TypesByUsageIndex = new TypeInfo[package.TypeUsages.Count]; MethodsByDefinitionIndex = new MethodBase[package.Methods.Length]; // Create Assembly objects from Il2Cpp package for (var image = 0; image < package.Images.Length; image++) { Assemblies.Add(new Assembly(this, image)); } }
public PropertyInfo(Il2CppInspector pkg, int propIndex, TypeInfo declaringType) : base(declaringType) { Index = propIndex; Definition = pkg.Properties[propIndex]; Name = pkg.Strings[Definition.nameIndex]; // prop.get and prop.set are method indices from the first method of the declaring type if (Definition.get >= 0) { GetMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.get); } if (Definition.set >= 0) { SetMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.set); } }
public PropertyInfo(Il2CppInspector pkg, int propIndex, TypeInfo declaringType) : base(declaringType) { var prop = pkg.Metadata.Properties[propIndex]; Name = pkg.Strings[prop.nameIndex]; // NOTE: This relies on methods being added to TypeInfo.DeclaredMethods in the same order they are defined in the Il2Cpp metadata // prop.get and prop.set are method indices from the first method of the declaring type if (prop.get >= 0) { GetMethod = declaringType.DeclaredMethods[prop.get]; } if (prop.set >= 0) { SetMethod = declaringType.DeclaredMethods[prop.set]; } }
public static MetadataUsage FromEncodedIndex(Il2CppInspector package, uint encodedIndex) { uint index; MetadataUsageType usageType; if (package.Version < 19) { /* These encoded indices appear only in vtables, and are decoded by IsGenericMethodIndex/GetDecodedMethodIndex */ var isGeneric = encodedIndex & 0x80000000; index = package.Binary.VTableMethodReferences[encodedIndex & 0x7FFFFFFF]; usageType = (isGeneric != 0) ? MetadataUsageType.MethodRef : MetadataUsageType.MethodDef; } else { /* These encoded indices appear in metadata usages, and are decoded by GetEncodedIndexType/GetDecodedMethodIndex */ var encodedType = encodedIndex & 0xE0000000; usageType = (MetadataUsageType)(encodedType >> 29); index = encodedIndex & 0x1FFFFFFF; } return(new MetadataUsage(usageType, (int)index)); }
public PropertyInfo(Il2CppInspector pkg, int propIndex, TypeInfo declaringType) : base(declaringType) { Index = propIndex; Definition = pkg.Properties[propIndex]; MetadataToken = (int)Definition.token; Name = pkg.Strings[Definition.nameIndex]; rootDefinition = this; // Copy attributes Attributes = (PropertyAttributes)Definition.attrs; // prop.get and prop.set are method indices from the first method of the declaring type if (Definition.get >= 0) { GetMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.get); } if (Definition.set >= 0) { SetMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.set); } }
// Create a parameter. Specify paramIndex == -1 for a return type parameter public ParameterInfo(Il2CppInspector pkg, int paramIndex, MethodBase declaringMethod) { Index = paramIndex; DeclaringMethod = declaringMethod; if (paramIndex == -1) { Position = -1; paramTypeReference = TypeRef.FromReferenceIndex(declaringMethod.Assembly.Model, declaringMethod.Definition.returnType); Attributes |= ParameterAttributes.Retval; return; } Definition = pkg.Params[Index]; MetadataToken = (int)Definition.token; Name = pkg.Strings[Definition.nameIndex]; rootDefinition = this; // Handle unnamed/obfuscated parameter names if (string.IsNullOrEmpty(Name)) { Name = string.Format($"param_{Index:x8}"); } Position = paramIndex - declaringMethod.Definition.parameterStart; paramTypeReference = TypeRef.FromReferenceIndex(declaringMethod.Assembly.Model, Definition.typeIndex); var paramType = pkg.TypeReferences[Definition.typeIndex]; // Copy attributes Attributes = (ParameterAttributes)paramType.attrs; // Default initialization value if present if (pkg.ParameterDefaultValue.TryGetValue(paramIndex, out (ulong address, object variant)value)) { DefaultValue = value.variant; DefaultValueMetadataAddress = value.address; } }
// Create a parameter. Specify paramIndex == -1 for a return type parameter public ParameterInfo(Il2CppInspector pkg, int paramIndex, MethodInfo declaringMethod) { Member = declaringMethod; if (paramIndex == -1) { Position = -1; paramType = pkg.TypeUsages[declaringMethod.Definition.returnType]; Attributes |= ParameterAttributes.Retval; return; } var param = pkg.Metadata.Params[paramIndex]; Name = pkg.Metadata.Strings[param.nameIndex]; Position = paramIndex - declaringMethod.Definition.parameterStart; paramType = pkg.TypeUsages[param.typeIndex]; if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_OPTIONAL) != 0) { Attributes |= ParameterAttributes.Optional; } if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_OUT) != 0) { Attributes |= ParameterAttributes.Out; } if (Position == -1) { Attributes |= ParameterAttributes.Retval; } else if (!IsOut) { Attributes |= ParameterAttributes.In; } // TODO: DefaultValue/HasDefaultValue }
// Create type model public TypeModel(Il2CppInspector package) { Package = package; TypesByDefinitionIndex = new TypeInfo[package.TypeDefinitions.Length]; TypesByReferenceIndex = new TypeInfo[package.TypeReferences.Count]; GenericParameterTypes = new TypeInfo[package.GenericParameters.Length]; MethodsByDefinitionIndex = new MethodBase[package.Methods.Length]; MethodInvokers = new MethodInvoker[package.MethodInvokePointers.Length]; // Recursively create hierarchy of assemblies and types from TypeDefs // No code that executes here can access any type through a TypeRef (ie. via TypesByReferenceIndex) for (var image = 0; image < package.Images.Length; image++) { Assemblies.Add(new Assembly(this, image)); } // Create and reference types from TypeRefs // Note that you can't resolve any TypeRefs until all the TypeDefs have been processed for (int typeRefIndex = 0; typeRefIndex < package.TypeReferences.Count; typeRefIndex++) { if (TypesByReferenceIndex[typeRefIndex] != null) { /* type already generated - probably by forward reference through GetTypeFromVirtualAddress */ continue; } var typeRef = Package.TypeReferences[typeRefIndex]; var referencedType = resolveTypeReference(typeRef); TypesByReferenceIndex[typeRefIndex] = referencedType; } // Create types and methods from MethodSpec (which incorporates TypeSpec in IL2CPP) foreach (var spec in Package.MethodSpecs) { var methodDefinition = MethodsByDefinitionIndex[spec.methodDefinitionIndex]; var declaringType = methodDefinition.DeclaringType; // Concrete instance of a generic class // If the class index is not specified, we will later create a generic method in a non-generic class if (spec.classIndexIndex != -1) { var genericInstance = Package.GenericInstances[spec.classIndexIndex]; var genericArguments = ResolveGenericArguments(genericInstance); declaringType = declaringType.MakeGenericType(genericArguments); } MethodBase method; if (methodDefinition is ConstructorInfo) { method = declaringType.GetConstructorByDefinition((ConstructorInfo)methodDefinition); } else { method = declaringType.GetMethodByDefinition((MethodInfo)methodDefinition); } if (spec.methodIndexIndex != -1) { var genericInstance = Package.GenericInstances[spec.methodIndexIndex]; var genericArguments = ResolveGenericArguments(genericInstance); method = method.MakeGenericMethod(genericArguments); } method.VirtualAddress = Package.GetGenericMethodPointer(spec); GenericMethods[spec] = method; } // Generate a list of all namespaces used Namespaces = Assemblies.SelectMany(x => x.DefinedTypes).GroupBy(t => t.Namespace).Select(n => n.Key).Distinct().ToList(); // Find all custom attribute generators (populate AttributesByIndices) (use ToList() to force evaluation) var allAssemblyAttributes = Assemblies.Select(a => a.CustomAttributes).ToList(); var allTypeAttributes = TypesByDefinitionIndex.Select(t => t.CustomAttributes).ToList(); var allEventAttributes = TypesByDefinitionIndex.SelectMany(t => t.DeclaredEvents).Select(e => e.CustomAttributes).ToList(); var allFieldAttributes = TypesByDefinitionIndex.SelectMany(t => t.DeclaredFields).Select(f => f.CustomAttributes).ToList(); var allPropertyAttributes = TypesByDefinitionIndex.SelectMany(t => t.DeclaredProperties).Select(p => p.CustomAttributes).ToList(); var allMethodAttributes = MethodsByDefinitionIndex.Select(m => m.CustomAttributes).ToList(); var allParameterAttributes = MethodsByDefinitionIndex.SelectMany(m => m.DeclaredParameters).Select(p => p.CustomAttributes).ToList(); // Create method invokers (one per signature, in invoker index order) foreach (var method in MethodsByDefinitionIndex) { var index = package.GetInvokerIndex(method.DeclaringType.Assembly.ModuleDefinition, method.Definition); if (index != -1) { if (MethodInvokers[index] == null) { MethodInvokers[index] = new MethodInvoker(method, index); } method.Invoker = MethodInvokers[index]; } } // TODO: Some invokers are not initialized or missing, need to find out why // Create method invokers sourced from generic method invoker indices foreach (var spec in GenericMethods.Keys) { if (package.GenericMethodInvokerIndices.TryGetValue(spec, out var index)) { if (MethodInvokers[index] == null) { MethodInvokers[index] = new MethodInvoker(GenericMethods[spec], index); } GenericMethods[spec].Invoker = MethodInvokers[index]; } } }
public FieldInfo(Il2CppInspector pkg, int fieldIndex, TypeInfo declaringType) : base(declaringType) { Definition = pkg.Fields[fieldIndex]; Index = fieldIndex; Name = pkg.Strings[Definition.nameIndex]; rawOffset = pkg.FieldOffsets[fieldIndex]; rootDefinition = this; fieldTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.typeIndex); var fieldType = pkg.TypeReferences[Definition.typeIndex]; if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == Il2CppConstants.FIELD_ATTRIBUTE_PRIVATE) { Attributes |= FieldAttributes.Private; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == Il2CppConstants.FIELD_ATTRIBUTE_PUBLIC) { Attributes |= FieldAttributes.Public; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == Il2CppConstants.FIELD_ATTRIBUTE_FAM_AND_ASSEM) { Attributes |= FieldAttributes.FamANDAssem; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == Il2CppConstants.FIELD_ATTRIBUTE_ASSEMBLY) { Attributes |= FieldAttributes.Assembly; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == Il2CppConstants.FIELD_ATTRIBUTE_FAMILY) { Attributes |= FieldAttributes.Family; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == Il2CppConstants.FIELD_ATTRIBUTE_FAM_OR_ASSEM) { Attributes |= FieldAttributes.FamORAssem; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_STATIC) == Il2CppConstants.FIELD_ATTRIBUTE_STATIC) { Attributes |= FieldAttributes.Static; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_INIT_ONLY) == Il2CppConstants.FIELD_ATTRIBUTE_INIT_ONLY) { Attributes |= FieldAttributes.InitOnly; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_LITERAL) == Il2CppConstants.FIELD_ATTRIBUTE_LITERAL) { Attributes |= FieldAttributes.Literal; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_NOT_SERIALIZED) == Il2CppConstants.FIELD_ATTRIBUTE_NOT_SERIALIZED) { Attributes |= FieldAttributes.NotSerialized; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_SPECIAL_NAME) == Il2CppConstants.FIELD_ATTRIBUTE_SPECIAL_NAME) { Attributes |= FieldAttributes.SpecialName; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_PINVOKE_IMPL) == Il2CppConstants.FIELD_ATTRIBUTE_PINVOKE_IMPL) { Attributes |= FieldAttributes.PinvokeImpl; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_HAS_DEFAULT) != 0) { Attributes |= FieldAttributes.HasDefault; } // Default initialization value if present if (pkg.FieldDefaultValue.TryGetValue(fieldIndex, out (ulong address, object variant)value)) { DefaultValue = value.variant; DefaultValueMetadataAddress = value.address; } }
// TODO: ReturnTypeCustomAttributes public MethodInfo(Il2CppInspector pkg, int methodIndex, TypeInfo declaringType) : base(declaringType) { Definition = pkg.Metadata.Methods[methodIndex]; Index = methodIndex; if (Definition.methodIndex >= 0) { VirtualAddress = pkg.Binary.MethodPointers[Definition.methodIndex]; HasBody = true; } Name = pkg.Strings[Definition.nameIndex]; if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == Il2CppConstants.METHOD_ATTRIBUTE_PRIVATE) { Attributes |= MethodAttributes.Private; } if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == Il2CppConstants.METHOD_ATTRIBUTE_PUBLIC) { Attributes |= MethodAttributes.Public; } if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == Il2CppConstants.METHOD_ATTRIBUTE_FAM_AND_ASSEM) { Attributes |= MethodAttributes.FamANDAssem; } if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == Il2CppConstants.METHOD_ATTRIBUTE_ASSEM) { Attributes |= MethodAttributes.Assembly; } if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == Il2CppConstants.METHOD_ATTRIBUTE_FAMILY) { Attributes |= MethodAttributes.Family; } if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == Il2CppConstants.METHOD_ATTRIBUTE_FAM_OR_ASSEM) { Attributes |= MethodAttributes.FamORAssem; } if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_VIRTUAL) != 0) { Attributes |= MethodAttributes.Virtual; } if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_ABSTRACT) != 0) { Attributes |= MethodAttributes.Abstract; } if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_STATIC) != 0) { Attributes |= MethodAttributes.Static; } if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_FINAL) != 0) { Attributes |= MethodAttributes.Final; } if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_HIDE_BY_SIG) != 0) { Attributes |= MethodAttributes.HideBySig; } if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK) == Il2CppConstants.METHOD_ATTRIBUTE_NEW_SLOT) { Attributes |= MethodAttributes.NewSlot; } if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_PINVOKE_IMPL) != 0) { Attributes |= MethodAttributes.PinvokeImpl; } if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_SPECIAL_NAME) != 0) { Attributes |= MethodAttributes.SpecialName; } if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_UNMANAGED_EXPORT) != 0) { Attributes |= MethodAttributes.UnmanagedExport; } // Add return parameter returnType = pkg.TypeUsages[Definition.returnType]; ReturnParameter = new ParameterInfo(pkg, -1, this); // Add arguments for (var p = Definition.parameterStart; p < Definition.parameterStart + Definition.parameterCount; p++) { DeclaredParameters.Add(new ParameterInfo(pkg, p, this)); } }
public FieldInfo(Il2CppInspector pkg, int fieldIndex, TypeInfo declaringType) : base(declaringType) { Definition = pkg.Metadata.Fields[fieldIndex]; Index = fieldIndex; Offset = pkg.FieldOffsets[fieldIndex]; Name = pkg.Strings[Definition.nameIndex]; fieldType = pkg.TypeUsages[Definition.typeIndex]; if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == Il2CppConstants.FIELD_ATTRIBUTE_PRIVATE) { Attributes |= FieldAttributes.Private; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == Il2CppConstants.FIELD_ATTRIBUTE_PUBLIC) { Attributes |= FieldAttributes.Public; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == Il2CppConstants.FIELD_ATTRIBUTE_FAM_AND_ASSEM) { Attributes |= FieldAttributes.FamANDAssem; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == Il2CppConstants.FIELD_ATTRIBUTE_ASSEMBLY) { Attributes |= FieldAttributes.Assembly; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == Il2CppConstants.FIELD_ATTRIBUTE_FAMILY) { Attributes |= FieldAttributes.Family; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == Il2CppConstants.FIELD_ATTRIBUTE_FAM_OR_ASSEM) { Attributes |= FieldAttributes.FamORAssem; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_STATIC) == Il2CppConstants.FIELD_ATTRIBUTE_STATIC) { Attributes |= FieldAttributes.Static; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_INIT_ONLY) == Il2CppConstants.FIELD_ATTRIBUTE_INIT_ONLY) { Attributes |= FieldAttributes.InitOnly; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_LITERAL) == Il2CppConstants.FIELD_ATTRIBUTE_LITERAL) { Attributes |= FieldAttributes.Literal; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_NOT_SERIALIZED) == Il2CppConstants.FIELD_ATTRIBUTE_NOT_SERIALIZED) { Attributes |= FieldAttributes.NotSerialized; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_SPECIAL_NAME) == Il2CppConstants.FIELD_ATTRIBUTE_SPECIAL_NAME) { Attributes |= FieldAttributes.SpecialName; } if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_PINVOKE_IMPL) == Il2CppConstants.FIELD_ATTRIBUTE_PINVOKE_IMPL) { Attributes |= FieldAttributes.PinvokeImpl; } // Default initialization value if present if (pkg.FieldDefaultValue.TryGetValue(fieldIndex, out object variant)) { HasDefaultValue = true; DefaultValue = variant; } }
private static int Run(Options options) { // Banner var asmInfo = FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetEntryAssembly().Location); Console.WriteLine(asmInfo.ProductName); Console.WriteLine("Version " + asmInfo.ProductVersion); Console.WriteLine(asmInfo.LegalCopyright); Console.WriteLine(""); // Check excluded namespaces if (options.ExcludedNamespaces.Count() == 1 && options.ExcludedNamespaces.First().ToLower() == "none") { options.ExcludedNamespaces = new List <string>(); } // Check files if (!File.Exists(options.BinaryFile)) { Console.Error.WriteLine($"File {options.BinaryFile} does not exist"); return(1); } if (!File.Exists(options.MetadataFile)) { Console.Error.WriteLine($"File {options.MetadataFile} does not exist"); return(1); } // Creating a Visual Studio solution requires Unity assembly references var unityPath = string.Empty; var unityAssembliesPath = string.Empty; if (options.CreateSolution) { unityPath = Utils.FindPath(options.UnityPath); unityAssembliesPath = Utils.FindPath(options.UnityAssembliesPath); if (!Directory.Exists(unityPath)) { Console.Error.WriteLine($"Unity path {unityPath} does not exist"); return(1); } if (!File.Exists(unityPath + @"\Editor\Data\Managed\UnityEditor.dll")) { Console.Error.WriteLine($"No Unity installation found at {unityPath}"); return(1); } if (!Directory.Exists(unityAssembliesPath)) { Console.Error.WriteLine($"Unity assemblies path {unityAssembliesPath} does not exist"); return(1); } if (!File.Exists(unityAssembliesPath + @"\UnityEngine.UI.dll")) { Console.Error.WriteLine($"No Unity assemblies found at {unityAssembliesPath}"); return(1); } Console.WriteLine("Using Unity editor at " + unityPath); Console.WriteLine("Using Unity assemblies at " + unityAssembliesPath); } // Analyze data List <Il2CppInspector> il2cppInspectors; using (var il2cppTimer = new Benchmark("Analyze IL2CPP data")) il2cppInspectors = Il2CppInspector.LoadFromFile(options.BinaryFile, options.MetadataFile); if (il2cppInspectors == null) { Environment.Exit(1); } // Write output file int i = 0; foreach (var il2cpp in il2cppInspectors) { // Create model Il2CppModel model; using (var modelTimer = new Benchmark("Create type model")) model = new Il2CppModel(il2cpp); // C# signatures output using (var signaturesDumperTimer = new Benchmark("Generate C# code")) { var writer = new CSharpCodeStubs(model) { ExcludedNamespaces = options.ExcludedNamespaces.ToList(), SuppressMetadata = options.SuppressMetadata, MustCompile = options.MustCompile }; var imageSuffix = i++ > 0 ? "-" + (i - 1) : ""; var csOut = options.CSharpOutPath; if (csOut.ToLower().EndsWith(".cs")) { csOut = csOut.Insert(csOut.Length - 3, imageSuffix); } else { csOut += imageSuffix; } if (options.CreateSolution) { writer.WriteSolution(csOut, unityPath, unityAssembliesPath); } else { switch (options.LayoutSchema.ToLower(), options.SortOrder.ToLower()) {
private static int Run(Options options) { // Banner var asmInfo = FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetEntryAssembly().Location); Console.WriteLine(asmInfo.ProductName); Console.WriteLine("Version " + asmInfo.ProductVersion); Console.WriteLine(asmInfo.LegalCopyright); Console.WriteLine(""); // Check excluded namespaces if (options.ExcludedNamespaces.Count() == 1 && options.ExcludedNamespaces.First().ToLower() == "none") { options.ExcludedNamespaces = new List <string>(); } // Creating a Visual Studio solution requires Unity assembly references var unityPath = string.Empty; var unityAssembliesPath = string.Empty; if (options.CreateSolution) { unityPath = Utils.FindPath(options.UnityPath); unityAssembliesPath = Utils.FindPath(options.UnityAssembliesPath); if (!Directory.Exists(unityPath)) { Console.Error.WriteLine($"Unity path {unityPath} does not exist"); return(1); } string editorPathSuffix = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? @"/Contents/Managed/UnityEditor.dll" : @"\Editor\Data\Managed\UnityEditor.dll"; if (!File.Exists(unityPath + editorPathSuffix)) { Console.Error.WriteLine($"No Unity installation found at {unityPath}"); return(1); } if (!Directory.Exists(unityAssembliesPath)) { Console.Error.WriteLine($"Unity assemblies path {unityAssembliesPath} does not exist"); return(1); } string uiDllPath = Path.Combine(unityAssembliesPath, "UnityEngine.UI.dll"); if (!File.Exists(uiDllPath)) { Console.Error.WriteLine($"No UnityEngine.UI.dll assemblies found at {uiDllPath}"); return(1); } Console.WriteLine("Using Unity editor at " + unityPath); Console.WriteLine("Using Unity assemblies at " + unityAssembliesPath); } // Check files exist and determine whether they're archives or not List <Il2CppInspector> il2cppInspectors; using (new Benchmark("Analyze IL2CPP data")) { if (!File.Exists(options.BinaryFile)) { Console.Error.WriteLine($"File {options.BinaryFile} does not exist"); return(1); } try { il2cppInspectors = Il2CppInspector.LoadFromPackage(options.BinaryFile); } catch (Exception ex) { Console.Error.WriteLine(ex.Message); return(1); } if (il2cppInspectors == null) { if (!File.Exists(options.MetadataFile)) { Console.Error.WriteLine($"File {options.MetadataFile} does not exist"); return(1); } il2cppInspectors = Il2CppInspector.LoadFromFile(options.BinaryFile, options.MetadataFile); } } if (il2cppInspectors == null) { Environment.Exit(1); } // Write output file int i = 0; foreach (var il2cpp in il2cppInspectors) { // Create model TypeModel model; using (new Benchmark("Create .NET type model")) model = new TypeModel(il2cpp); AppModel appModel; using (new Benchmark("Create C++ application model")) { appModel = new AppModel(model).Build(options.UnityVersion, options.CppCompiler); } // C# signatures output using (new Benchmark("Generate C# code")) { var writer = new CSharpCodeStubs(model) { ExcludedNamespaces = options.ExcludedNamespaces.ToList(), SuppressMetadata = options.SuppressMetadata, MustCompile = options.MustCompile }; var imageSuffix = i++ > 0 ? "-" + (i - 1) : ""; var csOut = options.CSharpOutPath; if (csOut.ToLower().EndsWith(".cs")) { csOut = csOut.Insert(csOut.Length - 3, imageSuffix); } else { csOut += imageSuffix; } if (options.CreateSolution) { writer.WriteSolution(csOut, unityPath, unityAssembliesPath); } else { switch (options.LayoutSchema.ToLower(), options.SortOrder.ToLower()) {
// IL2CPP doesn't seem to retain return type custom attributes public MethodInfo(Il2CppInspector pkg, int methodIndex, TypeInfo declaringType) : base(pkg, methodIndex, declaringType) { // Add return parameter returnTypeUsage = Definition.returnType; ReturnParameter = new ParameterInfo(pkg, -1, this); }
private static int Run(Options options) { // Banner var asmInfo = FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetEntryAssembly().Location); Console.WriteLine(asmInfo.ProductName); Console.WriteLine("Version " + asmInfo.ProductVersion); Console.WriteLine(asmInfo.LegalCopyright); Console.WriteLine(""); // Check script target is valid if (!PythonScript.GetAvailableTargets().Contains(options.ScriptTarget)) { Console.Error.WriteLine($"Script target {options.ScriptTarget} is invalid."); Console.Error.WriteLine("Valid targets are: " + string.Join(", ", PythonScript.GetAvailableTargets())); return(1); } // Check excluded namespaces if (options.ExcludedNamespaces.Count() == 1 && options.ExcludedNamespaces.First().ToLower() == "none") { options.ExcludedNamespaces = new List <string>(); } // Creating a Visual Studio solution requires Unity assembly references var unityPath = string.Empty; var unityAssembliesPath = string.Empty; if (options.CreateSolution) { unityPath = Utils.FindPath(options.UnityPath); unityAssembliesPath = Utils.FindPath(options.UnityAssembliesPath); if (!Directory.Exists(unityPath)) { Console.Error.WriteLine($"Unity path {unityPath} does not exist"); return(1); } string editorPathSuffix = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? @"/Contents/Managed/UnityEditor.dll" : @"\Editor\Data\Managed\UnityEditor.dll"; if (!File.Exists(unityPath + editorPathSuffix)) { Console.Error.WriteLine($"No Unity installation found at {unityPath}"); return(1); } if (!Directory.Exists(unityAssembliesPath)) { Console.Error.WriteLine($"Unity assemblies path {unityAssembliesPath} does not exist"); return(1); } string uiDllPath = Path.Combine(unityAssembliesPath, "UnityEngine.UI.dll"); if (!File.Exists(uiDllPath)) { Console.Error.WriteLine($"No UnityEngine.UI.dll assemblies found at {uiDllPath}"); return(1); } Console.WriteLine("Using Unity editor at " + unityPath); Console.WriteLine("Using Unity assemblies at " + unityAssembliesPath); } // Check that specified binary files exist foreach (var file in options.BinaryFiles) { if (!File.Exists(file)) { Console.Error.WriteLine($"File {file} does not exist"); return(1); } } // Check files exist and determine whether they're archives or not List <Il2CppInspector> il2cppInspectors; using (new Benchmark("Analyze IL2CPP data")) { try { il2cppInspectors = Il2CppInspector.LoadFromPackage(options.BinaryFiles); } catch (Exception ex) { Console.Error.WriteLine(ex.Message); return(1); } if (il2cppInspectors == null) { if (!File.Exists(options.MetadataFile)) { Console.Error.WriteLine($"File {options.MetadataFile} does not exist"); return(1); } try { il2cppInspectors = Il2CppInspector.LoadFromFile(options.BinaryFiles.First(), options.MetadataFile); } catch (Exception ex) { Console.Error.WriteLine(ex.Message); return(1); } } } if (il2cppInspectors == null) { Environment.Exit(1); } // Write output files for each binary int imageIndex = 0; foreach (var il2cpp in il2cppInspectors) { Console.WriteLine($"Processing image {imageIndex} - {il2cpp.BinaryImage.Arch} / {il2cpp.BinaryImage.Bits}-bit"); // Create model TypeModel model; using (new Benchmark("Create .NET type model")) model = new TypeModel(il2cpp); AppModel appModel; using (new Benchmark("Create C++ application model")) { appModel = new AppModel(model, makeDefaultBuild: false).Build(options.UnityVersion, options.CppCompiler); } // C# signatures output using (new Benchmark("Generate C# code")) { var writer = new CSharpCodeStubs(model) { ExcludedNamespaces = options.ExcludedNamespaces.ToList(), SuppressMetadata = options.SuppressMetadata, MustCompile = options.MustCompile }; var csOut = getOutputPath(options.CSharpOutPath, "cs", imageIndex); if (options.CreateSolution) { writer.WriteSolution(csOut, unityPath, unityAssembliesPath); } else { switch (options.LayoutSchema.ToLower(), options.SortOrder.ToLower()) {
private static int Run(Options options) { // Banner var asmInfo = FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetEntryAssembly().Location); Console.WriteLine(asmInfo.ProductName); Console.WriteLine("Version " + asmInfo.ProductVersion); Console.WriteLine(asmInfo.LegalCopyright); Console.WriteLine(""); // Safe plugin manager load try { PluginManager.EnsureInit(); } catch (Exception ex) when(ex is InvalidOperationException || ex is DirectoryNotFoundException) { Console.Error.WriteLine(ex.Message); Environment.Exit(1); } // Check plugin options are valid if (!PluginOptions.ParsePluginOptions(options.PluginOptions, PluginOptions.GetPluginOptionTypes())) { return(1); } // Check script target is valid if (!PythonScript.GetAvailableTargets().Contains(options.ScriptTarget)) { Console.Error.WriteLine($"Script target {options.ScriptTarget} is invalid."); Console.Error.WriteLine("Valid targets are: " + string.Join(", ", PythonScript.GetAvailableTargets())); return(1); } // Set load options var loadOptions = new LoadOptions { BinaryFilePath = options.BinaryFiles.First() }; // Check image base if (!string.IsNullOrEmpty(options.ElfImageBaseString)) { try { loadOptions.ImageBase = Convert.ToUInt64(options.ElfImageBaseString, 16); } catch (Exception ex) when(ex is ArgumentException || ex is FormatException || ex is OverflowException) { Console.Error.WriteLine("Image base must be a 32 or 64-bit hex value (optionally starting with '0x')"); return(1); } } // Check Unity asset if (options.UnityVersionAsset != null) { try { options.UnityVersion = UnityVersion.FromAssetFile(options.UnityVersionAsset); Console.WriteLine("Unity asset file has version " + options.UnityVersion); } catch (FileNotFoundException) { Console.Error.WriteLine($"Unity asset file {options.UnityVersionAsset} does not exist"); return(1); } catch (ArgumentException) { Console.Error.WriteLine("Could not determine Unity version from asset file - ignoring"); } } // Check excluded namespaces if (options.ExcludedNamespaces.Count() == 1 && options.ExcludedNamespaces.First().ToLower() == "none") { options.ExcludedNamespaces = new List <string>(); } // Creating a Visual Studio solution requires Unity assembly references var unityPath = string.Empty; var unityAssembliesPath = string.Empty; if (options.CreateSolution) { unityPath = Utils.FindPath(options.UnityPath); unityAssembliesPath = Utils.FindPath(options.UnityAssembliesPath); if (!Directory.Exists(unityPath)) { Console.Error.WriteLine($"Unity path {unityPath} does not exist"); return(1); } string editorPathSuffix = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? @"/Contents/Managed/UnityEditor.dll" : @"\Editor\Data\Managed\UnityEditor.dll"; if (!File.Exists(unityPath + editorPathSuffix)) { Console.Error.WriteLine($"No Unity installation found at {unityPath}"); return(1); } if (!Directory.Exists(unityAssembliesPath)) { Console.Error.WriteLine($"Unity assemblies path {unityAssembliesPath} does not exist"); return(1); } string uiDllPath = Path.Combine(unityAssembliesPath, "UnityEngine.UI.dll"); if (!File.Exists(uiDllPath)) { Console.Error.WriteLine($"No UnityEngine.UI.dll assemblies found at {uiDllPath}"); return(1); } Console.WriteLine("Using Unity editor at " + unityPath); Console.WriteLine("Using Unity assemblies at " + unityAssembliesPath); } // Set plugin handlers PluginManager.ErrorHandler += (s, e) => { Console.Error.WriteLine($"The plugin {e.Error.Plugin.Name} encountered an error while executing {e.Error.Operation}: {e.Error.Exception.Message}." + " Plugin has been disabled."); }; PluginManager.StatusHandler += (s, e) => { Console.WriteLine("Plugin " + e.Plugin.Name + ": " + e.Text); }; // Check that specified binary files exist foreach (var file in options.BinaryFiles) { if (!File.Exists(file)) { Console.Error.WriteLine($"File {file} does not exist"); return(1); } } // Check files exist and determine whether they're archives or not bool isExtractedFromPackage = false; List <Il2CppInspector> il2cppInspectors; using (new Benchmark("Analyze IL2CPP data")) { try { il2cppInspectors = Il2CppInspector.LoadFromPackage(options.BinaryFiles, loadOptions); isExtractedFromPackage = true; } catch (Exception ex) { Console.Error.WriteLine(ex.Message); return(1); } if (il2cppInspectors == null) { isExtractedFromPackage = false; if (!File.Exists(options.MetadataFile)) { Console.Error.WriteLine($"File {options.MetadataFile} does not exist"); return(1); } try { il2cppInspectors = Il2CppInspector.LoadFromFile(options.BinaryFiles.First(), options.MetadataFile, loadOptions); } catch (Exception ex) { Console.Error.WriteLine(ex.Message); return(1); } } } if (il2cppInspectors == null) { Environment.Exit(1); } // Save metadata and binary if extracted or modified and save requested if (!string.IsNullOrEmpty(options.MetadataFileOut)) { if (isExtractedFromPackage || il2cppInspectors[0].Metadata.IsModified) { Console.WriteLine($"Saving metadata file to {options.MetadataFileOut}"); il2cppInspectors[0].SaveMetadataToFile(options.MetadataFileOut); } else { Console.WriteLine("Metadata file was not modified - skipping save"); } } if (!string.IsNullOrEmpty(options.BinaryFileOut)) { var outputIndex = 0; foreach (var il2cpp in il2cppInspectors) { // If there's an extension, strip the leading period var ext = Path.GetExtension(options.BinaryFileOut); if (ext.Length > 0) { ext = ext.Substring(1); } var outPath = getOutputPath(options.BinaryFileOut, ext, outputIndex); if (isExtractedFromPackage || il2cpp.Binary.IsModified) { Console.WriteLine($"Saving binary file to {outPath}"); il2cpp.SaveBinaryToFile(outPath); } else { Console.WriteLine("Binary file was not modified - skipping save"); } outputIndex++; } } // Write output files for each binary int imageIndex = 0; foreach (var il2cpp in il2cppInspectors) { Console.WriteLine($"Processing image {imageIndex} - {il2cpp.BinaryImage.Arch} / {il2cpp.BinaryImage.Bits}-bit"); // Create model TypeModel model; using (new Benchmark("Create .NET type model")) model = new TypeModel(il2cpp); AppModel appModel; using (new Benchmark("Create C++ application model")) { appModel = new AppModel(model, makeDefaultBuild: false).Build(options.UnityVersion, options.CppCompiler); } // C# signatures output using (new Benchmark("Generate C# code")) { var writer = new CSharpCodeStubs(model) { ExcludedNamespaces = options.ExcludedNamespaces.ToList(), SuppressMetadata = options.SuppressMetadata, MustCompile = options.MustCompile }; var csOut = getOutputPath(options.CSharpOutPath, "cs", imageIndex); if (options.CreateSolution) { writer.WriteSolution(csOut, unityPath, unityAssembliesPath); } else { switch (options.LayoutSchema.ToLower(), options.SortOrder.ToLower()) {
public ConstructorInfo(Il2CppInspector pkg, int methodIndex, TypeInfo declaringType) : base(pkg, methodIndex, declaringType) { }
// Create type model public Il2CppModel(Il2CppInspector package) { Package = package; TypesByDefinitionIndex = new TypeInfo[package.TypeDefinitions.Length]; TypesByReferenceIndex = new TypeInfo[package.TypeReferences.Count]; MethodsByDefinitionIndex = new MethodBase[package.Methods.Length]; MethodInvokers = new MethodInvoker[package.MethodInvokePointers.Length]; // Recursively create hierarchy of assemblies and types from TypeDefs // No code that executes here can access any type through a TypeRef (ie. via TypesByReferenceIndex) for (var image = 0; image < package.Images.Length; image++) { Assemblies.Add(new Assembly(this, image)); } // Create and reference types from TypeRefs // Note that you can't resolve any TypeRefs until all the TypeDefs have been processed for (int typeRefIndex = 0; typeRefIndex < package.TypeReferences.Count; typeRefIndex++) { var typeRef = Package.TypeReferences[typeRefIndex]; var referencedType = resolveTypeReference(typeRef); TypesByReferenceIndex[typeRefIndex] = referencedType; } // Create types and methods from MethodSpec (which incorporates TypeSpec in IL2CPP) foreach (var spec in Package.MethodSpecs) { TypeInfo declaringType; // Concrete instance of a generic class // If the class index is not specified, we will later create a generic method in a non-generic class if (spec.classIndexIndex != -1) { if (!TypesByMethodSpecClassIndex.ContainsKey(spec.classIndexIndex)) { TypesByMethodSpecClassIndex.Add(spec.classIndexIndex, new TypeInfo(this, spec)); } declaringType = TypesByMethodSpecClassIndex[spec.classIndexIndex]; } else { declaringType = MethodsByDefinitionIndex[spec.methodDefinitionIndex].DeclaringType; } // Concrete instance of a generic method if (spec.methodIndexIndex != -1) { // Method or constructor var concreteMethod = new MethodInfo(this, spec, declaringType); if (concreteMethod.Name == ConstructorInfo.ConstructorName || concreteMethod.Name == ConstructorInfo.TypeConstructorName) { GenericMethods.Add(spec, new ConstructorInfo(this, spec, declaringType)); } else { GenericMethods.Add(spec, concreteMethod); } } } // Create method invokers (one per signature, in invoker index order) foreach (var method in MethodsByDefinitionIndex) { var index = package.GetInvokerIndex(method.DeclaringType.Assembly.ModuleDefinition, method.Definition); if (index != -1) { if (MethodInvokers[index] == null) { MethodInvokers[index] = new MethodInvoker(method, index); } method.Invoker = MethodInvokers[index]; } } // TODO: Some invokers are not initialized or missing, need to find out why // Create method invokers sourced from generic method invoker indices foreach (var spec in GenericMethods.Keys) { if (package.GenericMethodInvokerIndices.TryGetValue(spec, out var index)) { if (MethodInvokers[index] == null) { MethodInvokers[index] = new MethodInvoker(GenericMethods[spec], index); } GenericMethods[spec].Invoker = MethodInvokers[index]; } } }
// Create a parameter. Specify paramIndex == -1 for a return type parameter public ParameterInfo(Il2CppInspector pkg, int paramIndex, MethodBase declaringMethod) { Index = paramIndex; DeclaringMethod = declaringMethod; if (paramIndex == -1) { Position = -1; paramTypeReference = declaringMethod.Definition.returnType; Attributes |= ParameterAttributes.Retval; return; } Definition = pkg.Params[Index]; Name = pkg.Strings[Definition.nameIndex]; // Handle unnamed/obfuscated parameter names if (string.IsNullOrEmpty(Name)) { Name = string.Format($"param_{Index:x8}"); } Position = paramIndex - declaringMethod.Definition.parameterStart; paramTypeReference = Definition.typeIndex; var paramType = pkg.TypeReferences[paramTypeReference]; if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_HAS_DEFAULT) != 0) { Attributes |= ParameterAttributes.HasDefault; } if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_OPTIONAL) != 0) { Attributes |= ParameterAttributes.Optional; } if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_IN) != 0) { Attributes |= ParameterAttributes.In; } if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_OUT) != 0) { Attributes |= ParameterAttributes.Out; } if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_RESERVED_MASK) != 0) { Attributes |= ParameterAttributes.ReservedMask; } if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL) != 0) { Attributes |= ParameterAttributes.HasFieldMarshal; } if (Position == -1) { Attributes |= ParameterAttributes.Retval; } // Default initialization value if present if (pkg.ParameterDefaultValue.TryGetValue(paramIndex, out (ulong address, object variant)value)) { DefaultValue = value.variant; DefaultValueMetadataAddress = value.address; } }