第三章 共享程序集和强命名程序集
3.1 两种程序集,两种部署
CLR支持两种程序集:弱命名程序集和强命名程序集
强命名程序集使用发布者的公钥/私钥进行了签名。这一对秘钥允许对程序集进行唯一性的标识,保护和版本控制,并允许程序集部署到用户机器的任何地方,和Internet上。
程序集有两种方式部署:私有或全局
私有部署的程序集是指部署到应用程序基目录或者某个子目录的程序集。弱命名程序集只能以私有方式部署。
全局部署的程序集是指部署到一些公认位置的程序集。强命名程序集既可以私有部署,也可全局部署。
3.2 为程序集分配强名称
强命名程序集有四个重要特性:它们共同对程序集进行唯一性标识:文件名(不计扩展名),版本号,语言文化和公钥。公钥标记--公钥派生的小哈希值。
弱命名程序集可在清单数据中嵌入程序集版本和语言文化;然而,CLR通过探测子目录查找附属程序集时,会忽略版本号,只有语言文化信息。由于弱命名程序集总是私有部署,所以CLR在应用程序基目录或子目录中搜索程序集文件时只使用程序集名称。
强命名程序集除了有文件名,程序集版本号和语言文化,还用发布者私钥进行了签名。对文件进行签名的准确含义是:生成强命名程序集时,程序集FileDef青岛那元数据表列出构成程序集的所有文件。每将一个文件添加到清单,都对文件内容进行哈希处理。哈希值和文件名一道存储到FileDef表中。生成包含清单的PE文件后,会对PE文件的完整内容(除去Authenticode Signature,程序集强名称数据以及PE头校验和)进行哈希处理。
3.3 全局程序集缓存
全局程序集缓存(Global Assembly Cache,GAC)是所有程序需要访问的程序集公认位置。GAC的具体位置是一种实现细节,不同版本会有所变化。
GAC目录是结构化的:其中包含许多子目录,子目录名称用算法生成,所有不要将程序集文件手动复制到GAC目录,要用工具完成这项任务。在GAC中全局部署是对程序集进行注册的一种形式。
3.4 在生成的程序集中引用强命名程序集
安装.NET Framework时,实际会安装Microsoft的程序集文件的两套拷贝。一套安装到编译器/CLR目录,另一套安装到GAC的子目录。编译器/CLR目录中的文件方便你生成程序集,而GAC中的拷贝则方便在运行时加载。
编译器/CLR目录中的程序集不依赖机器,这些程序集只包含元数据。由于编译时不需要IL代码,所以该目录不必同时包含程序集x86,x64,和ARM版本。
GAC中的程序集才同时包含元数据和IL代码,因为仅在运行时才需要代码,由于代码可针对特定CPU架构进行优化,所以GAC允许存在一个程序集的多个拷贝。每个CPU架构都有一个专门的子目录来容纳这些拷贝。
3.5 强命名程序集能防篡改
用私钥对程序集进行签名,并将公钥和签名嵌入程序集,CLR就可验证程序集被修改或破坏。
程序集安装到GAC时,系统对包含清单的那个文件的内容进行哈希处理,将哈希值与PE文件嵌入的RSA数据签名进行比较(在用公钥解除了签名之后)。如果两个值完成一致,表明内容未被篡改。此外,系统还对程序集的其他文件的内容进行哈希处理,并将哈希值与清单的FileDef表中的存储的哈希值进行比较。任何一个哈希值不匹配,表明程序集至少有一个文件被篡改,程序集将无法安装到GAC。
3.6 延迟签名
延迟签名也称为部分签名。延迟签名允许只用公司的公钥生成程序集,暂时不用私钥。为了实现延迟签名,需要获取存储在文件中的公钥值,将文件名传给用于生成程序集的实现应用。
使用延迟签名技术开发程序集的步骤:
1.开发期间,获取只含公司公钥的文件,使用/keyfile和/delaysing编译器开关编译陈程序集:csc /keyfile:MyCompany.PublicKey /delaysign MyAssembly.cs
2.生成程序集后执行下面命令,使CLR暂时信任程序集的内容,不对它进行哈希处理,也不对哈希值进行比较。SN.exe -Vr MyAssembly.dll
3.准备好打包和部署程序集,获取公司的私钥并执行以下命令。SN.exe -Ra MyAssembly.dll MyCompany.PrivateKey
4.为了在实际环境中测试执行以下命令,重新启用这个程序集的验证:SN -Vu MyAssembly.dll
3.7 私有部署强命名程序集
私有部署达成了“简单复制部署”目标,而且能更好地隔离应用及其程序集。
程序集也可以部署只由少数应用程序知道的目录(不推荐)
3.8 ‘运行时"如何解析类型引用
运行应用程序,CLR会加载并初始化自身 ,读取程序集的CLR头,查找标识了应用程序入口方法的MethodDefToken,检查MethodDef元数据表找到方法IL代码在文件中的偏移量,将IL代码JIT编译成本地代码,最后执行本机代码。对IL代码进行JIT编译,CLR会检测所有类型和成员引用,加载它们的定义程序集(如果尚未加载)。
解析引用类型时,CLR可能在三个地方找到类型。
相同文件:编译时便能发现对相同文件中的类型的访问,这称为早期绑定。类型直接从文件中加载,执行继续。
不同文件,相同程序集:“运行时”确保被引用的文件在当前程序集元数据的FileDef表中,检查加载程序集清单文件的目录,加载被引用的文件,检查哈希值以确保文件完整性。发现类型的成员,执行继续。
不同文件,不同程序集:如果引用的类型在其他程序集的文件中,“运行时”会加载被引用的程序集的清单文件。如果需要的类型不在该文件中,就继续加载包含了类型的文件。发现类型的成员,执行继续。
3.9 高级管理控制(配置)
编译方法时,CLR判断它引用了哪些类型和成员,根据这些信息,”运行时“检查进行引用的程序集的AssemblyRef表,判断程序集生成时引用了哪些程序集。然后,CLR在应用程序集配置文件中检查程序集/版本,进行指定的版本号重定向操作。随后,CLR查找新的,重定向的程序集/版本。
系统允许使用和元数据所记录的不完全匹配的程序集版本。
发布者策略控制