예제 #1
0
파일: Utils.cs 프로젝트: wowjinxy/Cpp2IL
        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);
        }
예제 #2
0
파일: Utils.cs 프로젝트: wowjinxy/Cpp2IL
        public static TypeReference ImportTypeInto(MemberReference importInto, Il2CppType toImport, PE.PE theDll, Il2CppMetadata metadata)
        {
            var moduleDefinition = importInto.Module;

            switch (toImport.type)
            {
            case Il2CppTypeEnum.IL2CPP_TYPE_OBJECT:
                return(moduleDefinition.ImportReference(typeof(object)));

            case Il2CppTypeEnum.IL2CPP_TYPE_VOID:
                return(moduleDefinition.ImportReference(typeof(void)));

            case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:
                return(moduleDefinition.ImportReference(typeof(bool)));

            case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:
                return(moduleDefinition.ImportReference(typeof(char)));

            case Il2CppTypeEnum.IL2CPP_TYPE_I1:
                return(moduleDefinition.ImportReference(typeof(sbyte)));

            case Il2CppTypeEnum.IL2CPP_TYPE_U1:
                return(moduleDefinition.ImportReference(typeof(byte)));

            case Il2CppTypeEnum.IL2CPP_TYPE_I2:
                return(moduleDefinition.ImportReference(typeof(short)));

            case Il2CppTypeEnum.IL2CPP_TYPE_U2:
                return(moduleDefinition.ImportReference(typeof(ushort)));

            case Il2CppTypeEnum.IL2CPP_TYPE_I4:
                return(moduleDefinition.ImportReference(typeof(int)));

            case Il2CppTypeEnum.IL2CPP_TYPE_U4:
                return(moduleDefinition.ImportReference(typeof(uint)));

            case Il2CppTypeEnum.IL2CPP_TYPE_I:
                return(moduleDefinition.ImportReference(typeof(IntPtr)));

            case Il2CppTypeEnum.IL2CPP_TYPE_U:
                return(moduleDefinition.ImportReference(typeof(UIntPtr)));

            case Il2CppTypeEnum.IL2CPP_TYPE_I8:
                return(moduleDefinition.ImportReference(typeof(long)));

            case Il2CppTypeEnum.IL2CPP_TYPE_U8:
                return(moduleDefinition.ImportReference(typeof(ulong)));

            case Il2CppTypeEnum.IL2CPP_TYPE_R4:
                return(moduleDefinition.ImportReference(typeof(float)));

            case Il2CppTypeEnum.IL2CPP_TYPE_R8:
                return(moduleDefinition.ImportReference(typeof(double)));

            case Il2CppTypeEnum.IL2CPP_TYPE_STRING:
                return(moduleDefinition.ImportReference(typeof(string)));

            case Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF:
                return(moduleDefinition.ImportReference(typeof(TypedReference)));

            case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:
            case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:
            {
                var typeDefinition = SharedState.TypeDefsByIndex[toImport.data.classIndex];
                return(moduleDefinition.ImportReference(typeDefinition));
            }

            case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
            {
                var arrayType = theDll.ReadClassAtVirtualAddress <Il2CppArrayType>(toImport.data.array);
                var oriType   = theDll.GetIl2CppType(arrayType.etype);
                return(new ArrayType(ImportTypeInto(importInto, oriType, theDll, metadata), arrayType.rank));
            }

            case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:
            {
                var genericClass =
                    theDll.ReadClassAtVirtualAddress <Il2CppGenericClass>(toImport.data.generic_class);
                var typeDefinition      = SharedState.TypeDefsByIndex[genericClass.typeDefinitionIndex];
                var genericInstanceType = new GenericInstanceType(moduleDefinition.ImportReference(typeDefinition));
                var genericInst         =
                    theDll.ReadClassAtVirtualAddress <Il2CppGenericInst>(genericClass.context.class_inst);
                var pointers = theDll.GetPointers(genericInst.type_argv, (long)genericInst.type_argc);
                foreach (var pointer in pointers)
                {
                    var oriType = theDll.GetIl2CppType(pointer);
                    genericInstanceType.GenericArguments.Add(ImportTypeInto(importInto, oriType, theDll,
                                                                            metadata));
                }

                return(genericInstanceType);
            }

            case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:
            {
                var oriType = theDll.GetIl2CppType(toImport.data.type);
                return(new ArrayType(ImportTypeInto(importInto, oriType, theDll, metadata)));
            }

            case Il2CppTypeEnum.IL2CPP_TYPE_VAR:
            {
                if (SharedState.GenericParamsByIndex.TryGetValue(toImport.data.genericParameterIndex,
                                                                 out var genericParameter))
                {
                    return(genericParameter);
                }

                var param       = metadata.genericParameters[toImport.data.genericParameterIndex];
                var genericName = metadata.GetStringFromIndex(param.nameIndex);
                if (importInto is MethodDefinition methodDefinition)
                {
                    genericParameter = new GenericParameter(genericName, methodDefinition.DeclaringType);
                    methodDefinition.DeclaringType.GenericParameters.Add(genericParameter);
                    SharedState.GenericParamsByIndex.Add(toImport.data.genericParameterIndex, genericParameter);
                    return(genericParameter);
                }

                var typeDefinition = (TypeDefinition)importInto;
                genericParameter = new GenericParameter(genericName, typeDefinition);
                typeDefinition.GenericParameters.Add(genericParameter);
                SharedState.GenericParamsByIndex.Add(toImport.data.genericParameterIndex, genericParameter);
                return(genericParameter);
            }

            case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:
            {
                if (SharedState.GenericParamsByIndex.TryGetValue(toImport.data.genericParameterIndex,
                                                                 out var genericParameter))
                {
                    return(genericParameter);
                }

                var methodDefinition = (MethodDefinition)importInto;
                var param            = metadata.genericParameters[toImport.data.genericParameterIndex];
                var genericName      = metadata.GetStringFromIndex(param.nameIndex);
                genericParameter = new GenericParameter(genericName, methodDefinition);
                methodDefinition.GenericParameters.Add(genericParameter);
                SharedState.GenericParamsByIndex.Add(toImport.data.genericParameterIndex, genericParameter);
                return(genericParameter);
            }

            case Il2CppTypeEnum.IL2CPP_TYPE_PTR:
            {
                var oriType = theDll.GetIl2CppType(toImport.data.type);
                return(new PointerType(ImportTypeInto(importInto, oriType, theDll, metadata)));
            }

            default:
                return(moduleDefinition.ImportReference(typeof(object)));
            }
        }
예제 #3
0
파일: Utils.cs 프로젝트: wowjinxy/Cpp2IL
        internal static string GetTypeName(Il2CppMetadata metadata, PE.PE cppAssembly, Il2CppType type, bool fullName = false)
        {
            string ret;

            switch (type.type)
            {
            case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:
            case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:
            {
                var typeDef = metadata.typeDefs[type.data.classIndex];
                ret = String.Empty;
                if (fullName)
                {
                    ret = metadata.GetStringFromIndex(typeDef.namespaceIndex);
                    if (ret != String.Empty)
                    {
                        ret += ".";
                    }
                }

                ret += GetTypeName(metadata, cppAssembly, typeDef);
                break;
            }

            case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:
            {
                var genericClass = cppAssembly.ReadClassAtVirtualAddress <Il2CppGenericClass>(type.data.generic_class);
                var typeDef      = metadata.typeDefs[genericClass.typeDefinitionIndex];
                ret = metadata.GetStringFromIndex(typeDef.nameIndex);
                var genericInst = cppAssembly.ReadClassAtVirtualAddress <Il2CppGenericInst>(genericClass.context.class_inst);
                ret  = ret.Replace($"`{genericInst.type_argc}", "");
                ret += GetGenericTypeParams(metadata, cppAssembly, genericInst);
                break;
            }

            case Il2CppTypeEnum.IL2CPP_TYPE_VAR:
            case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:
            {
                var param = metadata.genericParameters[type.data.genericParameterIndex];
                ret = metadata.GetStringFromIndex(param.nameIndex);
                break;
            }

            case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
            {
                var arrayType = cppAssembly.ReadClassAtVirtualAddress <Il2CppArrayType>(type.data.array);
                var oriType   = cppAssembly.GetIl2CppType(arrayType.etype);
                ret = $"{GetTypeName(metadata, cppAssembly, oriType)}[{new string(',', arrayType.rank - 1)}]";
                break;
            }

            case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:
            {
                var oriType = cppAssembly.GetIl2CppType(type.data.type);
                ret = $"{GetTypeName(metadata, cppAssembly, oriType)}[]";
                break;
            }

            case Il2CppTypeEnum.IL2CPP_TYPE_PTR:
            {
                var oriType = cppAssembly.GetIl2CppType(type.data.type);
                ret = $"{GetTypeName(metadata, cppAssembly, oriType)}*";
                break;
            }

            default:
                ret = TypeString[(int)type.type];
                break;
            }

            return(ret);
        }
예제 #4
0
        internal static List <GlobalIdentifier> MapGlobalIdentifiers(Il2CppMetadata metadata, PE.PE cppAssembly)
        {
            //Classes
            var ret = metadata.metadataUsageDic[1]
                      .Select(kvp => new { kvp, type = cppAssembly.types[kvp.Value] })
                      .Select(t => new GlobalIdentifier
            {
                Name           = Utils.GetTypeName(metadata, cppAssembly, t.type, true),
                Offset         = cppAssembly.metadataUsages[t.kvp.Key],
                IdentifierType = GlobalIdentifier.Type.TYPE
            }).ToList();

            //Idx 2 is exactly the same thing
            ret.AddRange(metadata.metadataUsageDic[2]
                         .Select(kvp => new { kvp, type = cppAssembly.types[kvp.Value] })
                         .Select(t => new GlobalIdentifier
            {
                Name           = Utils.GetTypeName(metadata, cppAssembly, t.type, true),
                Offset         = cppAssembly.metadataUsages[t.kvp.Key],
                IdentifierType = GlobalIdentifier.Type.TYPE
            })
                         );

            //Methods is idx 3
            //Don't @ me, i prefer LINQ to foreach loops.
            //But that said this could be optimised to less t-ing
            ret.AddRange(metadata.metadataUsageDic[3]
                         .Select(kvp => new { kvp, method = metadata.methodDefs[kvp.Value] })
                         .Select(t => new { t.kvp, t.method, type = metadata.typeDefs[t.method.declaringType] })
                         .Select(t => new { t.kvp, t.method, typeName = Utils.GetTypeName(metadata, cppAssembly, t.type) })
                         .Select(t => new { t.kvp, methodName = t.typeName + "." + metadata.GetStringFromIndex(t.method.nameIndex) + "()" })
                         .Select(t => new GlobalIdentifier
            {
                IdentifierType = GlobalIdentifier.Type.METHOD,
                Name           = t.methodName,
                Offset         = cppAssembly.metadataUsages[t.kvp.Key]
            })
                         );

            //Fields is idx 4
            ret.AddRange(metadata.metadataUsageDic[4]
                         .Select(kvp => new { kvp, fieldRef = metadata.fieldRefs[kvp.Value] })
                         .Select(t => new { t.kvp, t.fieldRef, type = cppAssembly.types[t.fieldRef.typeIndex] })
                         .Select(t => new { t.type, t.kvp, t.fieldRef, typeDef = metadata.typeDefs[t.type.data.classIndex] })
                         .Select(t => new { t.type, t.kvp, fieldDef = metadata.fieldDefs[t.typeDef.firstFieldIdx + t.fieldRef.fieldIndex] })
                         .Select(t => new { t.kvp, fieldName = Utils.GetTypeName(metadata, cppAssembly, t.type, true) + "." + metadata.GetStringFromIndex(t.fieldDef.nameIndex) })
                         .Select(t => new GlobalIdentifier
            {
                IdentifierType = GlobalIdentifier.Type.FIELD,
                Name           = t.fieldName,
                Offset         = cppAssembly.metadataUsages[t.kvp.Key]
            })
                         );

            //Literals
            ret.AddRange(metadata.metadataUsageDic[5]
                         .Select(kvp => new GlobalIdentifier
            {
                IdentifierType = GlobalIdentifier.Type.LITERAL,
                Offset         = cppAssembly.metadataUsages[kvp.Key],
                Name           = $"{metadata.GetStringLiteralFromIndex(kvp.Value)}"
            })
                         );

            foreach (var kvp in metadata.metadataUsageDic[6]) //kIl2CppMetadataUsageMethodRef
            {
                var methodSpec = cppAssembly.methodSpecs[kvp.Value];
                var methodDef  = metadata.methodDefs[methodSpec.methodDefinitionIndex];
                var typeDef    = metadata.typeDefs[methodDef.declaringType];
                var typeName   = Utils.GetTypeName(metadata, cppAssembly, typeDef);
                if (methodSpec.classIndexIndex != -1)
                {
                    var classInst = cppAssembly.genericInsts[methodSpec.classIndexIndex];
                    typeName += Utils.GetGenericTypeParams(metadata, cppAssembly, classInst);
                }

                var methodName = typeName + "." + metadata.GetStringFromIndex(methodDef.nameIndex) + "()";
                if (methodSpec.methodIndexIndex != -1)
                {
                    var methodInst = cppAssembly.genericInsts[methodSpec.methodIndexIndex];
                    methodName += Utils.GetGenericTypeParams(metadata, cppAssembly, methodInst);
                }

                ret.Add(new GlobalIdentifier
                {
                    Name           = methodName,
                    IdentifierType = GlobalIdentifier.Type.METHOD,
                    Offset         = cppAssembly.metadataUsages[kvp.Key]
                });
            }

            return(ret);
        }
예제 #5
0
        /// <summary>
        /// Creates all the Assemblies defined in the provided metadata, along with (stub) definitions of all the types contained therein, and registers them with the resolver.
        /// </summary>
        /// <param name="metadata">The Il2Cpp metadata to extract assemblies from</param>
        /// <param name="resolver">The Assembly Resolver that assemblies are registered with, used to ensure assemblies can cross reference.</param>
        /// <param name="moduleParams">Configuration for the module creation.</param>
        /// <returns>A list of Mono.Cecil Assemblies, containing empty type definitions for each defined type.</returns>
        internal static List <AssemblyDefinition> CreateAssemblies(Il2CppMetadata metadata, RegistryAssemblyResolver resolver, ModuleParameters moduleParams)
        {
            var assemblies = new List <AssemblyDefinition>();

            foreach (var assemblyDefinition in metadata.assemblyDefinitions)
            {
                //Get the name of the assembly (= the name of the DLL without the file extension)
                var assemblyNameString = metadata.GetStringFromIndex(assemblyDefinition.nameIndex).Replace(".dll", "");

                //Build a Mono.Cecil assembly name from this name
                var asmName = new AssemblyNameDefinition(assemblyNameString, new Version("0.0.0.0"));
                Console.Write($"\t\t{assemblyNameString}...");

                //Create an empty assembly and register it
                var assembly = AssemblyDefinition.CreateAssembly(asmName, metadata.GetStringFromIndex(assemblyDefinition.nameIndex), moduleParams);
                resolver.Register(assembly);
                assemblies.Add(assembly);

                //Ensure it really _is_ empty
                var mainModule = assembly.MainModule;
                mainModule.Types.Clear();

                //Find the end index of the types belonging to this assembly (as they're all in one huge list in the metadata)
                var end = assemblyDefinition.firstTypeIndex + assemblyDefinition.typeCount;

                for (var defNumber = assemblyDefinition.firstTypeIndex; defNumber < end; defNumber++)
                {
                    //Get the metadata type info, its namespace, and name.
                    var type = metadata.typeDefs[defNumber];
                    var ns   = metadata.GetStringFromIndex(type.namespaceIndex);
                    var name = metadata.GetStringFromIndex(type.nameIndex);

                    TypeDefinition definition;
                    if (type.declaringTypeIndex != -1)
                    {
                        //This is a type declared within another (inner class/type)
                        definition = SharedState.TypeDefsByIndex[defNumber];
                    }
                    else
                    {
                        //This is a new type so ensure it's registered
                        definition = new TypeDefinition(ns, name, (TypeAttributes)type.flags);
                        mainModule.Types.Add(definition);
                        SharedState.TypeDefsByIndex.Add(defNumber, definition);
                    }

                    //Ensure we include all inner types within this type.
                    for (var nestedNumber = 0; nestedNumber < type.nested_type_count; nestedNumber++)
                    {
                        //These are stored in a separate field in the metadata.
                        var nestedIndex = metadata.nestedTypeIndices[type.nestedTypesStart + nestedNumber];
                        var nested      = metadata.typeDefs[nestedIndex];

                        //Create it and register.
                        var nestedDef = new TypeDefinition(metadata.GetStringFromIndex(nested.namespaceIndex),
                                                           metadata.GetStringFromIndex(nested.nameIndex), (TypeAttributes)nested.flags);

                        definition.NestedTypes.Add(nestedDef);
                        SharedState.TypeDefsByIndex.Add(nestedIndex, nestedDef);
                    }
                }

                Console.WriteLine("OK");
            }

            return(assemblies);
        }
예제 #6
0
        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);
        }
예제 #7
0
        /// <summary>
        /// Creates all the Assemblies defined in the provided metadata, along with (stub) definitions of all the types contained therein, and registers them with the resolver.
        /// </summary>
        /// <param name="metadata">The Il2Cpp metadata to extract assemblies from</param>
        /// <param name="resolver">The Assembly Resolver that assemblies are registered with, used to ensure assemblies can cross reference.</param>
        /// <param name="moduleParams">Configuration for the module creation.</param>
        /// <returns>A list of Mono.Cecil Assemblies, containing empty type definitions for each defined type.</returns>
        internal static List <AssemblyDefinition> CreateAssemblies(Il2CppMetadata metadata, RegistryAssemblyResolver resolver, ModuleParameters moduleParams)
        {
            var assemblies = new List <AssemblyDefinition>();

            foreach (var assemblyDefinition in metadata.imageDefinitions)
            {
                //Get the name of the assembly (= the name of the DLL without the file extension)
                var assemblyNameString = metadata.GetStringFromIndex(assemblyDefinition.nameIndex).Replace(".dll", "");

                //Build a Mono.Cecil assembly name from this name
                var asmName = new AssemblyNameDefinition(assemblyNameString, new Version("0.0.0.0"));
                Console.Write($"\t\t{assemblyNameString}...");

                //Create an empty assembly and register it
                var assembly = AssemblyDefinition.CreateAssembly(asmName, metadata.GetStringFromIndex(assemblyDefinition.nameIndex), moduleParams);
                resolver.Register(assembly);
                assemblies.Add(assembly);

                //Ensure it really _is_ empty
                var mainModule = assembly.MainModule;
                mainModule.Types.Clear();

                //Find the end index of the types belonging to this assembly (as they're all in one huge list in the metadata)
                var end = assemblyDefinition.firstTypeIndex + assemblyDefinition.typeCount;

                for (var defNumber = assemblyDefinition.firstTypeIndex; defNumber < end; defNumber++)
                {
                    //Get the metadata type info, its namespace, and name.
                    var type = metadata.typeDefs[defNumber];
                    var ns   = metadata.GetStringFromIndex(type.namespaceIndex);
                    var name = metadata.GetStringFromIndex(type.nameIndex);

                    TypeDefinition?definition = null;
                    if (type.declaringTypeIndex != -1)
                    {
                        //This is a type declared within another (inner class/type)

                        //Have we already declared this type due to handling its parent?
                        SharedState.TypeDefsByIndex.TryGetValue(defNumber, out definition);
                    }

                    if (definition == null)
                    {
                        //This is a new type (including nested type with parent not defined yet) so ensure it's registered
                        definition = new TypeDefinition(ns, name, (TypeAttributes)type.flags);
                        if (ns == "System" && name == "String")
                        {
                            typeof(TypeReference).GetField("etype", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(definition, (byte)0x0e);  //mark as string
                        }

                        mainModule.Types.Add(definition);
                        SharedState.AllTypeDefinitions.Add(definition);
                        SharedState.TypeDefsByIndex.Add(defNumber, definition);
                    }

                    //Ensure we include all inner types within this type.
                    for (var nestedNumber = 0; nestedNumber < type.nested_type_count; nestedNumber++)
                    {
                        //These are stored in a separate field in the metadata.
                        var nestedIndex = metadata.nestedTypeIndices[type.nestedTypesStart + nestedNumber];
                        var nested      = metadata.typeDefs[nestedIndex];


                        if (SharedState.TypeDefsByIndex.TryGetValue(nestedIndex, out var alreadyMadeNestedType))
                        {
                            //Type has already been defined (can be out-of-order in v27+) so we just add it.
                            definition.NestedTypes.Add(alreadyMadeNestedType);
                        }
                        else
                        {
                            //Create it and register.
                            var nestedDef = new TypeDefinition(metadata.GetStringFromIndex(nested.namespaceIndex),
                                                               metadata.GetStringFromIndex(nested.nameIndex), (TypeAttributes)nested.flags);

                            definition.NestedTypes.Add(nestedDef);
                            SharedState.AllTypeDefinitions.Add(nestedDef);
                            SharedState.TypeDefsByIndex.Add(nestedIndex, nestedDef);
                        }
                    }
                }

                Console.WriteLine("OK");
            }

            return(assemblies);
        }