internal static IEnumerable <XrefInstance> CachedXrefScan(CachedScanResultsAttribute attribute)
 {
     for (var i = attribute.XrefRangeStart; i < attribute.XrefRangeEnd; i++)
     {
         yield return(XrefScanCache.GetAt(i).AsXrefInstance(GameAssemblyBase));
     }
 }
        internal static void CallMetadataInitForMethod(CachedScanResultsAttribute attribute)
        {
            if (attribute.MetadataInitFlagRva == 0 || attribute.MetadataInitTokenRva == 0)
            {
                return;
            }

            if (Marshal.ReadByte((IntPtr)(GameAssemblyBase + attribute.MetadataInitFlagRva)) != 0)
            {
                return;
            }

            if (ourMetadataInitForMethodDelegate == null)
            {
                ourMetadataInitForMethodDelegate =
                    Marshal.GetDelegateForFunctionPointer <XrefScanMetadataRuntimeUtil.InitMetadataForMethod>(
                        (IntPtr)(GameAssemblyBase + XrefScanCache.Header.InitMethodMetadataRva));
            }

            var token = Marshal.ReadInt32((IntPtr)(GameAssemblyBase + attribute.MetadataInitTokenRva));

            ourMetadataInitForMethodDelegate(token);

            Marshal.WriteByte((IntPtr)(GameAssemblyBase + attribute.MetadataInitFlagRva), 1);
        }
Beispiel #3
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}");
                }
            }
        }