예제 #1
0
        /// <summary>
        /// Removes any friend assembly references (InternalsVisibleTo attributes) that do not have public keys.
        /// </summary>
        /// <param name="assemblyPath">The path to the assembly you want to remove friend references from.</param>
        /// <param name="keyPath">The path to the strong-name key file you want to use (.snk or .pfx).</param>
        /// <param name="keyFilePassword">The password for the provided strong-name key file.</param>
        /// <param name="probingPaths">Additional paths to probe for references.</param>
        /// <returns>
        ///   <c>true</c> if any invalid friend references were found and fixed, <c>false</c> if no invalid friend references was found.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">assemblyPath was not provided.</exception>
        /// <exception cref="System.IO.FileNotFoundException">Could not find provided assembly file.</exception>
        public static bool RemoveInvalidFriendAssemblies(string assemblyPath, string keyPath, string keyFilePassword, params string[] probingPaths)
        {
            // Verify assembly path was passed in.
            if (string.IsNullOrWhiteSpace(assemblyPath))
            {
                throw new ArgumentNullException(nameof(assemblyPath));
            }

            // Make sure the file actually exists.
            if (!File.Exists(assemblyPath))
            {
                throw new FileNotFoundException($"Could not find provided assembly file '{assemblyPath}'.", assemblyPath);
            }

            bool fixApplied = false;

            using (var outFileMgr = new OutputFileManager(assemblyPath, assemblyPath))
            {
                using (var a = AssemblyDefinition.ReadAssembly(assemblyPath, GetReadParameters(assemblyPath, probingPaths)))
                {
                    var ivtAttributes = a.CustomAttributes.Where(attr => attr.AttributeType.FullName == typeof(InternalsVisibleToAttribute).FullName).ToList();

                    foreach (var friendReference in ivtAttributes)
                    {
                        // Find any without a public key defined.
                        if (friendReference.HasConstructorArguments && friendReference.ConstructorArguments.Any(ca => ca.Value?.ToString().IndexOf("PublicKey=", StringComparison.Ordinal) == -1))
                        {
                            a.CustomAttributes.Remove(friendReference);
                            fixApplied = true;
                        }
                    }

                    if (fixApplied)
                    {
                        if (!a.Name.IsRetargetable)
                        {
                            a.Write(outFileMgr.IntermediateAssemblyPath, new WriterParameters {
                                StrongNameKeyPair = GetStrongNameKeyPair(keyPath, keyFilePassword), WriteSymbols = File.Exists(Path.ChangeExtension(assemblyPath, ".pdb"))
                            });
                        }

                        AssemblyInfoCache.TryRemove(assemblyPath, out var _);
                    }
                }

                outFileMgr.Commit();
            }

            return(fixApplied);
        }
예제 #2
0
        /// <summary>
        /// Fixes an assembly reference.
        /// </summary>
        /// <param name="assemblyPath">The path to the assembly you want to fix a reference for.</param>
        /// <param name="referenceAssemblyPath">The path to the reference assembly path you want to fix in the first assembly.</param>
        /// <param name="keyPath">The path to the strong-name key file you want to use (.snk or .pfx).</param>
        /// <param name="keyFilePassword">The password for the provided strong-name key file.</param>
        /// <param name="probingPaths">Additional paths to probe for references.</param>
        /// <returns>
        ///   <c>true</c> if an assembly reference was found and fixed, <c>false</c> if no reference was found.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">assemblyPath was not provided.
        /// or
        /// referenceAssemblyPath was not provided.</exception>
        /// <exception cref="System.IO.FileNotFoundException">Could not find provided assembly file.
        /// or
        /// Could not find provided reference assembly file.</exception>
        public static bool FixAssemblyReference(string assemblyPath, string referenceAssemblyPath, string keyPath, string keyFilePassword, params string[] probingPaths)
        {
            // Verify assembly path was passed in.
            if (string.IsNullOrWhiteSpace(assemblyPath))
            {
                throw new ArgumentNullException(nameof(assemblyPath));
            }

            if (string.IsNullOrWhiteSpace(referenceAssemblyPath))
            {
                throw new ArgumentNullException(nameof(referenceAssemblyPath));
            }

            // Make sure the file actually exists.
            if (!File.Exists(assemblyPath))
            {
                throw new FileNotFoundException($"Could not find provided assembly file '{assemblyPath}'.", assemblyPath);
            }

            if (!File.Exists(referenceAssemblyPath))
            {
                throw new FileNotFoundException($"Could not find provided reference assembly file '{referenceAssemblyPath}'.", referenceAssemblyPath);
            }

            bool fixApplied = false;

            using (var fileManagerA = new OutputFileManager(assemblyPath, assemblyPath))
                using (var fileManagerB = new OutputFileManager(referenceAssemblyPath, referenceAssemblyPath))
                {
                    using (var a = AssemblyDefinition.ReadAssembly(assemblyPath, GetReadParameters(assemblyPath, probingPaths)))
                        using (var b = AssemblyDefinition.ReadAssembly(referenceAssemblyPath, GetReadParameters(referenceAssemblyPath, probingPaths)))
                        {
                            var assemblyReference = a.MainModule.AssemblyReferences.FirstOrDefault(r => r.Name.Equals(b.Name.Name, StringComparison.OrdinalIgnoreCase));

                            // Found a matching reference, let's set the public key token.
                            if (assemblyReference != null && BitConverter.ToString(assemblyReference.PublicKeyToken) != BitConverter.ToString(b.Name.PublicKeyToken))
                            {
                                assemblyReference.PublicKeyToken = b.Name.PublicKeyToken ?? new byte[0];
                                assemblyReference.Version        = b.Name.Version;

                                a.Write(fileManagerA.IntermediateAssemblyPath, new WriterParameters {
                                    StrongNameKeyPair = GetStrongNameKeyPair(keyPath, keyFilePassword), WriteSymbols = File.Exists(Path.ChangeExtension(assemblyPath, ".pdb"))
                                });

                                AssemblyInfoCache.TryRemove(assemblyPath, out var _);

                                fixApplied = true;
                            }

                            var friendReference = b.CustomAttributes.SingleOrDefault(attr => attr.AttributeType.FullName == typeof(InternalsVisibleToAttribute).FullName &&
                                                                                     attr.ConstructorArguments[0].Value.ToString() == a.Name.Name);

                            if (friendReference != null && a.Name.HasPublicKey)
                            {
                                // Add the public key to the attribute.
                                var typeRef = friendReference.ConstructorArguments[0].Type;
                                friendReference.ConstructorArguments.Clear();
                                friendReference.ConstructorArguments.Add(new CustomAttributeArgument(typeRef, a.Name.Name + ", PublicKey=" + BitConverter.ToString(a.Name.PublicKey).Replace("-", string.Empty)));

                                // Save and resign.
                                b.Write(fileManagerB.IntermediateAssemblyPath, new WriterParameters {
                                    StrongNameKeyPair = GetStrongNameKeyPair(keyPath, keyFilePassword), WriteSymbols = File.Exists(Path.ChangeExtension(referenceAssemblyPath, ".pdb"))
                                });

                                AssemblyInfoCache.TryRemove(assemblyPath, out var _);

                                fixApplied = true;
                            }
                        }

                    fileManagerA.Commit();
                    fileManagerB.Commit();
                }

            return(fixApplied);
        }
예제 #3
0
        /// <summary>
        /// Signs the assembly at the specified path with your own strong-name key file.
        /// </summary>
        /// <param name="assemblyPath">The path to the assembly you want to strong-name sign.</param>
        /// <param name="keyPath">The path to the strong-name key file you want to use (.snk or .pfx).</param>
        /// <param name="outputPath">The directory path where the strong-name signed assembly will be copied to.</param>
        /// <param name="keyFilePassword">The password for the provided strong-name key file.</param>
        /// <param name="probingPaths">Additional paths to probe for references.</param>
        /// <returns>
        /// The assembly information of the new strong-name signed assembly.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">assemblyPath parameter was not provided.</exception>
        /// <exception cref="System.IO.FileNotFoundException">Could not find provided assembly file.
        /// or
        /// Could not find provided strong-name key file.</exception>
        /// <exception cref="System.BadImageFormatException">The file is not a .NET managed assembly.</exception>
        public static AssemblyInfo SignAssembly(string assemblyPath, string keyPath, string outputPath, string keyFilePassword, params string[] probingPaths)
        {
            // Verify assembly path was passed in.
            if (string.IsNullOrWhiteSpace(assemblyPath))
            {
                throw new ArgumentNullException(nameof(assemblyPath));
            }

            // Make sure the file actually exists.
            if (!File.Exists(assemblyPath))
            {
                throw new FileNotFoundException($"Could not find provided assembly file '{assemblyPath}'.", assemblyPath);
            }

            if (string.IsNullOrWhiteSpace(outputPath))
            {
                // Overwrite the file if no output path is provided.
                outputPath = Path.GetDirectoryName(assemblyPath);
            }
            else
            {
                // Create the directory structure.
                Directory.CreateDirectory(outputPath);
            }

            string outputFile = Path.Combine(Path.GetFullPath(outputPath), Path.GetFileName(assemblyPath));

            using (var outputFileMgr = new OutputFileManager(assemblyPath, outputFile))
            {
                // Get the assembly info and go from there.
                var info = GetAssemblyInfo(assemblyPath);

                // Don't sign assemblies with a strong-name signature.
                if (info.IsSigned)
                {
                    // If the target directory is different from the input...
                    if (!outputFileMgr.IsInPlaceReplace)
                    {
                        // ...just copy the source file to the destination.
                        outputFileMgr.CopySourceToFinalOutput();
                    }

                    return(GetAssemblyInfo(outputFile));
                }

                if (outputFileMgr.IsInPlaceReplace)
                {
                    outputFileMgr.CreateBackup();
                }

                using (var ad = AssemblyDefinition.ReadAssembly(assemblyPath, GetReadParameters(assemblyPath, probingPaths)))
                {
                    ad.Write(outputFileMgr.IntermediateAssemblyPath, new WriterParameters()
                    {
                        StrongNameKeyPair = GetStrongNameKeyPair(keyPath, keyFilePassword), WriteSymbols = outputFileMgr.HasSymbols
                    });
                }

                AssemblyInfoCache.TryRemove(assemblyPath, out var _);

                outputFileMgr.Commit();

                return(GetAssemblyInfo(outputFile));
            }
        }