public static void DoPass(RewriteGlobalContext context, UnhollowerOptions options)
        {
            var registerMethod = typeof(DefaultAssemblyResolver).GetMethod("RegisterAssembly", BindingFlags.Instance | BindingFlags.NonPublic);

            foreach (AssemblyRewriteContext asmContext in context.Assemblies)
            {
                var module = asmContext.NewAssembly.MainModule;
                if (module.AssemblyResolver is DefaultAssemblyResolver resolver)
                {
                    foreach (AssemblyNameReference reference in module.AssemblyReferences)
                    {
                        var match = context.Assemblies.FirstOrDefault(f => f.NewAssembly.FullName == reference.FullName);
                        if (match != null)
                        {
                            registerMethod !.Invoke(resolver, new object[] { match.NewAssembly });
                        }
                    }
                }
            }

            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);
        }
        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);
        }
Exemplo n.º 3
0
            public void GenerateAssembliesInternal(AppDomainListener listener)
            {
                listener.DoPreloaderLog("Generating Il2CppUnhollower assemblies", LogLevel.Message);

                Directory.CreateDirectory(Preloader.IL2CPPUnhollowedPath);

                foreach (var dllFile in Directory.EnumerateFiles(Preloader.IL2CPPUnhollowedPath, "*.dll",
                                                                 SearchOption.TopDirectoryOnly))
                {
                    File.Delete(dllFile);
                }

                var tempDumperDirectory = Path.Combine(Preloader.IL2CPPUnhollowedPath, "temp");

                Directory.CreateDirectory(tempDumperDirectory);

                var dumperConfig = new Config
                {
                    GenerateScript   = false,
                    GenerateDummyDll = true
                };

                listener.DoPreloaderLog("Generating Il2CppDumper intermediate assemblies", LogLevel.Info);

                Il2CppDumper.Il2CppDumper.PerformDump(GameAssemblyPath,
                                                      Path.Combine(Paths.GameRootPath, $"{Paths.ProcessName}_Data",
                                                                   "il2cpp_data", "Metadata", "global-metadata.dat"),
                                                      tempDumperDirectory,
                                                      dumperConfig,
                                                      s => listener.DoDumperLog(s, LogLevel.Debug));


                listener.DoPreloaderLog("Executing Il2CppUnhollower generator", LogLevel.Info);

                LogSupport.InfoHandler    += s => listener.DoUnhollowerLog(s, LogLevel.Info);
                LogSupport.WarningHandler += s => listener.DoUnhollowerLog(s, LogLevel.Warning);
                LogSupport.TraceHandler   += s => listener.DoUnhollowerLog(s, LogLevel.Debug);
                LogSupport.ErrorHandler   += s => listener.DoUnhollowerLog(s, LogLevel.Error);

                var unhollowerOptions = new UnhollowerOptions
                {
                    GameAssemblyPath     = GameAssemblyPath,
                    MscorlibPath         = Path.Combine(Paths.ManagedPath, "mscorlib.dll"),
                    SourceDir            = Path.Combine(tempDumperDirectory, "DummyDll"),
                    OutputDir            = Preloader.IL2CPPUnhollowedPath,
                    UnityBaseLibsDir     = Directory.Exists(UnityBaseLibsDirectory) ? UnityBaseLibsDirectory : null,
                    NoCopyUnhollowerLibs = true
                };

                try
                {
                    Program.Main(unhollowerOptions);
                }
                catch (Exception e)
                {
                    listener.DoUnhollowerLog($"Exception while unhollowing: {e}", LogLevel.Error);
                }
            }
Exemplo n.º 4
0
        public static string UnSystemify(this string str, UnhollowerOptions options)
        {
            foreach (var prefix in options.NamespacesAndAssembliesToPrefix)
            {
                if (str.StartsWith(prefix))
                {
                    return("Il2Cpp" + str);
                }
            }

            return(str);
        }
        public static bool IsObfuscated(this string str, UnhollowerOptions options)
        {
            if (options.ObfuscatedNamesRegex != null)
            {
                return(options.ObfuscatedNamesRegex.IsMatch(str));
            }

            foreach (var it in str)
            {
                if (!char.IsDigit(it) && !(it >= 'a' && it <= 'z' || it >= 'A' && it <= 'Z') && it != '_' && it != '`' && it != '.' && it != '<' && it != '>')
                {
                    return(true);
                }
            }

            return(false);
        }
Exemplo n.º 6
0
    public override void Run(BuildContext context)
    {
        var dumperConfig = new Il2CppDumper.Config
        {
            //GenerateScript = false,
            GenerateDummyDll = true
        };

        Console.WriteLine("Test2");

        context.Information("Generating Il2CppDumper intermediate assemblies");

        var gameAssemblyPath = Path.Combine(context.AmongUsPath, "GameAssembly.dll");

        if (!Directory.Exists(context.TempPath))
        {
            Directory.CreateDirectory(context.TempPath);
        }

        Il2CppDumper.Il2CppDumper.PerformDump(
            gameAssemblyPath,
            Path.Combine(context.AmongUsPath, "Among Us_Data", "il2cpp_data", "Metadata", "global-metadata.dat"),
            context.TempPath, dumperConfig, context.Debug
            );

        context.Information("Executing Il2CppUnhollower generator");

        UnhollowerBaseLib.LogSupport.InfoHandler    += context.Information;
        UnhollowerBaseLib.LogSupport.WarningHandler += context.Warning;
        UnhollowerBaseLib.LogSupport.TraceHandler   += context.Debug;
        UnhollowerBaseLib.LogSupport.ErrorHandler   += context.Error;

        var unhollowerOptions = new UnhollowerOptions
        {
            GameAssemblyPath     = gameAssemblyPath,
            MscorlibPath         = Path.Combine(context.AmongUsPath, "mono", "Managed", "mscorlib.dll"),
            SourceDir            = Path.Combine(context.TempPath, "DummyDll"),
            OutputDir            = Path.Combine(context.AmongUsPath, "BepInEx", "unhollowed"),
            UnityBaseLibsDir     = Path.Combine(context.AmongUsPath, "BepInEx", "unity-libs"),
            NoCopyUnhollowerLibs = true
        };

        AssemblyUnhollower.Program.Main(unhollowerOptions);
    }
Exemplo n.º 7
0
        private string UnmangleFieldNameBase(FieldDefinition field, UnhollowerOptions options)
        {
            if (options.PassthroughNames)
            {
                return(field.Name);
            }

            if (!field.Name.IsObfuscated(options))
            {
                if (!field.Name.IsInvalidInSource())
                {
                    return(field.Name);
                }
                return(field.Name.FilterInvalidInSourceChars());
            }

            var accessModString = MethodAccessTypeLabels[(int)(field.Attributes & FieldAttributes.FieldAccessMask)];
            var staticString    = field.IsStatic ? "_Static" : "";

            return("field_" + accessModString + staticString + "_" + DeclaringType.AssemblyContext.RewriteTypeRef(field.FieldType).GetUnmangledName());
        }
Exemplo n.º 8
0
        private string UnmangleFieldName(FieldDefinition field, UnhollowerOptions options, Dictionary <string, int>?renamedFieldCounts)
        {
            if (options.PassthroughNames)
            {
                return(field.Name);
            }

            if (!field.Name.IsObfuscated(options))
            {
                if (!field.Name.IsInvalidInSource())
                {
                    return(field.Name);
                }
                return(field.Name.FilterInvalidInSourceChars());
            }

            if (renamedFieldCounts == null)
            {
                throw new ArgumentNullException(nameof(renamedFieldCounts));
            }

            var unmangleFieldNameBase = UnmangleFieldNameBase(field, options);

            renamedFieldCounts.TryGetValue(unmangleFieldNameBase, out var count);
            renamedFieldCounts[unmangleFieldNameBase] = count + 1;

            unmangleFieldNameBase += "_" + count;

            if (DeclaringType.AssemblyContext.GlobalContext.Options.RenameMap.TryGetValue(
                    DeclaringType.NewType.GetNamespacePrefix() + "." + DeclaringType.NewType.Name + "::" + unmangleFieldNameBase, out var newName))
            {
                unmangleFieldNameBase = newName;
            }

            return(unmangleFieldNameBase);
        }
Exemplo n.º 9
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.º 10
0
        public static void DoPass(RewriteGlobalContext context, UnhollowerOptions options)
        {
            var data         = new List <(long, int, int)>();
            var assemblyList = new List <string>();

            foreach (var assemblyRewriteContext in context.Assemblies)
            {
                assemblyList.Add(assemblyRewriteContext.NewAssembly.FullName);

                foreach (var typeRewriteContext in assemblyRewriteContext.Types)
                {
                    foreach (var methodRewriteContext in typeRewriteContext.Methods)
                    {
                        var address = methodRewriteContext.Rva;

                        if (address != 0)
                        {
                            data.Add((address, methodRewriteContext.NewMethod.MetadataToken.ToInt32(), assemblyList.Count - 1));
                        }
                    }
                }
            }

            data.Sort((a, b) => a.Item1.CompareTo(b.Item1));

            var header = new MethodAddressToTokenMap.FileHeader
            {
                Magic         = MethodAddressToTokenMap.Magic,
                Version       = MethodAddressToTokenMap.Version,
                NumMethods    = data.Count,
                NumAssemblies = assemblyList.Count
            };

            using var writer = new BinaryWriter(new FileStream(Path.Combine(options.OutputDir, MethodAddressToTokenMap.FileName), FileMode.Create, FileAccess.Write), Encoding.UTF8, false);
            writer.Write(header);

            foreach (var s in assemblyList)
            {
                writer.Write(s);
            }

            header.DataOffset = (int)writer.BaseStream.Position;

            foreach (var valueTuple in data)
            {
                writer.Write(valueTuple.Item1);
            }

            foreach (var valueTuple in data)
            {
                writer.Write(valueTuple.Item2);
                writer.Write(valueTuple.Item3);
            }

            writer.BaseStream.Position = 0;
            writer.Write(header);

            if (options.Verbose)
            {
                using var plainTextWriter = new StreamWriter(Path.Combine(options.OutputDir, MethodAddressToTokenMap.FileName + ".txt"));
                for (var i = 0; i < data.Count; i++)
                {
                    plainTextWriter.WriteLine($"{i}\t{data[i].Item1}\t{data[i].Item2}\t{data[i].Item3}");
                }
            }
        }
Exemplo n.º 11
0
        public static void DoPass(RewriteGlobalContext context, UnhollowerOptions options)
        {
            if (string.IsNullOrEmpty(options.GameAssemblyPath))
            {
                Pass15GenerateMemberContexts.HasObfuscatedMethods = false;
                return;
            }

            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;
            }

            context.HasGcWbarrierFieldWrite = FindByteSequence(gameAssemblyPtr, accessor.Capacity, nameof(IL2CPP.il2cpp_gc_wbarrier_set_field));

            if (!Pass15GenerateMemberContexts.HasObfuscatedMethods)
            {
                return;
            }

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

            context.MethodStartAddresses.Sort();

            // Scan xrefs
            context.Assemblies.SelectMany(it => it.Types).SelectMany(it => it.Methods).AsParallel().ForAll(
                originalTypeMethod =>
            {
                var address = originalTypeMethod.FileOffset;
                if (address == 0)
                {
                    return;
                }

                if (!options.NoXrefCache)
                {
                    var pair = XrefScanMetadataGenerationUtil.FindMetadataInitForMethod(originalTypeMethod, (long)gameAssemblyPtr);
                    originalTypeMethod.MetadataInitFlagRva  = pair.FlagRva;
                    originalTypeMethod.MetadataInitTokenRva = pair.TokenRva;
                }

                var nextMethodStart = context.MethodStartAddresses.BinarySearch(address + 1);
                if (nextMethodStart < 0)
                {
                    nextMethodStart = ~nextMethodStart;
                }
                var length = nextMethodStart >= context.MethodStartAddresses.Count ? 1024 * 1024 : (context.MethodStartAddresses[nextMethodStart] - address);
                foreach (var callTargetGlobal in XrefScanner.XrefScanImpl(XrefScanner.DecoderForAddress(IntPtr.Add(gameAssemblyPtr, (int)address), (int)length), true))
                {
                    var callTarget = callTargetGlobal.RelativeToBase((long)gameAssemblyPtr + originalTypeMethod.FileOffset - originalTypeMethod.Rva);
                    if (callTarget.Type == XrefType.Method)
                    {
                        var targetRelative = (long)callTarget.Pointer;
                        methodToCallersMap.GetOrAdd(targetRelative, _ => new List <XrefInstance>()).AddLocked(new XrefInstance(XrefType.Method, (IntPtr)originalTypeMethod.Rva, callTarget.FoundAt));
                        methodToCalleesMap.GetOrAdd(originalTypeMethod.Rva, _ => new List <long>()).AddLocked(targetRelative);
                    }

                    if (!options.NoXrefCache)
                    {
                        originalTypeMethod.XrefScanResults.Add(callTarget);
                    }
                }
            });

            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(options) || originalMethod.IsVirtual)
                        {
                            MarkMethodAlive(methodRewriteContext.Rva);
                        }
                    }
                }
            }
        }
Exemplo n.º 12
0
        public static void DoPass(RewriteGlobalContext context, UnhollowerOptions options)
        {
            var data = new List <MethodXrefScanCache.MethodData>();
            var existingAttributesPerAddress = new Dictionary <long, CachedScanResultsAttribute>();

            if (options.NoXrefCache)
            {
                goto skipDataGather;
            }

            foreach (var assemblyRewriteContext in context.Assemblies)
            {
                if (options.AdditionalAssembliesBlacklist.Contains(assemblyRewriteContext.NewAssembly.Name.Name))
                {
                    continue;
                }

                var imports = assemblyRewriteContext.Imports;

                foreach (var typeRewriteContext in assemblyRewriteContext.Types)
                {
                    foreach (var methodRewriteContext in typeRewriteContext.Methods)
                    {
                        var address = methodRewriteContext.Rva;

                        if (existingAttributesPerAddress.TryGetValue(address, out var attribute))
                        {
                            methodRewriteContext.NewMethod.CustomAttributes.Add(
                                new CustomAttribute(imports.CachedScanResultsAttributeCtor)
                            {
                                Fields =
                                {
                                    new CustomAttributeNamedArgument(
                                        nameof(CachedScanResultsAttribute.RefRangeStart),
                                        new CustomAttributeArgument(imports.Int, attribute.RefRangeStart)),
                                    new CustomAttributeNamedArgument(
                                        nameof(CachedScanResultsAttribute.RefRangeEnd),
                                        new CustomAttributeArgument(imports.Int, attribute.RefRangeEnd)),
                                    new CustomAttributeNamedArgument(
                                        nameof(CachedScanResultsAttribute.XrefRangeStart),
                                        new CustomAttributeArgument(imports.Int, attribute.RefRangeStart)),
                                    new CustomAttributeNamedArgument(
                                        nameof(CachedScanResultsAttribute.XrefRangeEnd),
                                        new CustomAttributeArgument(imports.Int, attribute.RefRangeEnd)),
                                    new CustomAttributeNamedArgument(
                                        nameof(CachedScanResultsAttribute.MetadataInitTokenRva),
                                        new CustomAttributeArgument(imports.Int, attribute.MetadataInitTokenRva)),
                                    new CustomAttributeNamedArgument(
                                        nameof(CachedScanResultsAttribute.MetadataInitFlagRva),
                                        new CustomAttributeArgument(imports.Int, attribute.MetadataInitFlagRva)),
                                }
                            });
                            continue;
                        }

                        var xrefStart = data.Count;

                        foreach (var xrefScanResult in methodRewriteContext.XrefScanResults)
                        {
                            data.Add(MethodXrefScanCache.MethodData.FromXrefInstance(xrefScanResult));
                        }

                        var xrefEnd = data.Count;

                        var refStart = 0;
                        var refEnd   = 0;

                        if (address != 0)
                        {
                            if (Pass16ScanMethodRefs.MapOfCallers.TryGetValue(address, out var callerMap))
                            {
                                refStart = data.Count;
                                foreach (var xrefInstance in callerMap)
                                {
                                    data.Add(MethodXrefScanCache.MethodData.FromXrefInstance(xrefInstance));
                                }

                                refEnd = data.Count;
                            }
                        }

                        if (xrefEnd != xrefStart || refStart != refEnd)
                        {
                            methodRewriteContext.NewMethod.CustomAttributes.Add(
                                new CustomAttribute(imports.CachedScanResultsAttributeCtor)
                            {
                                Fields =
                                {
                                    new CustomAttributeNamedArgument(
                                        nameof(CachedScanResultsAttribute.RefRangeStart),
                                        new CustomAttributeArgument(imports.Int, refStart)),
                                    new CustomAttributeNamedArgument(
                                        nameof(CachedScanResultsAttribute.RefRangeEnd),
                                        new CustomAttributeArgument(imports.Int, refEnd)),
                                    new CustomAttributeNamedArgument(
                                        nameof(CachedScanResultsAttribute.XrefRangeStart),
                                        new CustomAttributeArgument(imports.Int, xrefStart)),
                                    new CustomAttributeNamedArgument(
                                        nameof(CachedScanResultsAttribute.XrefRangeEnd),
                                        new CustomAttributeArgument(imports.Int, xrefEnd)),
                                    new CustomAttributeNamedArgument(
                                        nameof(CachedScanResultsAttribute.MetadataInitTokenRva),
                                        new CustomAttributeArgument(imports.Long, methodRewriteContext.MetadataInitTokenRva)),
                                    new CustomAttributeNamedArgument(
                                        nameof(CachedScanResultsAttribute.MetadataInitFlagRva),
                                        new CustomAttributeArgument(imports.Long, methodRewriteContext.MetadataInitFlagRva)),
                                }
                            });

                            existingAttributesPerAddress[address] = new CachedScanResultsAttribute
                            {
                                RefRangeStart        = refStart,
                                RefRangeEnd          = refEnd,
                                XrefRangeStart       = xrefStart,
                                XrefRangeEnd         = xrefEnd,
                                MetadataInitFlagRva  = methodRewriteContext.MetadataInitFlagRva,
                                MetadataInitTokenRva = methodRewriteContext.MetadataInitTokenRva
                            };
                        }
                    }
                }
            }

skipDataGather:

            var header = new MethodXrefScanCache.FileHeader
            {
                Magic   = MethodXrefScanCache.Magic,
                Version = MethodXrefScanCache.Version,
                InitMethodMetadataRva = XrefScanMetadataGenerationUtil.MetadataInitForMethodRva
            };

            using var writer = new BinaryWriter(new FileStream(Path.Combine(options.OutputDir, MethodXrefScanCache.FileName), FileMode.Create, FileAccess.Write), Encoding.UTF8, false);
            writer.Write(header);

            foreach (var valueTuple in data)
            {
                writer.Write(valueTuple);
            }

            if (options.Verbose)
            {
                using var plainTextWriter = new StreamWriter(Path.Combine(options.OutputDir, MethodXrefScanCache.FileName + ".txt"));
                for (var i = 0; i < data.Count; i++)
                {
                    plainTextWriter.WriteLine($"{i}\t{data[i].Type}\t{data[i].Address}\t{data[i].FoundAt}");
                }
            }
        }