




已阅读5页,还剩1页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
.NET环境下实现程序集的动态替换.NET程序集是包含一个或者多个类型定义文件和资源文件的集合,它是 .NET Framework 编程的基本组成部分。也可以通俗地描述它为由.NET生成的.exe文件或者.dll文件。.NET环境下支持两种程序集:弱命名程序集和强命名程序集。 弱命名程序集和强命名程序集在结构上是相同的。他们都采用PE文件格式,包含PE表头,CLR表头,元数据和清单表。区别在于:强命名程序集拥有一个发布者的公钥/私钥签名对,他们用于唯一的标识程序集的发布者。通过公钥/私钥对,我们可以对程序集进行唯一的标识,安全策略和版本策略。一、需求背景在传统的win32环境下,我们只需要将程序集覆盖同名程序集,便可以实现对程序集的动态替换。但是这种替换方式,很容易导致DLL Hell问题。DLL Hell问题是指两个不同的公司可能开发处具有相同名称的程序集,如果将相同名称的程序集放置到同一个目录下,则会出现程序集覆盖现象,最后安装的程序集会覆盖前面的程序集,从而可能导致应用程序不能正常运行。为了解决这一问题,在.NET环境下,CLR采取了强命名程序集的方式来唯一的表示程序集。强命名程序集包含四个标识:名称,版本号,语言文化标识和一个共有/私有密钥对。显然地,在.NET环境下,仅程序集名称相同的两个程序集,是不会发生动态替换的情况的。那么,在.NET环境下,我们如何才能实现强命名程序集的动态替换呢?下面我们假想这样一个应用场景:我们熟悉的System.Data.SqlClient.dll就是一个.NET程序集,该程序集是微软官方提供的数据提供程序(.NET Data Provider),它是.NET应用程序与数据库交互的桥梁。图一展示了常见.NET应用系统的结构。一般地,.NET应用系统包括应用程序,.NET Data Provider 以及数据库。应用程序需要通过.NET Data Provider才能向数据库中访问和存储数据。图一:.NET应用系统结构图正常情况下,上面介绍的应用系统可以很好地服务于企业日常运作,满足企业需求。但是在某些特殊情况下,出于对成本和业务扩展等因素的综合考虑,企业需要更换应用系统的后台数据库,比如,将后台数据库由SQL Server更换为神通数据库。自然地,我们想到要将数据提供程序由System.Data.SqlClient.dll更换为System.Data.OscarClient.dll,然后,重新收集企业的业务需求,最终重新编写应用程序。但是,如果为了节省成本,企业强烈要求不能更换应用程序,仍然使用现有的应用程序,作为一个程序员,你是否会觉得该需求不可能实现?让我们重新梳理一下需求:后台数据库由SQL Server更换为神通数据库,应用程序保持不变,即:不能修改应用程序源代码,并且不能对应用程序进行重新编译,我们看到应用程序只是一些程序集文件(.exe文件或.dll文件)。如果想完成该项目,看来只能从.NET Data Provider入手了,但是,看起来这也是不可能完成的任务,因为System.Data.SqlClient.dll是经过强命名的程序集,它的公钥标记是b77a5c561934e089,这个程序集已被调用它的应用程序所记住,在应用程序不作任何变动的情况下,即使我们基于System.Data.OscarClient.dll仿冒出一个System.Data.SqlClient.dll,但是因为公钥标记不匹配,上层应用程序仍不识别该程序集,应用系统也将无法正常运行。如果能修改上层应用程序所记住System.Data.SqlClient.dll的公钥标记,用一个新的公钥标记来代替,并将该标记设置为仿冒出来的System.Data.SqlClient.dll的公钥标记,问题便可迎刃而解。要修改强命名程序的公钥标记,调用 Mono.Cecil组件是唯一的选择。二、Mono.Cecil简介Mono.Cecil是Mono的组件之一,它是一个强大的MSIL的注入工具,利用它可以实现动态创建程序集,也可以实现拦截器横向切入动态方法,甚至还可以修改已有的程序集。我们可以用它来打探一个.NET程序集内部的结构,就像反射那样,只不过并不需要将程序集加载进来,Mono.Cecil只是读取文件物理内容而已。更重要的是,Mono.Cecil可以修改并保存程序集,这便可以让我们实现各种各样的要求。另外,它支持多个运行时框架如:.NET2.0、.NET3.5、.NET4.0以及silverlight程序。显然地,有了Mono.Cecil,我们可以容易地实现程序集的动态替换,Mono.Cecil的功能非常强大,本文只涉及了很少的一部分。三、解决方案及步骤将Mono.Cecil应用于本项目的主要思路是用Mono.Cecil加载一个程序集,使用微软提供SN工具来生成新的公钥标记替换掉原来程序集的公钥标记,然后对仿冒的System.Data.SqlClient.dll进行重新签名,最后是修改调用System.Data.SqlClient.dll的外部程序所记录的公钥标记,最终实现应用程序的顺利执行。下面对这一过程作具体描述。1.使用SN工具生成私钥文件(.snk),获取公钥标记。以VS2008为例,生成.snk文件的过程如下:1).打开SDK Command Prompt或者VS2008中的Visual Studio 2008 Command Prompt2).输入sn -k aa.snk,得到的私钥文件aa.snk在命令提示符的当前文件夹下 3).输入sn -p aa.snk aaPublic.snk 4).输入sn -t aaPublic.snk 得到公钥标记(Publickeytoken)。经过上述步骤,我们可以获取到私钥文件aa.snk和公钥标记。公钥标记是一个16位的数字和字母混合而成的数,例如,本例中获得的公钥标记为:37a1891d587db1fe。2.使用私钥文件(.snk),对仿冒的程序集进行重新签名。到这里就需要使用Mono.Cecil组件了。为了配合使用,我们还需要调用另外一个资源:StrongName库。StrongName库作为一项资源包含在 MsCorEE.dll 中。在c#中调用它的声明如下:DllImport(mscoree.dll, EntryPoint = StrongNameKeyDelete, CharSet = CharSet.Auto)public static extern bool StrongNameKeyDelete(string wszKeyContainer);DllImport(mscoree.dll, EntryPoint = StrongNameTokenFromPublicKey, CharSet = CharSet.Auto)public static extern bool StrongNameTokenFromPublicKey(byte pbPublicKeyBlob, int cbPublicKeyBlob, out IntPtr ppbStrongNameToken, out int pcbStrongNameToken);DllImport(mscoree.dll, EntryPoint = StrongNameFreeBuffer, CharSet = CharSet.Auto)public static extern void StrongNameFreeBuffer(IntPtr pbMemory);DllImport(mscoree.dll, EntryPoint = StrongNameKeyInstall, CharSet = CharSet.Auto)public 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)public static extern bool StrongNameSignatureGeneration(string wszFilePath, string wszKeyContainer, IntPtr pbKeyBlob, int cbKeyBlob, int ppbSignatureBlob, int pcbSignatureBlob);其中,StrongNameKeyDelete是删除指定的密钥容器。StrongNameTokenFromPublicKey是获取表示公钥的标记,StrongNameFreeBuffer是释放上一次调用强名称函数(如 StrongNameGetPublicKey、StrongNameTokenFromPublicKey 或 StrongNameSignatureGeneration)时分配的内存,StrongNameKeyInstall是向容器中导入一个公钥/私钥对,StrongNameSignatureGeneration是生成指定程序集的强名称签名。实现重签名的代码如下:public static byte GetNewKey(string keyFileName) using (FileStream keyPairStream = File.OpenRead(keyFileName) return new StrongNameKeyPair(keyPairStream).PublicKey; public void ReSign() AssemblyDefinition asm = AssemblyFactory.GetAssembly(ASSEMBLYNAME); asm.Name.PublicKey = GetNewKey(KEYFILENAME); AssemblyFactory.SaveAssembly(asm, ASSEMBLYNAME); /用KEY文件建立密钥容器 byte pbKeyBlob = File.ReadAllBytes(KEYFILENAME); string wszKeyContainer = Guid.NewGuid().ToString(); StrongNameKeyInstall(wszKeyContainer, pbKeyBlob, pbKeyBlob.Length); /使用新建的密钥容器对程序集进行签名 StrongNameSignatureGeneration(ASSEMBLYNAME, wszKeyContainer, IntPtr.Zero, 0, 0, 0); /删除新建的密钥容器 StrongNameKeyDelete(wszKeyContainer); 其中,keyFileName参数既是私钥文件aa.snk,ASSEMBLYNAME是仿冒的System.Data.SqlClient.dll。上述重签名过程的实质就是首先建立一个密钥容器,使用密钥容器对程序集进行重签名。经过以上程序处理可将仿冒的System.Data.SqlClient.dll的公钥标记从9a875100e271928d修改为37a1891d587db1fe。3.修改调用程序集的外部应用程序所记录的公钥标记。示例代码如下:private static byte tryGetPublicKeyToken(string keyFileName) 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 bytepcbStrongNameToken; Marshal.Copy(ppbStrongNameToken, token, 0, pcbStrongNameToken); StrongNameFreeBuffer(ppbStrongNameToken); return token; public static void ReLink(string KEYFILENAME, string file ,string refAssemblyfile) /获取加密文件的公钥标记 byte publicKeyToken = tryGetPublicKeyToken(KEYFILENAME); /初始化一个要重新签名的程序信息列表 AssemblyInfo assemblyInfoList = new new AssemblyInfo FileName =file, new AssemblyInfo FileName =refAssemblyfile ; /获得每个程序集的名称 foreach (AssemblyInfo assemblyInfo in assemblyInfoList) assemblyInfo.FullName = AssemblyFactory.GetAssembly(assemblyInfo.FileName).Name.FullName; /检查是否被引用,是的话,就替换PublicKeyToken foreach (AssemblyInfo assemblyInfo in assemblyInfoList) AssemblyDefinition assembly =AssemblyFactory.GetAssembly(assemblyInfo.FileName); foreach (ModuleDefinition module in assembly.Modules) foreach (AssemblyNameReference reference in module.AssemblyReferences) foreach (AssemblyInfo assInfo in assemblyInfoList) if (assInfo.FullName = reference.FullName) reference.PublicKeyToken = publicKeyToken; AssemblyFactory.SaveAssembly(assembly, assemblyInfo.FileName); 其中,tryGetPublicKeyToken方法是获取私钥文件的公钥标记,ReLink方法实现了修改调用System.Data.SqlClient.dll的外部程序所记录的公钥标记。AssemblyDefinition, ModuleDef
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 工业废水处理与环境修复
- 工业排放标准与环境监测技术应用研究
- 工业废水处理技术及设备优化方案
- 工业污染与治理技术
- 工业生态与绿色生产
- 工业机器人技术的发展与挑战
- 工业机器人的人性化设计与交互技术
- 工业机械系统故障诊断与排除
- 工业级数据中心机房建设标准
- 工业自动化与智能化的趋势分析
- 通力电梯技能培训教材系列:《KCE控制系统课程》
- 《中医内科学》血证-课件
- 科研伦理与学术规范期末考试1题库
- 2023年深圳市龙华产业资本投资有限公司招聘笔试题库及答案解析
- 心电监护操作评分标准
- 国开经济学(本)1-14章练习试题及答案
- 电缆桥架安装记录
- 绿电制绿氢及其综合利用技术PPT
- 各类安全事故案例图片合集
- 急性有机磷中毒临床治疗指南
- 实验室CNAS评审常见问题精编要点
评论
0/150
提交评论