C# 动态修改dll的签名 以及修改引用该dll文件的签名

简介: 原文:C# 动态修改dll的签名 以及修改引用该dll文件的签名在读取RedisSessionStateProvider配置 提到用mono ceil 来修改程序集以及它的签名,里面GetPublicKey 和GetPubliKeyToken 方法里面那个字符串的获取 以及后来的签名 我们都应该 用code来实现,还有应用该dll文件的签名也一同需要修改。
原文: C# 动态修改dll的签名 以及修改引用该dll文件的签名

读取RedisSessionStateProvider配置 提到用mono ceil 来修改程序集以及它的签名,里面GetPublicKey 和GetPubliKeyToken 方法里面那个字符串的获取 以及后来的签名 我们都应该 用code来实现,还有应用该dll文件的签名也一同需要修改。

所以我这里实现了一个简单的helper方法 如下:

namespace ConsoleSession
{
    using Mono.Cecil;
    using System;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.InteropServices;

    public class ChangeAssemblyInfo
    {
        public string FileName { set; get; }
        public string FullName { set; get; }
    }
    public class keyHelper
    {
        static byte[] GetNewKey(string keyFileName)
        {
            using (FileStream keyPairStream = File.OpenRead(keyFileName))
            {
                return new StrongNameKeyPair(keyPairStream).PublicKey;
            }
        }

        public static void ReSign(string keyFileName, string assemblyFileName)
        {
            AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(assemblyFileName);
            asm.Name.PublicKey = GetNewKey(keyFileName);
            asm.Write(assemblyFileName);
            //用KEY文件建立密钥容器                     
            byte[] pbKeyBlob = File.ReadAllBytes(keyFileName);
            string wszKeyContainer = Guid.NewGuid().ToString();
            StrongNameKeyInstall(wszKeyContainer, pbKeyBlob, pbKeyBlob.Length);
            //使用新建的密钥容器对程序集经行签名          
            StrongNameSignatureGeneration(assemblyFileName, wszKeyContainer, IntPtr.Zero, 0, 0, 0);
            //删除新建的密钥容器          
            StrongNameKeyDelete(wszKeyContainer);
        }

        private static byte[] tryGetPublicKeyToken(string keyFileName)
        {
            try
            {
                byte[] newPublicKey;
                using (FileStream keyPairStream = File.OpenRead(keyFileName))
                {
                    newPublicKey = new StrongNameKeyPair(keyPairStream).PublicKey;
                }
                int pcbStrongNameToken;
                IntPtr ppbStrongNameToken;
                StrongNameTokenFromPublicKey(newPublicKey, newPublicKey.Length, out ppbStrongNameToken,
                                             out pcbStrongNameToken);
                var token = new byte[pcbStrongNameToken];
                Marshal.Copy(ppbStrongNameToken, token, 0, pcbStrongNameToken);
                StrongNameFreeBuffer(ppbStrongNameToken);
                return token;
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static void ReLink(string keyFileName, ChangeAssemblyInfo[] assemblyInfoList)
        {
            byte[] publicKeyToken = tryGetPublicKeyToken(keyFileName);
            if (publicKeyToken == null)
            {
                return;
            }

            //获得每个程序集的名称
            foreach (ChangeAssemblyInfo assemblyInfo in assemblyInfoList)
            {
                assemblyInfo.FullName = AssemblyDefinition.ReadAssembly(assemblyInfo.FileName).Name.FullName;
            }
            //检查是否被引用,是的话,就替换PublicKeyToken
            foreach (ChangeAssemblyInfo assemblyInfo in assemblyInfoList)
            {
                AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(assemblyInfo.FileName);
                foreach (ModuleDefinition module in assembly.Modules)
                    foreach (AssemblyNameReference reference in module.AssemblyReferences)
                        if (assemblyInfoList.Any(a => a.FullName == reference.FullName))
                        {
                            reference.PublicKeyToken = publicKeyToken;
                            assembly.Write(assemblyInfo.FileName);
                        }
            }
        }

        #region StrongName库作为一项资源包含在 MsCorEE.dll 中,其一系列API包含有
        [DllImport("mscoree.dll", EntryPoint = "StrongNameKeyDelete", CharSet = CharSet.Auto)]
        static extern bool StrongNameKeyDelete(string wszKeyContainer);

        [DllImport("mscoree.dll", EntryPoint = "StrongNameKeyInstall", CharSet = CharSet.Auto)]
        static extern bool StrongNameKeyInstall([MarshalAs(UnmanagedType.LPWStr)] string wszKeyContainer,
                                                       [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2,
                                                           SizeConst = 0)] byte[] pbKeyBlob, int arg0);

        [DllImport("mscoree.dll", EntryPoint = "StrongNameSignatureGeneration", CharSet = CharSet.Auto)]
        static extern bool StrongNameSignatureGeneration(string wszFilePath, string wszKeyContainer,
                                                                IntPtr pbKeyBlob, int cbKeyBlob, int ppbSignatureBlob,
                                                                int pcbSignatureBlob);

        [DllImport("mscoree.dll", EntryPoint = "StrongNameErrorInfo", CharSet = CharSet.Auto)]
        static extern uint StrongNameErrorInfo();

        [DllImport("mscoree.dll", EntryPoint = "StrongNameTokenFromPublicKey", CharSet = CharSet.Auto)]
        static extern bool StrongNameTokenFromPublicKey(byte[] pbPublicKeyBlob, int cbPublicKeyBlob,
                                                               out IntPtr ppbStrongNameToken, out int pcbStrongNameToken);

        [DllImport("mscoree.dll", EntryPoint = "StrongNameFreeBuffer", CharSet = CharSet.Auto)]
        static extern void StrongNameFreeBuffer(IntPtr pbMemory);
        #endregion
    }
}

调用code 如下:

    using System;
    using System.IO;
    using System.Linq;
    using Mono.Cecil;
    class Program
    {
        static void Main(string[] args)
        {
            #region 修改程序集
            string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Microsoft.Web.RedisSessionStateProvider3.dll");
            AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(filePath);
            TypeDefinition[] types = asm.MainModule.Types.ToArray();

            //修改ProviderConfiguration为public
            TypeDefinition typeConfiguration = types.FirstOrDefault(x => x.Name == "ProviderConfiguration");
            typeConfiguration.IsPublic = true;

            //修改ProviderConfiguration的字段为public
            TypeDefinition typeRedisProvide = types.FirstOrDefault(x => x.Name == "RedisSessionStateProvider");
            FieldDefinition filedConfiguration = typeRedisProvide.Fields.ToArray().FirstOrDefault(x => x.Name == "configuration");
            filedConfiguration.IsPublic = true;
            //保存dll文件
            filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Microsoft.Web.RedisSessionStateProvider.dll");
            asm.Write(filePath);
            #endregion
            string keyfileName = @"D:\mykey.snk";
            //修改单个dll文件的签名
            keyHelper.ReSign(keyfileName,filePath);

            //修改引用该dll文件的签名
            keyHelper.ReLink(keyfileName, new ChangeAssemblyInfo[] {
                new ChangeAssemblyInfo { FileName = filePath }
               ,new ChangeAssemblyInfo { FileName=Path.Combine(@"C:\Users\UNIT12\Documents\visual studio 2015\Projects\SessionWebApp\SessionWebApp\bin","SessionWebApp.dll")}
            });
            //Console.ReadLine();
        }
    
    }

参考资料:

利用Mono-cecil实现.NET程序的重新签名,重新链接相关库的引用

 

目录
相关文章
|
8月前
|
存储 监控 算法
基于 C# 的局域网计算机监控系统文件变更实时监测算法设计与实现研究
本文介绍了一种基于C#语言的局域网文件变更监控算法,通过事件驱动与批处理机制结合,实现高效、低负载的文件系统实时监控。核心内容涵盖监控机制选择(如事件触发机制)、数据结构设计(如监控文件列表、事件队列)及批处理优化策略。文章详细解析了C#实现的核心代码,并提出性能优化与可靠性保障措施,包括批量处理、事件过滤和异步处理等技术。最后,探讨了该算法在企业数据安全监控、文件同步备份等场景的应用潜力,以及未来向智能化扩展的方向,如文件内容分析、智能告警机制和分布式监控架构。
225 3
基于 C# 编写的 Visual Studio 文件编码显示与修改扩展插件
基于 C# 编写的 Visual Studio 文件编码显示与修改扩展插件
239 9
|
存储 C#
【C#】大批量判断文件是否存在的两种方法效率对比
【C#】大批量判断文件是否存在的两种方法效率对比
449 1
|
监控 安全 C#
使用C#如何监控选定文件夹中文件的变动情况?
使用C#如何监控选定文件夹中文件的变动情况?
359 19
|
XML 存储 缓存
C#使用XML文件的详解及示例
C#使用XML文件的详解及示例
668 0
Delphi可不可以制作出像c#那样的dll类库?
在Delphi中,创建DLL项目(如dll.dpr)并定义一个类TMyCls后,在另一个项目(如test.dpr)中可以引入此DLL并直接实例化和调用类的方法。然而,Delphi目前主要支持两种DLL形式:动态链接库(需显式声明exports,仅支持函数调用)和ActiveX DLL(需定义IDL接口)。这两种方式都较为繁琐。相比之下,C# 的DLL类库更为便捷,编写并编译后即可在其他项目中直接使用。
|
编译器 C# Windows
C#基础:手动编译一个.cs源代码文件并生成.exe可执行文件
通过上述步骤,应该能够高效准确地编译C#源代码并生成相应的可执行文件。此外,这一过程强调了对命令行编译器的理解,这在调试和自动化编译流程中是非常重要的。
1332 2
|
文字识别 C# Python
使用C#将几个Excel文件合并去重分类
使用C#将几个Excel文件合并去重分类
210 3
|
C#
C# WPF 将第三方DLL嵌入 exe
C# WPF 将第三方DLL嵌入 exe
331 0
|
C# 图形学 数据安全/隐私保护
Unity数据加密☀️ 二、使用Rider将C#代码生成DLL文件
Unity数据加密☀️ 二、使用Rider将C#代码生成DLL文件