Пример #1
0
        public static void AnalyzeDeobfuscationParams(UnhollowerOptions options)
        {
            RewriteGlobalContext rewriteContext;

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

            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}");
                }
            }
        }
Пример #2
0
        public static void AnalyzeDeobfuscationParams(UnhollowerOptions options)
        {
            RewriteGlobalContext  rewriteContext;
            IIl2CppMetadataAccess inputAssemblies;

            using (new TimingCookie("Reading assemblies"))
                inputAssemblies = new CecilMetadataAccess(options.Source);

            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}");
                }
            }
        }
Пример #3
0
        public static void Main(UnhollowerOptions options)
        {
            if (string.IsNullOrEmpty(options.SourceDir))
            {
                Console.WriteLine("No input dir specified; use -h for help");
                return;
            }

            if (string.IsNullOrEmpty(options.OutputDir))
            {
                Console.WriteLine("No target dir specified; use -h for help");
                return;
            }
            if (string.IsNullOrEmpty(options.MscorlibPath))
            {
                Console.WriteLine("No mscorlib specified; use -h for help");
                return;
            }

            if (!Directory.Exists(options.OutputDir))
            {
                Directory.CreateDirectory(options.OutputDir);
            }

            RewriteGlobalContext rewriteContext;

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

            using (new TimingCookie("Computing renames"))
                Pass05CreateRenameGroups.DoPass(rewriteContext);
            using (new TimingCookie("Creating typedefs"))
                Pass10CreateTypedefs.DoPass(rewriteContext);
            using (new TimingCookie("Computing struct blittability"))
                Pass11ComputeTypeSpecifics.DoPass(rewriteContext);
            using (new TimingCookie("Filling typedefs"))
                Pass12FillTypedefs.DoPass(rewriteContext);
            using (new TimingCookie("Filling generic constraints"))
                Pass13FillGenericConstraints.DoPass(rewriteContext);
            using (new TimingCookie("Creating members"))
                Pass15GenerateMemberContexts.DoPass(rewriteContext);
            using (new TimingCookie("Scanning method cross-references"))
                Pass16ScanMethodRefs.DoPass(rewriteContext, options);
            using (new TimingCookie("Finalizing method declarations"))
                Pass18FinalizeMethodContexts.DoPass(rewriteContext);
            LogSupport.Info($"{Pass18FinalizeMethodContexts.TotalPotentiallyDeadMethods} total potentially dead methods");
            using (new TimingCookie("Filling method parameters"))
                Pass19CopyMethodParameters.DoPass(rewriteContext);

            using (new TimingCookie("Creating static constructors"))
                Pass20GenerateStaticConstructors.DoPass(rewriteContext);
            using (new TimingCookie("Creating value type fields"))
                Pass21GenerateValueTypeFields.DoPass(rewriteContext);
            using (new TimingCookie("Creating enums"))
                Pass22GenerateEnums.DoPass(rewriteContext);
            using (new TimingCookie("Creating IntPtr constructors"))
                Pass23GeneratePointerConstructors.DoPass(rewriteContext);
            using (new TimingCookie("Creating type getters"))
                Pass24GenerateTypeStaticGetters.DoPass(rewriteContext);
            using (new TimingCookie("Creating non-blittable struct constructors"))
                Pass25GenerateNonBlittableValueTypeDefaultCtors.DoPass(rewriteContext);

            using (new TimingCookie("Creating generic method static constructors"))
                Pass30GenerateGenericMethodStoreConstructors.DoPass(rewriteContext);
            using (new TimingCookie("Creating field accessors"))
                Pass40GenerateFieldAccessors.DoPass(rewriteContext);
            using (new TimingCookie("Filling methods"))
                Pass50GenerateMethods.DoPass(rewriteContext);
            using (new TimingCookie("Generating implicit conversions"))
                Pass60AddImplicitConversions.DoPass(rewriteContext);
            using (new TimingCookie("Creating properties"))
                Pass70GenerateProperties.DoPass(rewriteContext);

            if (options.UnityBaseLibsDir != null)
            {
                using (new TimingCookie("Unstripping types"))
                    Pass79UnstripTypes.DoPass(rewriteContext);
                using (new TimingCookie("Unstripping fields"))
                    Pass80UnstripFields.DoPass(rewriteContext);
                using (new TimingCookie("Unstripping methods"))
                    Pass80UnstripMethods.DoPass(rewriteContext);
                using (new TimingCookie("Unstripping method bodies"))
                    Pass81FillUnstrippedMethodBodies.DoPass(rewriteContext);
            }
            else
            {
                LogSupport.Warning("Not performing unstripping as unity libs are not specified");
            }

            using (new TimingCookie("Generating forwarded types"))
                Pass89GenerateForwarders.DoPass(rewriteContext);

            using (new TimingCookie("Writing xref cache"))
                Pass89GenerateMethodXrefCache.DoPass(rewriteContext, options);

            using (new TimingCookie("Writing assemblies"))
                Pass90WriteToDisk.DoPass(rewriteContext, options);

            using (new TimingCookie("Writing method pointer map"))
                Pass91GenerateMethodPointerMap.DoPass(rewriteContext, options);

            if (!options.NoCopyUnhollowerLibs)
            {
                File.Copy(typeof(IL2CPP).Assembly.Location, Path.Combine(options.OutputDir, typeof(IL2CPP).Assembly.GetName().Name + ".dll"), true);
                File.Copy(typeof(RuntimeLibMarker).Assembly.Location, Path.Combine(options.OutputDir, typeof(RuntimeLibMarker).Assembly.GetName().Name + ".dll"), true);
                File.Copy(typeof(Decoder).Assembly.Location, Path.Combine(options.OutputDir, typeof(Decoder).Assembly.GetName().Name + ".dll"), true);
            }

            LogSupport.Info("Done!");

            rewriteContext.Dispose();
        }
        public static void GenerateDeobfuscationMap(UnhollowerOptions options)
        {
            if (string.IsNullOrEmpty(options.SourceDir))
            {
                Console.WriteLine("No input dir specified; use -h for help");
                return;
            }

            if (string.IsNullOrEmpty(options.OutputDir))
            {
                Console.WriteLine("No target dir specified; use -h for help");
                return;
            }
            if (string.IsNullOrEmpty(options.DeobfuscationNewAssembliesPath))
            {
                Console.WriteLine("No obfuscated assembly path specified; use -h for help");
                return;
            }

            if (!Directory.Exists(options.OutputDir))
            {
                Directory.CreateDirectory(options.OutputDir);
            }

            RewriteGlobalContext  rewriteContext;
            IIl2CppMetadataAccess inputAssemblies;
            IIl2CppMetadataAccess systemAssemblies;

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

            using (new TimingCookie("Reading system assemblies"))
            {
                if (!string.IsNullOrEmpty(options.SystemLibrariesPath))
                {
                    systemAssemblies = new CecilMetadataAccess(Directory.EnumerateFiles(options.SystemLibrariesPath, "*.dll")
                                                               .Where(it => Path.GetFileName(it).StartsWith("System.") || Path.GetFileName(it) == "mscorlib.dll" || Path.GetFileName(it) == "netstandard.dll"));
                }
                else
                {
                    systemAssemblies = new CecilMetadataAccess(new[] { options.MscorlibPath });
                }
            }

            using (new TimingCookie("Creating rewrite assemblies"))
                rewriteContext = new RewriteGlobalContext(options, inputAssemblies, systemAssemblies, NullMetadataAccess.Instance);
            using (new TimingCookie("Computing renames"))
                Pass05CreateRenameGroups.DoPass(rewriteContext);
            using (new TimingCookie("Creating typedefs"))
                Pass10CreateTypedefs.DoPass(rewriteContext);
            using (new TimingCookie("Computing struct blittability"))
                Pass11ComputeTypeSpecifics.DoPass(rewriteContext);
            using (new TimingCookie("Filling typedefs"))
                Pass12FillTypedefs.DoPass(rewriteContext);
            using (new TimingCookie("Filling generic constraints"))
                Pass13FillGenericConstraints.DoPass(rewriteContext);
            using (new TimingCookie("Creating members"))
                Pass15GenerateMemberContexts.DoPass(rewriteContext);


            RewriteGlobalContext  cleanContext;
            IIl2CppMetadataAccess cleanAssemblies;

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

            using (new TimingCookie("Creating clean rewrite assemblies"))
                cleanContext = new RewriteGlobalContext(options, cleanAssemblies, systemAssemblies, NullMetadataAccess.Instance);
            using (new TimingCookie("Computing clean assembly renames"))
                Pass05CreateRenameGroups.DoPass(cleanContext);
            using (new TimingCookie("Creating clean assembly typedefs"))
                Pass10CreateTypedefs.DoPass(cleanContext);


            var usedNames = new Dictionary <TypeDefinition, (string OldName, int Penalty, bool ForceNs)>();

            using var fileOutput = new FileStream(options.OutputDir + Path.DirectorySeparatorChar + "RenameMap.csv.gz", FileMode.Create, FileAccess.Write);
            using var gzipStream = new GZipStream(fileOutput, CompressionLevel.Optimal, true);
            using var writer     = new StreamWriter(gzipStream, Encoding.UTF8, 65536, true);

            void DoEnum(TypeRewriteContext obfuscatedType, TypeRewriteContext cleanType)
            {
                foreach (var originalTypeField in obfuscatedType.OriginalType.Fields)
                {
                    if (!originalTypeField.Name.IsObfuscated(obfuscatedType.AssemblyContext.GlobalContext.Options))
                    {
                        continue;
                    }
                    var matchedField = cleanType.OriginalType.Fields[obfuscatedType.OriginalType.Fields.IndexOf(originalTypeField)];

                    writer.WriteLine(obfuscatedType.NewType.GetNamespacePrefix() + "." + obfuscatedType.NewType.Name + "::" + Pass22GenerateEnums.GetUnmangledName(originalTypeField) + ";" + matchedField.Name + ";0");
                }
            }

            foreach (var assemblyContext in rewriteContext.Assemblies)
            {
                if (options.DeobfuscationGenerationAssemblies.Count > 0 &&
                    !options.DeobfuscationGenerationAssemblies.Contains(assemblyContext.NewAssembly.Name.Name))
                {
                    continue;
                }

                var cleanAssembly = cleanContext.GetAssemblyByName(assemblyContext.OriginalAssembly.Name.Name);

                void DoType(TypeRewriteContext typeContext, TypeRewriteContext?enclosingType)
                {
                    if (!typeContext.OriginalNameWasObfuscated)
                    {
                        return;
                    }

                    var cleanType = FindBestMatchType(typeContext, cleanAssembly, enclosingType);

                    if (cleanType.Item1 == null)
                    {
                        return;
                    }

                    if (!usedNames.TryGetValue(cleanType.Item1.NewType, out var existing) || existing.Item2 < cleanType.Item2)
                    {
                        usedNames[cleanType.Item1.NewType] = (typeContext.NewType.GetNamespacePrefix() + "." + typeContext.NewType.Name, cleanType.Item2, typeContext.OriginalType.Namespace != cleanType.Item1.OriginalType.Namespace);
                    }
                    else
                    {
                        return;
                    }

                    if (typeContext.OriginalType.IsEnum)
                    {
                        DoEnum(typeContext, cleanType.Item1);
                    }

                    foreach (var originalTypeNestedType in typeContext.OriginalType.NestedTypes)
                    {
                        DoType(typeContext.AssemblyContext.GetContextForOriginalType(originalTypeNestedType), cleanType.Item1);
                    }
                }

                foreach (var typeContext in assemblyContext.Types)
                {
                    if (typeContext.NewType.DeclaringType != null)
                    {
                        continue;
                    }

                    DoType(typeContext, null);
                }
            }


            foreach (var keyValuePair in usedNames)
            {
                writer.WriteLine(keyValuePair.Value.Item1 + ";" + (keyValuePair.Value.ForceNs ? keyValuePair.Key.Namespace + "." : "") + keyValuePair.Key.Name + ";" + keyValuePair.Value.Item2);
            }

            LogSupport.Info("Done!");

            rewriteContext.Dispose();
        }
        public static void Main(UnhollowerOptions options)
        {
            if (string.IsNullOrEmpty(options.SourceDir))
            {
                Console.WriteLine("No input dir specified; use -h for help");
                return;
            }

            if (string.IsNullOrEmpty(options.OutputDir))
            {
                Console.WriteLine("No target dir specified; use -h for help");
                return;
            }
            if (string.IsNullOrEmpty(options.MscorlibPath))
            {
                Console.WriteLine("No mscorlib specified; use -h for help");
                return;
            }

            if (!Directory.Exists(options.OutputDir))
            {
                Directory.CreateDirectory(options.OutputDir);
            }

            RewriteGlobalContext rewriteContext;

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

            using (new TimingCookie("Computing renames"))
                Pass05CreateRenameGroups.DoPass(rewriteContext);
            using (new TimingCookie("Creating typedefs"))
                Pass10CreateTypedefs.DoPass(rewriteContext);
            using (new TimingCookie("Computing struct blittability"))
                Pass11ComputeTypeSpecifics.DoPass(rewriteContext);
            using (new TimingCookie("Filling typedefs"))
                Pass12FillTypedefs.DoPass(rewriteContext);
            using (new TimingCookie("Filling generic constraints"))
                Pass13FillGenericConstraints.DoPass(rewriteContext);
            using (new TimingCookie("Creating members"))
                Pass15GenerateMemberContexts.DoPass(rewriteContext);

            using (new TimingCookie("Creating static constructors"))
                Pass20GenerateStaticConstructors.DoPass(rewriteContext);
            using (new TimingCookie("Creating value type fields"))
                Pass21GenerateValueTypeFields.DoPass(rewriteContext);
            using (new TimingCookie("Creating enums"))
                Pass22GenerateEnums.DoPass(rewriteContext);
            using (new TimingCookie("Creating IntPtr constructors"))
                Pass23GeneratePointerConstructors.DoPass(rewriteContext);
            using (new TimingCookie("Creating type getters"))
                Pass24GenerateTypeStaticGetters.DoPass(rewriteContext);
            using (new TimingCookie("Creating non-blittable struct constructors"))
                Pass25GenerateNonBlittableValueTypeDefaultCtors.DoPass(rewriteContext);

            using (new TimingCookie("Creating generic method static constructors"))
                Pass30GenerateGenericMethodStoreConstructors.DoPass(rewriteContext);
            using (new TimingCookie("Creating field accessors"))
                Pass40GenerateFieldAccessors.DoPass(rewriteContext);
            using (new TimingCookie("Filling methods"))
                Pass50GenerateMethods.DoPass(rewriteContext);
            using (new TimingCookie("Generating implicit conversions"))
                Pass60AddImplicitConversions.DoPass(rewriteContext);
            using (new TimingCookie("Creating properties"))
                Pass70GenerateProperties.DoPass(rewriteContext);

            if (options.UnityBaseLibsDir != null)
            {
                using (new TimingCookie("Unstripping types"))
                    Pass79UnstripTypes.DoPass(rewriteContext);
                using (new TimingCookie("Unstripping methods"))
                    Pass80UnstripMethods.DoPass(rewriteContext);
            }
            else
            {
                Console.WriteLine("Not performing unstripping as unity libs are not specified");
            }

            using (new TimingCookie("Writing assemblies"))
                Pass99WriteToDisk.DoPass(rewriteContext, options);

            File.Copy(typeof(IL2CPP).Assembly.Location, Path.Combine(options.OutputDir, typeof(IL2CPP).Assembly.GetName().Name + ".dll"), true);
            File.Copy(typeof(DelegateSupport).Assembly.Location, Path.Combine(options.OutputDir, typeof(DelegateSupport).Assembly.GetName().Name + ".dll"), true);
            File.Copy(typeof(Decoder).Assembly.Location, Path.Combine(options.OutputDir, typeof(Decoder).Assembly.GetName().Name + ".dll"), true);

            Console.WriteLine("Done!");
        }