public static void DoPass(RewriteGlobalContext context)
        {
            var assemblyContext   = context.GetAssemblyByName("mscorlib");
            var typeContext       = assemblyContext.GetTypeByName("System.String");
            var objectTypeContext = assemblyContext.GetTypeByName("System.Object");

            var methodFromMonoString = new MethodDefinition("op_Implicit", MethodAttributes.Static | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeContext.NewType);

            methodFromMonoString.Parameters.Add(new ParameterDefinition(assemblyContext.Imports.String));
            typeContext.NewType.Methods.Add(methodFromMonoString);
            var fromBuilder = methodFromMonoString.Body.GetILProcessor();

            var createIl2CppStringNop = fromBuilder.Create(OpCodes.Nop);

            fromBuilder.Emit(OpCodes.Ldarg_0);
            fromBuilder.Emit(OpCodes.Dup);
            fromBuilder.Emit(OpCodes.Brtrue_S, createIl2CppStringNop);
            fromBuilder.Emit(OpCodes.Ret);

            fromBuilder.Append(createIl2CppStringNop);
            fromBuilder.Emit(OpCodes.Call, assemblyContext.Imports.StringToNative);
            fromBuilder.Emit(OpCodes.Newobj,
                             new MethodReference(".ctor", assemblyContext.Imports.Void, typeContext.NewType)
            {
                HasThis = true, Parameters = { new ParameterDefinition(assemblyContext.Imports.IntPtr) }
            });
            fromBuilder.Emit(OpCodes.Ret);

            var methodToObject = new MethodDefinition("op_Implicit", MethodAttributes.Static | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, objectTypeContext.NewType);

            methodToObject.Parameters.Add(new ParameterDefinition(assemblyContext.Imports.String));
            objectTypeContext.NewType.Methods.Add(methodToObject);
            var toObjectBuilder = methodToObject.Body.GetILProcessor();

            toObjectBuilder.Emit(OpCodes.Ldarg_0);
            toObjectBuilder.Emit(OpCodes.Call, methodFromMonoString);
            toObjectBuilder.Emit(OpCodes.Ret);

            var methodToMonoString = new MethodDefinition("op_Implicit", MethodAttributes.Static | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, assemblyContext.Imports.String);

            methodToMonoString.Parameters.Add(new ParameterDefinition(typeContext.NewType));
            typeContext.NewType.Methods.Add(methodToMonoString);
            var toBuilder = methodToMonoString.Body.GetILProcessor();

            var createStringNop = toBuilder.Create(OpCodes.Nop);

            toBuilder.Emit(OpCodes.Ldarg_0);
            toBuilder.Emit(OpCodes.Call, assemblyContext.Imports.Il2CppObjectBaseToPointer);
            toBuilder.Emit(OpCodes.Dup);
            toBuilder.Emit(OpCodes.Brtrue_S, createStringNop);
            toBuilder.Emit(OpCodes.Pop);
            toBuilder.Emit(OpCodes.Ldnull);
            toBuilder.Emit(OpCodes.Ret);

            toBuilder.Append(createStringNop);
            toBuilder.Emit(OpCodes.Call, assemblyContext.Imports.StringFromNative);
            toBuilder.Emit(OpCodes.Ret);

            AddDelegateConversions(context);
        }
Exemplo n.º 2
0
        public static void AnalyzeDeobfuscationParams(UnhollowerOptions options)
        {
            RewriteGlobalContext  rewriteContext;
            IIl2CppMetadataAccess inputAssemblies;

            using (new TimingCookie("Reading assemblies"))
                inputAssemblies = new CecilMetadataAccess(Directory.EnumerateFiles(options.SourceDir, "*.dll"));

            using (new TimingCookie("Creating assembly contexts"))
                rewriteContext = new RewriteGlobalContext(options, inputAssemblies, NullMetadataAccess.Instance, NullMetadataAccess.Instance);

            for (var chars = 1; chars <= 3; chars++)
            {
                for (var uniq = 3; uniq <= 15; uniq++)
                {
                    options.TypeDeobfuscationCharsPerUniquifier = chars;
                    options.TypeDeobfuscationMaxUniquifiers     = uniq;

                    rewriteContext.RenamedTypes.Clear();
                    rewriteContext.RenameGroups.Clear();

                    Pass05CreateRenameGroups.DoPass(rewriteContext);

                    var uniqueTypes    = rewriteContext.RenameGroups.Values.Count(it => it.Count == 1);
                    var nonUniqueTypes = rewriteContext.RenameGroups.Values.Count(it => it.Count > 1);

                    Console.WriteLine($"Chars=\t{chars}\tMaxU=\t{uniq}\tUniq=\t{uniqueTypes}\tNonUniq=\t{nonUniqueTypes}");
                }
            }
        }
 private static string GetConvertedTypeName(RewriteGlobalContext assemblyContextGlobalContext, TypeDefinition type)
 {
     if (type.Name.IsInvalidInSource())
     {
         var newNameBase            = assemblyContextGlobalContext.RenamedTypes[type];
         var genericParametersCount = type.GenericParameters.Count;
         var renameGroup            =
             assemblyContextGlobalContext.RenameGroups[((object)type.DeclaringType ?? type.Namespace, newNameBase, genericParametersCount)];
        public static void DoPass(RewriteGlobalContext context, UnhollowerOptions options)
        {
            var tasks = context.Assemblies.Where(it => !options.AdditionalAssembliesBlacklist.Contains(it.NewAssembly.Name.Name)).Select(assemblyContext => Task.Run(() => {
                assemblyContext.NewAssembly.Write(options.OutputDir + "/" + assemblyContext.NewAssembly.Name.Name + ".dll");
            })).ToArray();

            Task.WaitAll(tasks);
        }
        private static void FindMetadataInitForMethod(RewriteGlobalContext context, long gameAssemblyBase)
        {
            var unityObjectCctor = context.Assemblies
                                   .Single(it => it.OriginalAssembly.Name.Name == "UnityEngine.CoreModule").GetTypeByName("UnityEngine.Object").OriginalType.Methods.Single(it => it.Name == ".cctor");

            MetadataInitForMethodFileOffset =
                (IntPtr)((long)XrefScannerLowLevel.JumpTargets((IntPtr)(gameAssemblyBase + unityObjectCctor.ExtractOffset())).First());
            MetadataInitForMethodRva = (long)MetadataInitForMethodFileOffset - gameAssemblyBase - unityObjectCctor.ExtractOffset() + unityObjectCctor.ExtractRva();
        }
Exemplo n.º 6
0
 public static void DoPass(RewriteGlobalContext context)
 {
     foreach (var assemblyContext in context.Assemblies)
     {
         foreach (var typeContext in assemblyContext.Types)
         {
             ComputeSpecifics(typeContext);
         }
     }
 }
 public static void DoPass(RewriteGlobalContext context)
 {
     foreach (var assemblyContext in context.Assemblies)
     {
         foreach (var type in assemblyContext.OriginalAssembly.MainModule.Types)
         {
             ProcessType(type, assemblyContext, null);
         }
     }
 }
Exemplo n.º 8
0
 public static void DoPass(RewriteGlobalContext context)
 {
     foreach (var assemblyContext in context.Assemblies)
     {
         foreach (var typeContext in assemblyContext.Types)
         {
             typeContext.AddMembers();
         }
     }
 }
 public static void DoPass(RewriteGlobalContext context)
 {
     foreach (var assemblyContext in context.Assemblies)
     {
         foreach (var typeContext in assemblyContext.Types)
         {
             GenerateStaticProxy(assemblyContext, typeContext);
         }
     }
 }
Exemplo n.º 10
0
        private static string NameOrRename(this TypeReference typeRef, RewriteGlobalContext context)
        {
            var resolved = typeRef.Resolve();

            if (resolved != null && context.PreviousRenamedTypes.TryGetValue(resolved, out var rename))
            {
                return((rename.StableHash() % (ulong)Math.Pow(10, context.Options.TypeDeobfuscationCharsPerUniquifier)).ToString());
            }

            return(typeRef.Name);
        }
        public static void DoPass(RewriteGlobalContext context)
        {
            foreach (var assemblyContext in context.Assemblies)
            {
                foreach (var typeContext in assemblyContext.Types)
                {
                    GenerateStaticProxy(assemblyContext, typeContext);
                }
            }

            LogSupport.Trace($"\nTokenless method count: {ourTokenlessMethods}");
        }
        public static void DoPass(RewriteGlobalContext context)
        {
            foreach (var assemblyContext in context.Assemblies)
            {
                foreach (var typeContext in assemblyContext.Types)
                {
                    var type = typeContext.OriginalType;
                    var propertyCountsByName = new Dictionary <string, int>();

                    foreach (var oldProperty in type.Properties)
                    {
                        var unmangledPropertyName = UnmanglePropertyName(assemblyContext, oldProperty, typeContext.NewType, propertyCountsByName);

                        var property = new PropertyDefinition(unmangledPropertyName, oldProperty.Attributes,
                                                              assemblyContext.RewriteTypeRef(oldProperty.PropertyType));
                        foreach (var oldParameter in oldProperty.Parameters)
                        {
                            property.Parameters.Add(new ParameterDefinition(oldParameter.Name, oldParameter.Attributes,
                                                                            assemblyContext.RewriteTypeRef(oldParameter.ParameterType)));
                        }

                        typeContext.NewType.Properties.Add(property);

                        if (oldProperty.GetMethod != null)
                        {
                            property.GetMethod = typeContext.GetMethodByOldMethod(oldProperty.GetMethod).NewMethod;
                        }

                        if (oldProperty.SetMethod != null)
                        {
                            property.SetMethod = typeContext.GetMethodByOldMethod(oldProperty.SetMethod).NewMethod;
                        }
                    }

                    var defaultMemberAttribute = type.CustomAttributes.FirstOrDefault(it =>
                                                                                      it.AttributeType.Name == "AttributeAttribute" && it.Fields.Any(it => it.Name == "Name" && (string)it.Argument.Value == nameof(DefaultMemberAttribute)));
                    if (defaultMemberAttribute != null)
                    {
                        typeContext.NewType.CustomAttributes.Add(new CustomAttribute(
                                                                     new MethodReference(".ctor", assemblyContext.Imports.Void,
                                                                                         assemblyContext.Imports.DefaultMemberAttribute)
                        {
                            HasThis    = true,
                            Parameters = { new ParameterDefinition(assemblyContext.Imports.String) }
                        })
                        {
                            ConstructorArguments = { new CustomAttributeArgument(assemblyContext.Imports.String, "Item") }
                        });
                    }
                }
            }
        }
Exemplo n.º 13
0
        internal static (string?Namespace, string Name) GetConvertedTypeName(RewriteGlobalContext assemblyContextGlobalContext, TypeDefinition type, TypeDefinition?enclosingType)
        {
            if (assemblyContextGlobalContext.Options.PassthroughNames)
            {
                return(null, type.Name);
            }

            if (type.Name.IsObfuscated(assemblyContextGlobalContext.Options))
            {
                var newNameBase            = assemblyContextGlobalContext.RenamedTypes[type];
                var genericParametersCount = type.GenericParameters.Count;
                var renameGroup            =
                    assemblyContextGlobalContext.RenameGroups[((object)type.DeclaringType ?? type.Namespace, newNameBase, genericParametersCount)];
Exemplo n.º 14
0
        static void Main(string[] args)
        {
            if (args.Length != 3)
            {
                Console.WriteLine("Usage: AssemblyUnhollower.exe SourceAssemblyDir TargetAssemblyDir mscorlib");
                return;
            }

            var sourceDir = args[0];
            var targetDir = args[1];

            Console.WriteLine("Reading assemblies");
            var rewriteContext = new RewriteGlobalContext(args[2], Directory.EnumerateFiles(sourceDir, "*.dll"));

            Console.WriteLine("Creating typedefs");
            Pass10CreateTypedefs.DoPass(rewriteContext);
            Console.WriteLine("Filling typedefs");
            Pass11FillTypedefs.DoPass(rewriteContext);
            Console.WriteLine("Filling generic constraints");
            Pass12FillGenericConstraints.DoPass(rewriteContext);
            Console.WriteLine("Creating members");
            Pass15GenerateMemberContexts.DoPass(rewriteContext);

            Console.WriteLine("Creating static constructors");
            Pass20GenerateStaticConstructors.DoPass(rewriteContext);
            Console.WriteLine("Creating value type fields");
            Pass21GenerateValueTypeFields.DoPass(rewriteContext);
            Console.WriteLine("Creating enums");
            Pass22GenerateEnums.DoPass(rewriteContext);
            Console.WriteLine("Creating IntPtr constructors");
            Pass23GeneratePointerConstructors.DoPass(rewriteContext);
            Console.WriteLine("Creating type getters");
            Pass24GenerateTypeStaticGetters.DoPass(rewriteContext);

            Console.WriteLine("Creating generic method static constructors");
            Pass30GenerateGenericMethodStoreConstructors.DoPass(rewriteContext);
            Console.WriteLine("Creating field accessors");
            Pass40GenerateFieldAccessors.DoPass(rewriteContext);
            Console.WriteLine("Filling methods");
            Pass50GenerateMethods.DoPass(rewriteContext);
            Console.WriteLine("Creating properties");
            Pass70GenerateProperties.DoPass(rewriteContext);

            Console.WriteLine("Writing assemblies");
            Pass99WriteToDisk.DoPass(rewriteContext, targetDir);
        }
Exemplo n.º 15
0
        public static void DoPass(RewriteGlobalContext context)
        {
            foreach (var assemblyContext in context.Assemblies)
            {
                var il2CppTypeTypeRewriteContext = assemblyContext.GlobalContext.GetAssemblyByName("mscorlib").GetTypeByName("System.Object");
                var il2CppSystemTypeRef          = assemblyContext.NewAssembly.MainModule.ImportReference(il2CppTypeTypeRewriteContext.NewType);

                foreach (var typeContext in assemblyContext.Types)
                {
                    if (typeContext.ComputedTypeSpecifics != TypeRewriteContext.TypeSpecifics.BlittableStruct || typeContext.OriginalType.IsEnum)
                    {
                        continue;
                    }

                    var newType = typeContext.NewType;
                    newType.Attributes = newType.Attributes & ~(TypeAttributes.LayoutMask) |
                                         TypeAttributes.ExplicitLayout;

                    UtilGenerator.GenerateBoxMethod(newType, typeContext.ClassPointerFieldRef, il2CppSystemTypeRef);

                    foreach (var fieldContext in typeContext.Fields)
                    {
                        var field = fieldContext.OriginalField;
                        if (field.IsStatic)
                        {
                            continue;
                        }

                        var newField = new FieldDefinition(fieldContext.UnmangledName, field.Attributes.ForcePublic(),
                                                           !field.FieldType.IsValueType
                                ? assemblyContext.Imports.IntPtr
                                : assemblyContext.RewriteTypeRef(field.FieldType));

                        newField.Offset = Convert.ToInt32(
                            (string)field.CustomAttributes
                            .Single(it => it.AttributeType.Name == "FieldOffsetAttribute")
                            .Fields.Single().Argument.Value, 16);

                        newType.Fields.Add(newField);
                    }
                }
            }
        }
        public static void DoPass(RewriteGlobalContext context)
        {
            foreach (var assemblyContext in context.Assemblies)
            {
                var il2CppTypeTypeRewriteContext = assemblyContext.GlobalContext
                                                   .GetAssemblyByName("mscorlib").GetTypeByName("System.Type");
                var il2CppSystemTypeRef =
                    assemblyContext.NewAssembly.MainModule.ImportReference(il2CppTypeTypeRewriteContext.NewType);

                foreach (var typeContext in assemblyContext.Types)
                {
                    var typeGetMethod = new MethodDefinition("get_Il2CppType", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, il2CppSystemTypeRef);
                    typeContext.NewType.Methods.Add(typeGetMethod);
                    var typeProperty = new PropertyDefinition("Il2CppType", PropertyAttributes.None, il2CppSystemTypeRef);
                    typeProperty.GetMethod = typeGetMethod;
                    typeContext.NewType.Properties.Add(typeProperty);

                    typeProperty.CustomAttributes.Add(new CustomAttribute(assemblyContext.Imports.ObsoleteAttributeCtor)
                    {
                        ConstructorArguments =
                        {
                            new CustomAttributeArgument(assemblyContext.Imports.String,
                                                        "Use Il2CppType.Of<T>() instead. This will be removed in a future version of unhollower.")
                        }
                    });

                    var bodyBuilder = typeGetMethod.Body.GetILProcessor();

                    bodyBuilder.Emit(OpCodes.Ldsfld, typeContext.ClassPointerFieldRef);
                    bodyBuilder.Emit(OpCodes.Call, assemblyContext.Imports.GetIl2CppTypeFromClass);

                    bodyBuilder.Emit(OpCodes.Call,
                                     new MethodReference("internal_from_handle", il2CppSystemTypeRef,
                                                         il2CppSystemTypeRef)
                    {
                        Parameters = { new ParameterDefinition(assemblyContext.Imports.IntPtr) }
                    });

                    bodyBuilder.Emit(OpCodes.Ret);
                }
            }
        }
 public static void DoPass(RewriteGlobalContext context)
 {
     foreach (var assemblyContext in context.Assemblies)
     {
         foreach (var typeContext in assemblyContext.Types)
         {
             for (var i = 0; i < typeContext.OriginalType.GenericParameters.Count; i++)
             {
                 var originalParameter = typeContext.OriginalType.GenericParameters[i];
                 var newParameter      = typeContext.NewType.GenericParameters[i];
                 foreach (var originalConstraint in originalParameter.Constraints)
                 {
                     newParameter.Constraints.Add(
                         new GenericParameterConstraint(
                             assemblyContext.RewriteTypeRef(originalConstraint.ConstraintType)));
                 }
             }
         }
     }
 }
Exemplo n.º 18
0
        public static void DoPass(RewriteGlobalContext context)
        {
            foreach (var assemblyContext in context.Assemblies)
            {
                foreach (var typeContext in assemblyContext.Types)
                {
                    if (typeContext.ComputedTypeSpecifics !=
                        TypeRewriteContext.TypeSpecifics.NonBlittableStruct)
                    {
                        continue;
                    }

                    var emptyCtor = new MethodDefinition(".ctor",
                                                         MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName |
                                                         MethodAttributes.HideBySig, assemblyContext.Imports.Void);

                    typeContext.NewType.Methods.Add(emptyCtor);

                    var local0 = new VariableDefinition(assemblyContext.Imports.IntPtr);
                    emptyCtor.Body.Variables.Add(local0);

                    var bodyBuilder = emptyCtor.Body.GetILProcessor();
                    bodyBuilder.Emit(OpCodes.Ldsfld, typeContext.ClassPointerFieldRef);
                    bodyBuilder.Emit(OpCodes.Ldc_I4_0);
                    bodyBuilder.Emit(OpCodes.Conv_U);
                    bodyBuilder.Emit(OpCodes.Call, assemblyContext.Imports.ValueSizeGet);
                    bodyBuilder.Emit(OpCodes.Conv_U);
                    bodyBuilder.Emit(OpCodes.Localloc);
                    bodyBuilder.Emit(OpCodes.Stloc_0);
                    bodyBuilder.Emit(OpCodes.Ldarg_0);
                    bodyBuilder.Emit(OpCodes.Ldsfld, typeContext.ClassPointerFieldRef);
                    bodyBuilder.Emit(OpCodes.Ldloc_0);
                    bodyBuilder.Emit(OpCodes.Call, assemblyContext.Imports.ObjectBox);
                    bodyBuilder.Emit(OpCodes.Call, new MethodReference(".ctor", assemblyContext.Imports.Void, typeContext.NewType.BaseType)
                    {
                        HasThis = true, Parameters = { new ParameterDefinition(assemblyContext.Imports.IntPtr) }
                    });
                    bodyBuilder.Emit(OpCodes.Ret);
                }
            }
        }
        public AssemblyKnownImports(ModuleDefinition module, RewriteGlobalContext context)
        {
            Module    = module;
            myContext = context;

            myVoidReference                    = new Lazy <TypeReference>(() => Module.ImportReference(TargetTypeSystemHandler.Void));
            myIntPtrReference                  = new Lazy <TypeReference>(() => Module.ImportReference(TargetTypeSystemHandler.IntPtr));
            myStringReference                  = new Lazy <TypeReference>(() => Module.ImportReference(TargetTypeSystemHandler.String));
            myIntReference                     = new Lazy <TypeReference>(() => Module.ImportReference(TargetTypeSystemHandler.Int));
            myLongReference                    = new Lazy <TypeReference>(() => Module.ImportReference(TargetTypeSystemHandler.Long));
            myTypeReference                    = new Lazy <TypeDefinition>(() => TargetTypeSystemHandler.Type);
            myEnumReference                    = new Lazy <TypeReference>(() => Module.ImportReference(TargetTypeSystemHandler.Enum));
            myDelegateReference                = new Lazy <TypeReference>(() => Module.ImportReference(TargetTypeSystemHandler.Delegate));
            myMulticastDelegateReference       = new Lazy <TypeReference>(() => Module.ImportReference(TargetTypeSystemHandler.MulticastDelegate));
            myValueTypeReference               = new Lazy <TypeReference>(() => Module.ImportReference(TargetTypeSystemHandler.ValueType));
            myObjectReference                  = new Lazy <TypeReference>(() => Module.ImportReference(TargetTypeSystemHandler.Object));
            myIl2CppClassPointerStoreReference = new Lazy <TypeReference>(() => Module.ImportReference(typeof(Il2CppClassPointerStore <>)));

            myIl2CppReferenceArray = new Lazy <TypeReference>(() => Module.ImportReference(typeof(Il2CppReferenceArray <>)));
            myIl2CppStructArray    = new Lazy <TypeReference>(() => Module.ImportReference(typeof(Il2CppStructArray <>)));
            myIl2CppStringArray    = new Lazy <TypeReference>(() => Module.ImportReference(typeof(Il2CppStringArray)));
Exemplo n.º 20
0
        public static void DoPass(RewriteGlobalContext context)
        {
            foreach (var assemblyContext in context.Assemblies)
            {
                foreach (var typeContext in assemblyContext.Types)
                {
                    if (!typeContext.OriginalType.IsEnum)
                    {
                        continue;
                    }

                    var type    = typeContext.OriginalType;
                    var newType = typeContext.NewType;

                    if (type.CustomAttributes.Any(it => it.AttributeType.FullName == "System.FlagsAttribute"))
                    {
                        newType.CustomAttributes.Add(new CustomAttribute(assemblyContext.Imports.FlagsAttributeCtor));
                    }

                    foreach (var fieldDefinition in type.Fields)
                    {
                        var fieldName = fieldDefinition.Name;
                        if (!context.Options.PassthroughNames && fieldName.IsObfuscated(context.Options))
                        {
                            fieldName = GetUnmangledName(fieldDefinition);
                        }

                        if (context.Options.RenameMap.TryGetValue(typeContext.NewType.GetNamespacePrefix() + "::" + fieldName, out var newName))
                        {
                            fieldName = newName;
                        }

                        var newDef = new FieldDefinition(fieldName, fieldDefinition.Attributes | FieldAttributes.HasDefault, assemblyContext.RewriteTypeRef(fieldDefinition.FieldType));
                        newType.Fields.Add(newDef);

                        newDef.Constant = fieldDefinition.Constant;
                    }
                }
            }
        }
Exemplo n.º 21
0
        private static void ProcessType(RewriteGlobalContext context, TypeDefinition originalType, bool allowExtraHeuristics)
        {
            foreach (var nestedType in originalType.NestedTypes)
            {
                ProcessType(context, nestedType, allowExtraHeuristics);
            }

            if (context.RenamedTypes.ContainsKey(originalType))
            {
                return;
            }

            var unobfuscatedName = GetUnobfuscatedNameBase(context, originalType, allowExtraHeuristics);

            if (unobfuscatedName == null)
            {
                return;
            }

            context.RenameGroups.GetOrCreate(((object)originalType.DeclaringType ?? originalType.Namespace, unobfuscatedName, originalType.GenericParameters.Count), _ => new List <TypeDefinition>()).Add(originalType);
            context.RenamedTypes[originalType] = unobfuscatedName;
        }
Exemplo n.º 22
0
        public static void DoPass(RewriteGlobalContext context)
        {
            foreach (var assemblyContext in context.Assemblies)
            {
                var il2CppTypeTypeRewriteContext = assemblyContext.GlobalContext
                                                   .GetAssemblyByName("mscorlib").GetTypeByName("System.Type");
                var il2CppSystemTypeRef =
                    assemblyContext.NewAssembly.MainModule.ImportReference(il2CppTypeTypeRewriteContext.NewType);

                foreach (var typeContext in assemblyContext.Types)
                {
                    var typeGetMethod = new MethodDefinition("get_Il2CppType", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, il2CppSystemTypeRef);

                    if (typeContext.OriginalType.IsEnum)
                    {
                        continue;
                    }

                    typeContext.NewType.Methods.Add(typeGetMethod);
                    var typeProperty = new PropertyDefinition("Il2CppType", PropertyAttributes.None, il2CppSystemTypeRef);
                    typeProperty.GetMethod = typeGetMethod;
                    typeContext.NewType.Properties.Add(typeProperty);

                    var bodyBuilder = typeGetMethod.Body.GetILProcessor();

                    bodyBuilder.Emit(OpCodes.Ldsfld, typeContext.ClassPointerFieldRef);
                    bodyBuilder.Emit(OpCodes.Call, assemblyContext.Imports.GetIl2CppTypeFromClass);

                    bodyBuilder.Emit(OpCodes.Call,
                                     new MethodReference("internal_from_handle", il2CppSystemTypeRef,
                                                         il2CppSystemTypeRef)
                    {
                        Parameters = { new ParameterDefinition(assemblyContext.Imports.IntPtr) }
                    });

                    bodyBuilder.Emit(OpCodes.Ret);
                }
            }
        }
        public static void DoPass(RewriteGlobalContext context)
        {
            foreach (var assemblyContext in context.Assemblies)
            {
                foreach (var typeContext in assemblyContext.Types)
                {
                    foreach (var methodRewriteContext in typeContext.Methods)
                    {
                        var originalMethod = methodRewriteContext.OriginalMethod;
                        var newMethod      = methodRewriteContext.NewMethod;

                        foreach (var originalMethodParameter in originalMethod.Parameters)
                        {
                            var newName = originalMethodParameter.Name.IsObfuscated(context.Options)
                                ? $"param_{originalMethodParameter.Sequence}"
                                : originalMethodParameter.Name;

                            var newParameter = new ParameterDefinition(newName,
                                                                       originalMethodParameter.Attributes & ~ParameterAttributes.HasFieldMarshal,
                                                                       assemblyContext.RewriteTypeRef(originalMethodParameter.ParameterType));

                            if (originalMethodParameter.HasConstant && (originalMethodParameter.Constant == null ||
                                                                        originalMethodParameter.Constant is string ||
                                                                        originalMethodParameter.Constant is bool))
                            {
                                newParameter.Constant = originalMethodParameter.Constant;
                            }
                            else
                            {
                                newParameter.Attributes &= ~ParameterAttributes.HasDefault;
                            }

                            newMethod.Parameters.Add(newParameter);
                        }
                    }
                }
            }
        }
Exemplo n.º 24
0
        public static void DoPass(RewriteGlobalContext context)
        {
            foreach (var assemblyContext in context.Assemblies)
            {
                foreach (var typeContext in assemblyContext.Types)
                {
                    foreach (var originalParameter in typeContext.OriginalType.GenericParameters)
                    {
                        var newParameter = new GenericParameter(originalParameter.Name, typeContext.NewType);
                        typeContext.NewType.GenericParameters.Add(newParameter);
                        newParameter.Attributes = originalParameter.Attributes.StripValueTypeConstraint();
                    }

                    if (typeContext.OriginalType.IsEnum)
                    {
                        typeContext.NewType.BaseType = assemblyContext.Imports.Enum;
                    }
                    else if (typeContext.ComputedTypeSpecifics == TypeRewriteContext.TypeSpecifics.BlittableStruct)
                    {
                        typeContext.NewType.BaseType = assemblyContext.Imports.ValueType;
                    }
                }
            }

            // Second pass is explicitly done after first to account for rewriting of generic base types - value-typeness is important there
            foreach (var assemblyContext in context.Assemblies)
            {
                foreach (var typeContext in assemblyContext.Types)
                {
                    if (!typeContext.OriginalType.IsEnum && typeContext.ComputedTypeSpecifics !=
                        TypeRewriteContext.TypeSpecifics.BlittableStruct)
                    {
                        typeContext.NewType.BaseType = assemblyContext.RewriteTypeRef(typeContext.OriginalType.BaseType);
                    }
                }
            }
        }
Exemplo n.º 25
0
        public static void DoPass(RewriteGlobalContext context, UnhollowerOptions options)
        {
            if (string.IsNullOrEmpty(options.GameAssemblyPath))
            {
                Pass15GenerateMemberContexts.HasObfuscatedMethods = false;
                return;
            }
            if (!Pass15GenerateMemberContexts.HasObfuscatedMethods)
            {
                return;
            }

            var methodToCallersMap = new Dictionary <long, List <long> >();
            var methodToCalleesMap = new Dictionary <long, List <long> >();

            using var mappedFile = MemoryMappedFile.CreateFromFile(options.GameAssemblyPath, FileMode.Open, null, 0, MemoryMappedFileAccess.Read);
            using var accessor   = mappedFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read);

            IntPtr gameAssemblyPtr;

            unsafe
            {
                byte *fileStartPtr = null;
                accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref fileStartPtr);
                gameAssemblyPtr = (IntPtr)fileStartPtr;
            }

            // Scan xrefs
            foreach (var assemblyRewriteContext in context.Assemblies)
            {
                foreach (var typeRewriteContext in assemblyRewriteContext.Types)
                {
                    foreach (var originalTypeMethod in typeRewriteContext.Methods)
                    {
                        var address = originalTypeMethod.FileOffset;
                        if (address == 0)
                        {
                            continue;
                        }

                        foreach (var callTarget in XrefScannerLowLevel.CallAndIndirectTargets(IntPtr.Add(gameAssemblyPtr, (int)address)))
                        {
                            var targetRelative = (long)callTarget - (long)gameAssemblyPtr;
                            methodToCallersMap.GetOrCreate(targetRelative, _ => new List <long>()).Add(address);
                            methodToCalleesMap.GetOrCreate(address, _ => new List <long>()).Add(targetRelative);
                        }
                    }
                }
            }

            MapOfCallers = methodToCallersMap;

            void MarkMethodAlive(long address)
            {
                if (!NonDeadMethods.Add(address))
                {
                    return;
                }
                if (!methodToCalleesMap.TryGetValue(address, out var calleeList))
                {
                    return;
                }

                foreach (var callee in calleeList)
                {
                    MarkMethodAlive(callee);
                }
            }

            // Now decided which of them are possible dead code
            foreach (var assemblyRewriteContext in context.Assemblies)
            {
                foreach (var typeRewriteContext in assemblyRewriteContext.Types)
                {
                    foreach (var methodRewriteContext in typeRewriteContext.Methods)
                    {
                        if (methodRewriteContext.FileOffset == 0)
                        {
                            continue;
                        }

                        var originalMethod = methodRewriteContext.OriginalMethod;
                        if (!originalMethod.Name.IsObfuscated() || originalMethod.IsVirtual)
                        {
                            MarkMethodAlive(methodRewriteContext.FileOffset);
                        }
                    }
                }
            }
        }
Exemplo n.º 26
0
        public static void DoPass(RewriteGlobalContext context)
        {
            foreach (var assemblyContext in context.Assemblies)
            {
                foreach (var typeContext in assemblyContext.Types)
                {
                    foreach (var methodRewriteContext in typeContext.Methods)
                    {
                        var originalMethod = methodRewriteContext.OriginalMethod;
                        var newMethod      = methodRewriteContext.NewMethod;
                        var imports        = assemblyContext.Imports;

                        foreach (var originalMethodParameter in originalMethod.Parameters)
                        {
                            var newParameter = new ParameterDefinition(originalMethodParameter.Name,
                                                                       originalMethodParameter.Attributes & ~ParameterAttributes.HasFieldMarshal,
                                                                       assemblyContext.RewriteTypeRef(originalMethodParameter.ParameterType));

                            if (originalMethodParameter.HasConstant && (originalMethodParameter.Constant == null || originalMethodParameter.Constant is string || originalMethodParameter.Constant is bool))
                            {
                                newParameter.Constant = originalMethodParameter.Constant;
                            }
                            else
                            {
                                newParameter.Attributes &= ~ParameterAttributes.HasDefault;
                            }

                            newMethod.Parameters.Add(newParameter);
                        }

                        var bodyBuilder    = newMethod.Body.GetILProcessor();
                        var exceptionLocal = new VariableDefinition(imports.IntPtr);
                        var argArray       = new VariableDefinition(new PointerType(imports.IntPtr));
                        var resultVar      = new VariableDefinition(imports.IntPtr);
                        var valueTypeLocal = new VariableDefinition(newMethod.ReturnType);
                        newMethod.Body.Variables.Add(exceptionLocal);
                        newMethod.Body.Variables.Add(argArray);
                        newMethod.Body.Variables.Add(resultVar);

                        if (valueTypeLocal.VariableType.FullName != "System.Void")
                        {
                            newMethod.Body.Variables.Add(valueTypeLocal);
                        }

                        if (!originalMethod.DeclaringType.IsValueType)
                        {
                            if (originalMethod.IsConstructor)
                            {
                                bodyBuilder.Emit(OpCodes.Ldarg_0);
                                bodyBuilder.Emit(OpCodes.Ldsfld, typeContext.ClassPointerFieldRef);
                                bodyBuilder.Emit(OpCodes.Call, imports.Il2CppNewObject);
                                bodyBuilder.Emit(OpCodes.Call,
                                                 new MethodReference(".ctor", imports.Void, typeContext.SelfSubstitutedRef)
                                {
                                    Parameters = { new ParameterDefinition(imports.IntPtr) }, HasThis = true
                                });
                            }
                            else if (!originalMethod.IsStatic)
                            {
                                bodyBuilder.Emit(OpCodes.Ldarg_0);
                                bodyBuilder.Emit(OpCodes.Call, imports.Il2CppObjectBaseToPointerNotNull);
                                bodyBuilder.Emit(OpCodes.Pop);
                            }
                        }

                        bodyBuilder.EmitLdcI4(originalMethod.Parameters.Count * IntPtr.Size);
                        bodyBuilder.Emit(OpCodes.Conv_U);
                        bodyBuilder.Emit(OpCodes.Localloc);
                        bodyBuilder.Emit(OpCodes.Stloc, argArray);

                        var argOffset = originalMethod.IsStatic ? 0 : 1;

                        for (var i = 0; i < newMethod.Parameters.Count; i++)
                        {
                            bodyBuilder.Emit(OpCodes.Ldloc, argArray);
                            bodyBuilder.EmitLdcI4(i * IntPtr.Size);
                            bodyBuilder.Emit(OpCodes.Add);

                            var newParam = newMethod.Parameters[i];

                            if (newParam.ParameterType.FullName == "System.String")
                            {
                                bodyBuilder.Emit(OpCodes.Ldarg, argOffset + i);
                                bodyBuilder.Emit(OpCodes.Call, imports.StringToNative);
                            }
                            else if (newParam.ParameterType is GenericParameter)
                            {
                                GenerateGenericParameter(bodyBuilder, newMethod, newParam, imports, argOffset + i);
                            }
                            else if (newParam.ParameterType.IsValueType)
                            {
                                bodyBuilder.Emit(OpCodes.Ldarga, argOffset + i);
                            }
                            else
                            {
                                bodyBuilder.Emit(OpCodes.Ldarg, argOffset + i);
                                bodyBuilder.Emit(OpCodes.Call, imports.Il2CppObjectBaseToPointer);
                            }

                            bodyBuilder.Emit(OpCodes.Stind_I);
                        }

                        if (originalMethod.IsVirtual || originalMethod.IsAbstract)
                        {
                            bodyBuilder.Emit(OpCodes.Ldarg_0);
                            bodyBuilder.Emit(OpCodes.Call, imports.Il2CppObjectBaseToPointer);
                            bodyBuilder.Emit(OpCodes.Ldsfld, methodRewriteContext.NonGenericMethodInfoPointerField);
                            bodyBuilder.Emit(OpCodes.Call, imports.GetVirtualMethod);
                        }
                        else if (methodRewriteContext.GenericInstantiationsStoreSelfSubstRef != null)
                        {
                            bodyBuilder.Emit(OpCodes.Ldsfld, new FieldReference("Pointer", imports.IntPtr, methodRewriteContext.GenericInstantiationsStoreSelfSubstMethodRef));
                        }
                        else
                        {
                            bodyBuilder.Emit(OpCodes.Ldsfld, methodRewriteContext.NonGenericMethodInfoPointerField);
                        }

                        if (originalMethod.IsStatic)
                        {
                            bodyBuilder.Emit(OpCodes.Ldc_I4_0);
                        }
                        else
                        {
                            if (originalMethod.DeclaringType.IsValueType)
                            {
                                bodyBuilder.Emit(OpCodes.Ldarg_0);
                            }
                            else
                            {
                                bodyBuilder.Emit(OpCodes.Ldarg_0);
                                bodyBuilder.Emit(OpCodes.Call, imports.Il2CppObjectBaseToPointer);
                            }
                        }

                        bodyBuilder.Emit(OpCodes.Ldloc, argArray);
                        bodyBuilder.Emit(OpCodes.Ldloca, exceptionLocal);
                        bodyBuilder.Emit(OpCodes.Call, imports.RuntimeInvoke);
                        bodyBuilder.Emit(OpCodes.Stloc, resultVar);

                        bodyBuilder.Emit(OpCodes.Ldloc, exceptionLocal);
                        bodyBuilder.Emit(OpCodes.Call, imports.RaiseExceptionIfNecessary);

                        bodyBuilder.Emit(OpCodes.Ldloc, resultVar);
                        if (originalMethod.ReturnType.FullName == "System.Void")
                        {
                            bodyBuilder.Emit(OpCodes.Pop);
                        }
                        else if (originalMethod.ReturnType.FullName == "System.String")
                        {
                            bodyBuilder.Emit(OpCodes.Call, imports.StringFromNative);
                        }
                        else if (originalMethod.ReturnType.IsValueType)
                        {
                            bodyBuilder.Emit(OpCodes.Call, imports.ObjectUnbox);
                            bodyBuilder.Emit(OpCodes.Ldobj, newMethod.ReturnType);
                        }
                        else if (originalMethod.ReturnType is GenericParameter)
                        {
                            GenerateGenericReturn(bodyBuilder, newMethod, assemblyContext.Imports);
                        }
                        else
                        {
                            var createRealObject = bodyBuilder.Create(OpCodes.Newobj,
                                                                      new MethodReference(".ctor", imports.Void, newMethod.ReturnType)
                            {
                                Parameters = { new ParameterDefinition(imports.IntPtr) }, HasThis = true
                            });

                            bodyBuilder.Emit(OpCodes.Dup);
                            bodyBuilder.Emit(OpCodes.Brtrue_S, createRealObject);
                            bodyBuilder.Emit(OpCodes.Pop);
                            bodyBuilder.Emit(OpCodes.Ldnull);
                            bodyBuilder.Emit(OpCodes.Ret);

                            bodyBuilder.Append(createRealObject);
                        }

                        bodyBuilder.Emit(OpCodes.Ret);
                    }
                }
            }
        }
        internal static TypeReference?ResolveTypeInNewAssembliesRaw(RewriteGlobalContext context, TypeReference unityType, AssemblyKnownImports imports)
        {
            if (unityType is ByReferenceType)
            {
                var resolvedElementType = ResolveTypeInNewAssemblies(context, unityType.GetElementType(), imports);
                return(resolvedElementType == null ? null : new ByReferenceType(resolvedElementType));
            }

            if (unityType is GenericParameter)
            {
                return(null);
            }

            if (unityType is ArrayType arrayType)
            {
                if (arrayType.Rank != 1)
                {
                    return(null);
                }
                var resolvedElementType = ResolveTypeInNewAssemblies(context, unityType.GetElementType(), imports);
                if (resolvedElementType == null)
                {
                    return(null);
                }
                if (resolvedElementType.FullName == "System.String")
                {
                    return(imports.Il2CppStringArray);
                }
                var genericBase = resolvedElementType.IsValueType
                    ? imports.Il2CppStructArray
                    : imports.Il2CppReferenceArray;
                return(new GenericInstanceType(genericBase)
                {
                    GenericArguments = { resolvedElementType }
                });
            }

            if (unityType.DeclaringType != null)
            {
                var enclosingResolvedType = ResolveTypeInNewAssembliesRaw(context, unityType.DeclaringType, imports);
                if (enclosingResolvedType == null)
                {
                    return(null);
                }
                var resolvedNestedType = enclosingResolvedType.Resolve().NestedTypes.FirstOrDefault(it => it.Name == unityType.Name);
                if (resolvedNestedType == null)
                {
                    return(null);
                }
                return(resolvedNestedType);
            }

            if (unityType is PointerType)
            {
                var resolvedElementType = ResolveTypeInNewAssemblies(context, unityType.GetElementType(), imports);
                return(resolvedElementType == null ? null : new PointerType(resolvedElementType));
            }

            if (unityType is GenericInstanceType genericInstance)
            {
                var baseRef = ResolveTypeInNewAssemblies(context, genericInstance.ElementType, imports);
                if (baseRef == null)
                {
                    return(null);
                }
                var newInstance = new GenericInstanceType(baseRef);
                foreach (var unityGenericArgument in genericInstance.GenericArguments)
                {
                    var resolvedArgument = ResolveTypeInNewAssemblies(context, unityGenericArgument, imports);
                    if (resolvedArgument == null)
                    {
                        return(null);
                    }
                    newInstance.GenericArguments.Add(resolvedArgument);
                }

                return(newInstance);
            }

            var targetAssemblyName = unityType.Scope.Name;

            if (targetAssemblyName.EndsWith(".dll"))
            {
                targetAssemblyName = targetAssemblyName.Substring(0, targetAssemblyName.Length - 4);
            }
            if ((targetAssemblyName == "mscorlib" || targetAssemblyName == "netstandard") && (unityType.IsValueType || unityType.FullName == "System.String" || unityType.FullName == "System.Void") && unityType.FullName != "System.RuntimeTypeHandle")
            {
                return(TargetTypeSystemHandler.Type.Module.GetType(unityType.FullName));
            }

            if (targetAssemblyName == "UnityEngine")
            {
                foreach (var assemblyRewriteContext in context.Assemblies)
                {
                    if (!assemblyRewriteContext.NewAssembly.Name.Name.StartsWith("UnityEngine"))
                    {
                        continue;
                    }

                    var newTypeInAnyUnityAssembly =
                        assemblyRewriteContext.TryGetTypeByName(unityType.FullName)?.NewType;
                    if (newTypeInAnyUnityAssembly != null)
                    {
                        return(newTypeInAnyUnityAssembly);
                    }
                }
            }

            var targetAssembly = context.TryGetAssemblyByName(targetAssemblyName);
            var newType        = targetAssembly?.TryGetTypeByName(unityType.FullName)?.NewType;

            return(newType);
        }
        public static void DoPass(RewriteGlobalContext context)
        {
            int methodsUnstripped = 0;
            int methodsIgnored    = 0;

            foreach (var unityAssembly in context.UnityAssemblies.Assemblies)
            {
                var processedAssembly = context.TryGetAssemblyByName(unityAssembly.Name.Name);
                if (processedAssembly == null)
                {
                    continue;
                }
                var imports = processedAssembly.Imports;

                foreach (var unityType in unityAssembly.MainModule.Types)
                {
                    var processedType = processedAssembly.TryGetTypeByName(unityType.FullName);
                    if (processedType == null)
                    {
                        continue;
                    }

                    foreach (var unityMethod in unityType.Methods)
                    {
                        if (unityMethod.Name == ".cctor" || unityMethod.Name == ".ctor")
                        {
                            continue;
                        }
                        if (unityMethod.IsAbstract)
                        {
                            continue;
                        }

                        var processedMethod = processedType.TryGetMethodByUnityAssemblyMethod(unityMethod);
                        if (processedMethod != null)
                        {
                            continue;
                        }

                        var returnType = ResolveTypeInNewAssemblies(context, unityMethod.ReturnType, imports);
                        if (returnType == null)
                        {
                            LogSupport.Trace($"Method {unityMethod} has unsupported return type {unityMethod.ReturnType}");
                            methodsIgnored++;
                            continue;
                        }

                        var newMethod       = new MethodDefinition(unityMethod.Name, unityMethod.Attributes & ~MethodAttributes.MemberAccessMask | MethodAttributes.Public, returnType);
                        var hadBadParameter = false;
                        foreach (var unityMethodParameter in unityMethod.Parameters)
                        {
                            var convertedType = ResolveTypeInNewAssemblies(context, unityMethodParameter.ParameterType, imports);
                            if (convertedType == null)
                            {
                                hadBadParameter = true;
                                LogSupport.Trace($"Method {unityMethod} has unsupported parameter type {unityMethodParameter.ParameterType}");
                                break;
                            }

                            newMethod.Parameters.Add(new ParameterDefinition(unityMethodParameter.Name, unityMethodParameter.Attributes, convertedType));
                        }

                        if (hadBadParameter)
                        {
                            methodsIgnored++;
                            continue;
                        }

                        foreach (var unityMethodGenericParameter in unityMethod.GenericParameters)
                        {
                            var newParameter = new GenericParameter(unityMethodGenericParameter.Name, newMethod);
                            newParameter.Attributes = unityMethodGenericParameter.Attributes;
                            foreach (var genericParameterConstraint in unityMethodGenericParameter.Constraints)
                            {
                                if (genericParameterConstraint.ConstraintType.FullName == "System.ValueType")
                                {
                                    continue;
                                }
                                if (genericParameterConstraint.ConstraintType.Resolve().IsInterface)
                                {
                                    continue;
                                }

                                var newType = ResolveTypeInNewAssemblies(context, genericParameterConstraint.ConstraintType, imports);
                                if (newType != null)
                                {
                                    newParameter.Constraints.Add(new GenericParameterConstraint(newType));
                                }
                            }

                            newMethod.GenericParameters.Add(newParameter);
                        }

                        if ((unityMethod.ImplAttributes & MethodImplAttributes.InternalCall) != 0)
                        {
                            var delegateType = UnstripGenerator.CreateDelegateTypeForICallMethod(unityMethod, newMethod, imports);
                            processedType.NewType.NestedTypes.Add(delegateType);
                            delegateType.DeclaringType = processedType.NewType;

                            processedType.NewType.Methods.Add(newMethod);

                            var delegateField = UnstripGenerator.GenerateStaticCtorSuffix(processedType.NewType, delegateType, unityMethod, imports);
                            UnstripGenerator.GenerateInvokerMethodBody(newMethod, delegateField, delegateType, processedType, imports);
                        }
                        else
                        {
                            Pass81FillUnstrippedMethodBodies.PushMethod(unityMethod, newMethod, processedType, imports);
                            processedType.NewType.Methods.Add(newMethod);
                        }

                        if (unityMethod.IsGetter)
                        {
                            GetOrCreateProperty(unityMethod, newMethod).GetMethod = newMethod;
                        }
                        else if (unityMethod.IsSetter)
                        {
                            GetOrCreateProperty(unityMethod, newMethod).SetMethod = newMethod;
                        }

                        var paramsMethod = context.CreateParamsMethod(unityMethod, newMethod, imports, type => ResolveTypeInNewAssemblies(context, type, imports));
                        if (paramsMethod != null)
                        {
                            processedType.NewType.Methods.Add(paramsMethod);
                        }

                        methodsUnstripped++;
                    }
                }
            }

            LogSupport.Info(""); // finish the progress line
            LogSupport.Info($"{methodsUnstripped} methods restored");
            LogSupport.Info($"{methodsIgnored} methods failed to restore");
        }
        private static void AddDelegateConversions(RewriteGlobalContext context)
        {
            foreach (var assemblyContext in context.Assemblies)
            {
                foreach (var typeContext in assemblyContext.Types)
                {
                    if (typeContext.OriginalType.BaseType?.FullName != "System.MulticastDelegate")
                    {
                        continue;
                    }

                    var invokeMethod = typeContext.NewType.Methods.Single(it => it.Name == "Invoke");
                    if (invokeMethod.Parameters.Count > 8)
                    {
                        continue;                                    // mscorlib only contains delegates of up to 8 parameters
                    }
                    // Don't generate implicit conversions for pointers and byrefs, as they can't be specified in generics
                    if (invokeMethod.Parameters.Any(it => it.ParameterType.IsByReference || it.ParameterType.IsPointer))
                    {
                        continue;
                    }

                    var implicitMethod = new MethodDefinition("op_Implicit", MethodAttributes.Static | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeContext.SelfSubstitutedRef);
                    typeContext.NewType.Methods.Add(implicitMethod);

                    var hasReturn     = invokeMethod.ReturnType.FullName != "System.Void";
                    var hasParameters = invokeMethod.Parameters.Count > 0;

                    TypeReference monoDelegateType;
                    if (!hasReturn && !hasParameters)
                    {
                        monoDelegateType =
                            typeContext.NewType.Module.ImportReference(
                                assemblyContext.Imports.Type.Module.GetType("System.Action"));
                    }
                    else if (!hasReturn)
                    {
                        monoDelegateType =
                            typeContext.NewType.Module.ImportReference(
                                assemblyContext.Imports.Type.Module.GetType(
                                    "System.Action`" + invokeMethod.Parameters.Count));
                    }
                    else
                    {
                        monoDelegateType =
                            typeContext.NewType.Module.ImportReference(
                                assemblyContext.Imports.Type.Module.GetType(
                                    "System.Func`" + (invokeMethod.Parameters.Count + 1)));
                    }

                    GenericInstanceType?genericInstanceType = null;
                    if (hasParameters)
                    {
                        genericInstanceType = new GenericInstanceType(monoDelegateType);
                        for (var i = 0; i < invokeMethod.Parameters.Count; i++)
                        {
                            genericInstanceType.GenericArguments.Add(invokeMethod.Parameters[i].ParameterType);
                        }
                    }

                    if (hasReturn)
                    {
                        genericInstanceType ??= new GenericInstanceType(monoDelegateType);
                        genericInstanceType.GenericArguments.Add(invokeMethod.ReturnType);
                    }

                    implicitMethod.Parameters.Add(new ParameterDefinition(genericInstanceType != null
                        ? typeContext.NewType.Module.ImportReference(genericInstanceType)
                        : monoDelegateType));

                    var bodyBuilder = implicitMethod.Body.GetILProcessor();

                    bodyBuilder.Emit(OpCodes.Ldarg_0);
                    var delegateSupportTypeRef = typeContext.NewType.Module.ImportReference(typeof(DelegateSupport));
                    var genericConvertRef      = new MethodReference(nameof(DelegateSupport.ConvertDelegate), assemblyContext.Imports.Void, delegateSupportTypeRef)
                    {
                        HasThis = false, Parameters = { new ParameterDefinition(assemblyContext.Imports.Delegate) }
                    };
                    genericConvertRef.GenericParameters.Add(new GenericParameter(genericConvertRef));
                    genericConvertRef.ReturnType = genericConvertRef.GenericParameters[0];
                    var convertMethodRef = new GenericInstanceMethod(genericConvertRef)
                    {
                        GenericArguments = { typeContext.SelfSubstitutedRef }
                    };
                    bodyBuilder.Emit(OpCodes.Call, typeContext.NewType.Module.ImportReference(convertMethodRef));
                    bodyBuilder.Emit(OpCodes.Ret);

                    // public static T operator+(T lhs, T rhs) => Il2CppSystem.Delegate.Combine(lhs, rhs).Cast<T>();
                    var addMethod = new MethodDefinition("op_Addition", MethodAttributes.Static | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeContext.SelfSubstitutedRef);
                    typeContext.NewType.Methods.Add(addMethod);
                    addMethod.Parameters.Add(new ParameterDefinition(typeContext.SelfSubstitutedRef));
                    addMethod.Parameters.Add(new ParameterDefinition(typeContext.SelfSubstitutedRef));
                    var addBody = addMethod.Body.GetILProcessor();
                    addBody.Emit(OpCodes.Ldarg_0);
                    addBody.Emit(OpCodes.Ldarg_1);
                    addBody.Emit(OpCodes.Call, assemblyContext.Imports.DelegateCombine);
                    addBody.Emit(OpCodes.Call, assemblyContext.Imports.Module.ImportReference(new GenericInstanceMethod(assemblyContext.Imports.Il2CppObjectCast)
                    {
                        GenericArguments = { typeContext.SelfSubstitutedRef }
                    }));
                    addBody.Emit(OpCodes.Ret);

                    // public static T operator-(T lhs, T rhs) => Il2CppSystem.Delegate.Remove(lhs, rhs)?.Cast<T>();
                    var subtractMethod = new MethodDefinition("op_Subtraction", MethodAttributes.Static | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeContext.SelfSubstitutedRef);
                    typeContext.NewType.Methods.Add(subtractMethod);
                    subtractMethod.Parameters.Add(new ParameterDefinition(typeContext.SelfSubstitutedRef));
                    subtractMethod.Parameters.Add(new ParameterDefinition(typeContext.SelfSubstitutedRef));
                    var subtractBody = subtractMethod.Body.GetILProcessor();
                    subtractBody.Emit(OpCodes.Ldarg_0);
                    subtractBody.Emit(OpCodes.Ldarg_1);
                    subtractBody.Emit(OpCodes.Call, assemblyContext.Imports.DelegateRemove);
                    subtractBody.Emit(OpCodes.Dup);
                    var ret = subtractBody.Create(OpCodes.Ret);
                    subtractBody.Emit(OpCodes.Brfalse_S, ret);
                    subtractBody.Emit(OpCodes.Call, assemblyContext.Imports.Module.ImportReference(new GenericInstanceMethod(assemblyContext.Imports.Il2CppObjectCast)
                    {
                        GenericArguments = { typeContext.SelfSubstitutedRef }
                    }));
                    subtractBody.Append(ret);
                }
            }
        }
Exemplo n.º 30
0
        public static void DoPass(RewriteGlobalContext context)
        {
            var pdmNested0Caller  = 0;
            var pdmNestedNZCaller = 0;
            var pdmTop0Caller     = 0;
            var pdmTopNZCaller    = 0;

            foreach (var assemblyContext in context.Assemblies)
            {
                foreach (var typeContext in assemblyContext.Types)
                {
                    foreach (var methodContext in typeContext.Methods)
                    {
                        methodContext.CtorPhase2();

                        int callerCount = 0;
                        if (Pass16ScanMethodRefs.MapOfCallers.TryGetValue(methodContext.Rva, out var callers))
                        {
                            callerCount = callers.Count;
                        }

                        methodContext.NewMethod.CustomAttributes.Add(
                            new CustomAttribute(assemblyContext.Imports.CallerCountAttributeCtor)
                        {
                            ConstructorArguments =
                            { new CustomAttributeArgument(assemblyContext.Imports.Int, callerCount) }
                        });

                        if (!Pass15GenerateMemberContexts.HasObfuscatedMethods)
                        {
                            continue;
                        }
                        if (!methodContext.UnmangledName.Contains("_PDM_"))
                        {
                            continue;
                        }
                        TotalPotentiallyDeadMethods++;

                        var hasZeroCallers = callerCount == 0;
                        if (methodContext.DeclaringType.OriginalType.IsNested)
                        {
                            if (hasZeroCallers)
                            {
                                pdmNested0Caller++;
                            }
                            else
                            {
                                pdmNestedNZCaller++;
                            }
                        }
                        else
                        {
                            if (hasZeroCallers)
                            {
                                pdmTop0Caller++;
                            }
                            else
                            {
                                pdmTopNZCaller++;
                            }
                        }
                    }
                }
            }

            LogSupport.Trace("");
            LogSupport.Trace($"Dead method statistics: 0t={pdmTop0Caller} mt={pdmTopNZCaller} 0n={pdmNested0Caller} mn={pdmNestedNZCaller}");
        }