在讀取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程序的重新簽名,重新鏈接相關庫的引用