Example #1
0
        public static void DoPass(RewriteGlobalContext context)
        {
            var typesUnstripped = 0;

            foreach (var unityAssembly in context.UnityAssemblies.Assemblies)
            {
                var processedAssembly = context.TryGetAssemblyByName(unityAssembly.Name.Name);
                if (processedAssembly == null)
                {
                    var newAssembly = new AssemblyRewriteContext(context, unityAssembly,
                                                                 AssemblyDefinition.CreateAssembly(unityAssembly.Name, unityAssembly.MainModule.Name,
                                                                                                   ModuleKind.Dll));
                    context.AddAssemblyContext(unityAssembly.Name.Name, newAssembly);
                    processedAssembly = newAssembly;
                }
                var imports = processedAssembly.Imports;

                foreach (var unityType in unityAssembly.MainModule.Types)
                {
                    ProcessType(processedAssembly, unityType, null, imports, ref typesUnstripped);
                }
            }

            LogSupport.Trace(""); // end the progress message
            LogSupport.Trace($"{typesUnstripped} types restored");
        }
        private static void ProcessType(AssemblyRewriteContext processedAssembly, TypeDefinition unityType,
                                        TypeDefinition?enclosingNewType, AssemblyKnownImports imports, ref int typesUnstripped)
        {
            var processedType = enclosingNewType == null?processedAssembly.TryGetTypeByName(unityType.FullName)?.NewType : enclosingNewType.NestedTypes.SingleOrDefault(it => it.Name == unityType.Name);

            if (unityType.IsEnum)
            {
                if (processedType != null)
                {
                    return;
                }

                typesUnstripped++;
                var clonedType = CloneEnum(unityType, imports);
                if (enclosingNewType == null)
                {
                    processedAssembly.NewAssembly.MainModule.Types.Add(clonedType);
                }
                else
                {
                    enclosingNewType.NestedTypes.Add(clonedType);
                    clonedType.DeclaringType = enclosingNewType;
                }

                processedAssembly.RegisterTypeRewrite(new TypeRewriteContext(processedAssembly, null, clonedType));

                return;
            }

            foreach (var nestedUnityType in unityType.NestedTypes)
            {
                ProcessType(processedAssembly, nestedUnityType, processedType, imports, ref typesUnstripped);
            }
        }
Example #3
0
        public static void DoPass(RewriteGlobalContext context)
        {
            var unityAssemblyFiles = Directory.EnumerateFiles(context.Options.UnityBaseLibsDir, "*.dll");
            var loadedAssemblies   = unityAssemblyFiles.Select(it =>
                                                               AssemblyDefinition.ReadAssembly(it, new ReaderParameters(ReadingMode.Deferred))).ToList();

            var typesUnstripped = 0;

            foreach (var unityAssembly in loadedAssemblies)
            {
                var processedAssembly = context.TryGetAssemblyByName(unityAssembly.Name.Name);
                if (processedAssembly == null)
                {
                    var newAssembly = new AssemblyRewriteContext(context, unityAssembly,
                                                                 AssemblyDefinition.CreateAssembly(unityAssembly.Name, unityAssembly.MainModule.Name,
                                                                                                   ModuleKind.Dll));
                    context.AddAssemblyContext(unityAssembly.Name.Name, newAssembly);
                    processedAssembly = newAssembly;
                }
                var imports = processedAssembly.Imports;

                foreach (var unityType in unityAssembly.MainModule.Types)
                {
                    ProcessType(processedAssembly, unityType, null, imports, ref typesUnstripped);
                }
            }

            LogSupport.Trace(""); // end the progress message
            LogSupport.Trace($"{typesUnstripped} types restored");
        }
Example #4
0
        private static void ProcessType(TypeDefinition type, AssemblyRewriteContext assemblyContext, TypeDefinition?parentType)
        {
            var convertedTypeName = GetConvertedTypeName(assemblyContext.GlobalContext, type, parentType);
            var newType           = new TypeDefinition(convertedTypeName.Namespace ?? type.Namespace.UnSystemify(), convertedTypeName.Name, AdjustAttributes(type.Attributes));

            if (type.IsSealed && type.IsAbstract) // is static
            {
                newType.IsSealed = newType.IsAbstract = true;
            }

            if (parentType == null)
            {
                assemblyContext.NewAssembly.MainModule.Types.Add(newType);
            }
            else
            {
                parentType.NestedTypes.Add(newType);
                newType.DeclaringType = parentType;
            }

            foreach (var typeNestedType in type.NestedTypes)
            {
                ProcessType(typeNestedType, assemblyContext, newType);
            }

            assemblyContext.RegisterTypeRewrite(new TypeRewriteContext(assemblyContext, type, newType));
        }
Example #5
0
        private static string UnmanglePropertyName(AssemblyRewriteContext assemblyContext, PropertyDefinition prop)
        {
            if (!prop.Name.IsObfuscated())
            {
                return(prop.Name);
            }

            return("prop_" + assemblyContext.RewriteTypeRef(prop.PropertyType).Name + "_" + prop.DeclaringType.Properties
                   .Where(it => it.PropertyType.FullName == prop.PropertyType.FullName).ToList().IndexOf(prop));
        }
        private static string UnmanglePropertyName(AssemblyRewriteContext assemblyContext, PropertyDefinition prop)
        {
            if (!prop.Name.IsInvalidInSource())
            {
                return(prop.Name);
            }

            return("prop_" + assemblyContext.RewriteTypeRef(prop.PropertyType).GetUnmangledName() + "_" + prop.DeclaringType.Properties
                   .Where(it => it.PropertyType.UnmangledNamesMatch(prop.PropertyType)).ToList().IndexOf(prop));
        }
Example #7
0
        private static void ProcessType(AssemblyRewriteContext processedAssembly, TypeDefinition unityType,
                                        TypeDefinition?enclosingNewType, AssemblyKnownImports imports, ref int typesUnstripped)
        {
            var processedType = enclosingNewType == null?processedAssembly.TryGetTypeByName(unityType.FullName)?.NewType : enclosingNewType.NestedTypes.SingleOrDefault(it => it.Name == unityType.Name);

            if (unityType.IsEnum)
            {
                if (processedType != null)
                {
                    return;
                }

                typesUnstripped++;
                var clonedType = CloneEnum(unityType, imports);
                if (enclosingNewType == null)
                {
                    processedAssembly.NewAssembly.MainModule.Types.Add(clonedType);
                }
                else
                {
                    enclosingNewType.NestedTypes.Add(clonedType);
                    clonedType.DeclaringType = enclosingNewType;
                }

                processedAssembly.RegisterTypeRewrite(new TypeRewriteContext(processedAssembly, null, clonedType));

                return;
            }

            if (processedType == null && !unityType.IsEnum && !HasNonBlittableFields(unityType) && !unityType.HasGenericParameters) // restore all types even if it would be not entirely correct
            {
                typesUnstripped++;
                var clonedType = CloneStatic(unityType, imports);
                if (enclosingNewType == null)
                {
                    processedAssembly.NewAssembly.MainModule.Types.Add(clonedType);
                }
                else
                {
                    enclosingNewType.NestedTypes.Add(clonedType);
                    clonedType.DeclaringType = enclosingNewType;
                }

                processedAssembly.RegisterTypeRewrite(new TypeRewriteContext(processedAssembly, null, clonedType));
            }

            foreach (var nestedUnityType in unityType.NestedTypes)
            {
                ProcessType(processedAssembly, nestedUnityType, processedType, imports, ref typesUnstripped);
            }
        }
        private static string UnmanglePropertyName(AssemblyRewriteContext assemblyContext, PropertyDefinition prop, TypeReference declaringType, Dictionary <string, int> countsByBaseName)
        {
            if (assemblyContext.GlobalContext.Options.PassthroughNames || !prop.Name.IsObfuscated(assemblyContext.GlobalContext.Options))
            {
                return(prop.Name);
            }

            var baseName = "prop_" + assemblyContext.RewriteTypeRef(prop.PropertyType).GetUnmangledName();

            countsByBaseName.TryGetValue(baseName, out var index);
            countsByBaseName[baseName] = index + 1;

            var unmanglePropertyName = baseName + "_" + index;

            if (assemblyContext.GlobalContext.Options.RenameMap.TryGetValue(declaringType.GetNamespacePrefix() + "::" + unmanglePropertyName, out var newName))
            {
                unmanglePropertyName = newName;
            }

            return(unmanglePropertyName);
        }
        private static void ProcessType(TypeDefinition type, AssemblyRewriteContext assemblyContext, TypeDefinition?parentType)
        {
            var newType = new TypeDefinition(type.Namespace.UnSystemify(), GetConvertedTypeName(type), AdjustAttributes(type.Attributes));

            if (parentType == null)
            {
                assemblyContext.NewAssembly.MainModule.Types.Add(newType);
            }
            else
            {
                parentType.NestedTypes.Add(newType);
                newType.DeclaringType = parentType;
            }

            foreach (var typeNestedType in type.NestedTypes)
            {
                ProcessType(typeNestedType, assemblyContext, newType);
            }

            assemblyContext.RegisterTypeRewrite(new TypeRewriteContext(assemblyContext, type, newType));
        }
        private static void GenerateStaticProxy(AssemblyRewriteContext assemblyContext, TypeRewriteContext typeContext)
        {
            var oldType = typeContext.OriginalType;
            var newType = typeContext.NewType;

            if (oldType.IsEnum)
            {
                return;
            }

            var staticCtorMethod = new MethodDefinition(".cctor",
                                                        MethodAttributes.Static | MethodAttributes.Private | MethodAttributes.SpecialName |
                                                        MethodAttributes.HideBySig | MethodAttributes.RTSpecialName, assemblyContext.Imports.Void);

            newType.Methods.Add(staticCtorMethod);

            var ctorBuilder = staticCtorMethod.Body.GetILProcessor();

            if (newType.IsNested)
            {
                ctorBuilder.Emit(OpCodes.Ldsfld, assemblyContext.GlobalContext.GetNewTypeForOriginal(oldType.DeclaringType).ClassPointerFieldRef);
                ctorBuilder.Emit(OpCodes.Ldstr, oldType.Name);
                ctorBuilder.Emit(OpCodes.Call, assemblyContext.Imports.GetIl2CppNestedClass);
            }
            else
            {
                ctorBuilder.Emit(OpCodes.Ldstr, oldType.Module.Name);
                ctorBuilder.Emit(OpCodes.Ldstr, oldType.Namespace);
                ctorBuilder.Emit(OpCodes.Ldstr, oldType.Name);
                ctorBuilder.Emit(OpCodes.Call, assemblyContext.Imports.GetIl2CppGlobalClass);
            }

            if (oldType.HasGenericParameters)
            {
                var il2CppTypeTypeRewriteContext = assemblyContext.GlobalContext.GetAssemblyByName("mscorlib").GetTypeByName("System.Type");
                var il2CppSystemTypeRef          = newType.Module.ImportReference(il2CppTypeTypeRewriteContext.NewType);

                var il2CppTypeHandleTypeRewriteContext = assemblyContext.GlobalContext.GetAssemblyByName("mscorlib").GetTypeByName("System.RuntimeTypeHandle");
                var il2CppSystemTypeHandleRef          = newType.Module.ImportReference(il2CppTypeHandleTypeRewriteContext.NewType);

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

                ctorBuilder.EmitLdcI4(oldType.GenericParameters.Count);

                ctorBuilder.Emit(OpCodes.Newarr, il2CppSystemTypeRef);

                for (var i = 0; i < oldType.GenericParameters.Count; i++)
                {
                    ctorBuilder.Emit(OpCodes.Dup);
                    ctorBuilder.EmitLdcI4(i);

                    var param    = oldType.GenericParameters[i];
                    var storeRef = new GenericInstanceType(assemblyContext.Imports.Il2CppClassPointerStore)
                    {
                        GenericArguments = { param }
                    };
                    var fieldRef = new FieldReference(nameof(Il2CppClassPointerStore <object> .NativeClassPtr), assemblyContext.Imports.IntPtr, storeRef);
                    ctorBuilder.Emit(OpCodes.Ldsfld, fieldRef);

                    ctorBuilder.Emit(OpCodes.Call, assemblyContext.Imports.GetIl2CppTypeFromClass);

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

                var il2CppTypeArray = new GenericInstanceType(assemblyContext.Imports.Il2CppReferenceArray)
                {
                    GenericArguments = { il2CppSystemTypeRef }
                };
                ctorBuilder.Emit(OpCodes.Newobj, new MethodReference(".ctor", assemblyContext.Imports.Void, il2CppTypeArray)
                {
                    HasThis = true, Parameters = { new ParameterDefinition(new ArrayType(assemblyContext.Imports.Il2CppReferenceArray.GenericParameters[0])) }
                });
                ctorBuilder.Emit(OpCodes.Call, new MethodReference(nameof(Type.MakeGenericType), il2CppSystemTypeRef, il2CppSystemTypeRef)
                {
                    HasThis = true, Parameters = { new ParameterDefinition(il2CppTypeArray) }
                });

                ctorBuilder.Emit(OpCodes.Call, new MethodReference(typeof(Type).GetProperty(nameof(Type.TypeHandle)) !.GetMethod !.Name, il2CppSystemTypeHandleRef, il2CppSystemTypeRef)
                {
                    HasThis = true
                });
        private static (TypeRewriteContext?, int) FindBestMatchType(TypeRewriteContext obfType, AssemblyRewriteContext cleanAssembly, TypeRewriteContext?enclosingCleanType)
        {
            var inheritanceDepthOfOriginal = 0;
            var currentBase = obfType.OriginalType.BaseType;

            while (true)
            {
                if (currentBase == null)
                {
                    break;
                }
                var currentBaseContext = obfType.AssemblyContext.GlobalContext.TryGetNewTypeForOriginal(currentBase.Resolve());
                if (currentBaseContext == null || !currentBaseContext.OriginalNameWasObfuscated)
                {
                    break;
                }

                inheritanceDepthOfOriginal++;
                currentBase = currentBaseContext.OriginalType.BaseType;
            }

            var bestPenalty = int.MinValue;
            TypeRewriteContext?bestMatch = null;

            var source = enclosingCleanType?.OriginalType.NestedTypes.Select(it => cleanAssembly.GlobalContext.GetNewTypeForOriginal(it)) ??
                         cleanAssembly.Types.Where(it => it.NewType.DeclaringType == null);

            foreach (var candidateCleanType in source)
            {
                if (obfType.OriginalType.HasMethods != candidateCleanType.OriginalType.HasMethods)
                {
                    continue;
                }

                if (obfType.OriginalType.HasFields != candidateCleanType.OriginalType.HasFields)
                {
                    continue;
                }

                if (obfType.OriginalType.IsEnum)
                {
                    if (obfType.OriginalType.Fields.Count != candidateCleanType.OriginalType.Fields.Count)
                    {
                        continue;
                    }
                }

                int currentPenalty = 0;

                var tryBase         = candidateCleanType.OriginalType.BaseType;
                var actualBaseDepth = 0;
                while (tryBase != null)
                {
                    if (tryBase?.Name == currentBase?.Name && tryBase?.Namespace == currentBase?.Namespace)
                    {
                        break;
                    }

                    tryBase = tryBase?.Resolve().BaseType;
                    actualBaseDepth++;
                }

                if (tryBase == null && currentBase != null)
                {
                    continue;
                }

                var baseDepthDifference = Math.Abs(actualBaseDepth - inheritanceDepthOfOriginal);
                if (baseDepthDifference > 1)
                {
                    continue;                         // heuristic optimization
                }
                currentPenalty -= baseDepthDifference * 50;

                currentPenalty -= Math.Abs(candidateCleanType.OriginalType.Fields.Count - obfType.OriginalType.Fields.Count) * 5;

                currentPenalty -= Math.Abs(obfType.OriginalType.NestedTypes.Count - candidateCleanType.OriginalType.NestedTypes.Count) * 10;

                currentPenalty -= Math.Abs(obfType.OriginalType.Properties.Count - candidateCleanType.OriginalType.Properties.Count) * 5;

                currentPenalty -= Math.Abs(obfType.OriginalType.Interfaces.Count - candidateCleanType.OriginalType.Interfaces.Count) * 35;

                var options = obfType.AssemblyContext.GlobalContext.Options;

                foreach (var obfuscatedField in obfType.OriginalType.Fields)
                {
                    if (obfuscatedField.Name.IsObfuscated(options))
                    {
                        var bestFieldScore = candidateCleanType.OriginalType.Fields.Max(it => TypeMatchWeight(obfuscatedField.FieldType, it.FieldType, options));
                        currentPenalty += bestFieldScore * (bestFieldScore < 0 ? 10 : 2);
                        continue;
                    }

                    if (candidateCleanType.OriginalType.Fields.Any(it => it.Name == obfuscatedField.Name))
                    {
                        currentPenalty += 10;
                    }
                }

                foreach (var obfuscatedMethod in obfType.OriginalType.Methods)
                {
                    if (obfuscatedMethod.Name.Contains(".ctor"))
                    {
                        continue;
                    }

                    if (obfuscatedMethod.Name.IsObfuscated(options))
                    {
                        var bestMethodScore = candidateCleanType.OriginalType.Methods.Max(it => MethodSignatureMatchWeight(obfuscatedMethod, it, options));
                        currentPenalty += bestMethodScore * (bestMethodScore < 0 ? 10 : 1);

                        continue;
                    }

                    if (candidateCleanType.OriginalType.Methods.Any(it => it.Name == obfuscatedMethod.Name))
                    {
                        currentPenalty += obfuscatedMethod.Name.Length / 10 * 5 + 1;
                    }
                }

                if (currentPenalty == bestPenalty)
                {
                    bestMatch = null;
                }
                else if (currentPenalty > bestPenalty)
                {
                    bestPenalty = currentPenalty;
                    bestMatch   = candidateCleanType;
                }
            }

            // if (bestPenalty < -100)
            // bestMatch = null;

            return(bestMatch, bestPenalty);
        }