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

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 原文: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程序的重新签名,重新链接相关库的引用

 

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1月前
|
XML C# 数据格式
使用C#操作XML文件
使用C#操作XML文件
11 0
|
1月前
|
C#
C# 文件操作(全部) 追加、拷贝、删除、移动文件、创建目录
C# 文件操作(全部) 追加、拷贝、删除、移动文件、创建目录
23 0
|
3月前
|
C#
C#读取html文件
C#读取html文件
28 3
|
3月前
|
C# 开发者
C# 10.0中的文件范围命名空间:简化代码组织的新方式
【1月更文挑战第18天】C# 10.0引入了文件范围的命名空间,这是一种新的语法糖,用于更简洁地组织和管理代码。文件范围命名空间允许开发者在每个文件的基础上定义命名空间,而无需显式使用花括号包裹整个文件内容。本文将深入探讨文件范围命名空间的工作原理、使用场景以及它们为C#开发者带来的便利。
|
5月前
|
C#
Visual Studio C# CS0006 C# 未能找到元数据文件
Visual Studio C# CS0006 C# 未能找到元数据文件
66 0
Visual Studio C# CS0006 C# 未能找到元数据文件
|
6月前
|
开发框架 .NET C#
利用WinDbg分析C#程序产生的转储文件
利用WinDbg分析C#程序产生的转储文件
|
6天前
|
XML C# 数据格式
C# 解析XML文件
C# 解析XML文件
14 1
|
4月前
|
IDE C# 开发工具
C# | 多线程批量下载文件(创建N个线程同时批量下载文件,只需要几行代码而已)
批量下载文件时使用多线程可以有效缩短完成时间,本文将讲解如何使用C#+CodePlus扩展库快速完成多线程的文件下载。 大部分代码由IDE自动生成,需要我们自己编写的代码正好**10行**。也就是说,只需要10分钟,就可以手撸一个多线程的批量下载器。
88 0
C# | 多线程批量下载文件(创建N个线程同时批量下载文件,只需要几行代码而已)
|
1月前
|
安全 数据处理 C#
C# Post数据或文件到指定的服务器进行接收
C# Post数据或文件到指定的服务器进行接收
|
1月前
|
C# 开发工具 数据安全/隐私保护
C#实现基于Word保护性模板文件的修改
C#实现基于Word保护性模板文件的修改