zoukankan      html  css  js  c++  java
  • 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:UsersUNIT12Documentsvisual studio 2015ProjectsSessionWebAppSessionWebAppin","SessionWebApp.dll")}
                });
                //Console.ReadLine();
            }
        
        }

    参考资料:

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

  • 相关阅读:
    android闹钟小案例之知识点总结
    转载---程序员发展之路
    android闹钟小案例之功能阐述
    基础篇:2.熟练掌握相关监听器的注册和使用
    基础篇:1.掌握基本组件和容器组件的使用
    微博分享、注销功能的实现
    新浪微博授权认证的实现
    新浪微博分享功能的简单实现
    读《编程高手箴言》笔记一
    Spark内核架构核心组件.txt
  • 原文地址:https://www.cnblogs.com/majiang/p/6149007.html
Copyright © 2011-2022 走看看