您的位置:首页 > 编程语言 > C#

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

2016-12-09 12:24 423 查看
读取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程序的重新签名,重新链接相关库的引用

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: