目录结构:

contents structure [+]

1. 程序集的简介

程序集是一个.dll或者一个.exe文件,里面包含了很多类的定义和资源。比如我们使用的System.dll,System.Core.dll...文件。

CLR支持两种程序集:弱命名程序集和强命名程序集。弱命名和强命名程序集的结构完全相同。两者的区别在于:强命名程序集使用发布者的公钥/私钥进行了签名。这对秘钥允许对程序集进行唯一性的标识、保护和版本控制,并允许程序部署到用户机器的任何地方。

程序集可采用两种方式部署:私有或全局。私有部署的程序集是指部署到应用程序基目录或者某个子目录下面。全局部署是指部署到一些公认位置的程序集。弱命名程序集只能私有部署,强命名程序集既可以私有部署也可以全局部署。
如下:

  全局部署 私有部署
强命名程序集
弱命名程序集

2. 为程序集分配强名称

要由多个应用程序访问的程序集必须放到公认的目录。另外,检测到对程序集的引用时,CLR必须能自动检查该目录。

CLR支持对程序集进行唯一性标识的机制,这就是“强命名程序集”。强命名程序集共有4个重要特征,它们共同对程序集进行唯一性的标识:文件名(不计扩展名)、版本号、语言文化和公钥。由于公钥数字很大,所以经常使用从公钥派生的小哈希值,称为公钥标记(public key token)。例如下面4个程序集标识字符串显示了4个完全不同的程序集文件:

"MyTypes,Version=1.0.8123.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"
"MyTypes,Version=1.0.8123.0,Culture="en-Us",PublicKeyToken=b77a5c561934e089"
"MyTypes,Version=2.0.8123.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"
"MyTypes,Version=1.0.8123.0,Culture=neutral,PublicKeyToken=a0371q001382p23a"

2.1 如何指定程序集的版本资源信息

在PE(Portable Executable 可执行文件)文件中能嵌入标准的Win32版本资源。在生成程序集时,应该使用特性来设置各种版本资源字段,每种语言生成程序集版本资源的特性代码的都不一样,下面介绍使用VB语言生成PE文件时如何指定版本资源信息。

首先在Microsoft Visual Studio上新建一个VB的类库项目。在项目的本地文件夹下,可以找到AssemblyInfo.vb的文件

然后打开这个文件,可以看到其中的内容如下(笔者经过了修改,并且只贴出了部分代码):

<Assembly: AssemblyTitle("名称")>
<Assembly: AssemblyDescription("描述")>
<Assembly: AssemblyCompany("公司")>
<Assembly: AssemblyProduct("产品")>
<Assembly: AssemblyCopyright("Copyright © Microsoft 2018")>
<Assembly: AssemblyTrademark("商标")>
<Assembly: ComVisible(False)>
<Assembly: AssemblyVersion("1.0.0.0")>
<Assembly: AssemblyFileVersion("1.0.0.0")>

然后在Visual Studio中重新生成文件,找到生成的PE文件,右键“属性”->"详细信息",就可以看到如下图所示:

通过上面的方式指定程序集有点繁琐,好在Visual Studio为我们提供了便利,只需要在Visual Studio中右击项目,选择“属性”->"应用程序"->"程序集信息",就可以进行修改了。

2.2 如何对程序集签名

在上面我们已经知道了,弱命名程序集经过签名(使用公钥和私钥签名)就会成为强命名程序集,下面介绍如何签名程序集。

首先使用SN.exe来获得秘钥,SN.exe程序一般在C:\Program Files (x86)\Microsoft SDKs\Windows的子目录下面,下面使用SN.exe来创建一个包含公钥、私钥的文件。

sn -k MyCompany.snk

创建的MyCompany.snk是包含了一对公钥和秘钥的文件。公钥的数字很大,如果愿意的话,可以再次使用sn.exe来查看完整的公钥值和公钥标记值。只需要执行两次sn.exe。
第一次使用-p创建只含公钥的文件

sn -p MyCompany.snk MyCompany.PublicKey sha256

第二次使用-tp显示公钥标记和公钥本身。

sn -tp MyCompany.PublicKey 

然后会得到类似如下的输出:

Microsoft(R) .NET Framework 强名称实用工具 版本 4.0.30319.17929
版权所有(C) Microsoft Corporation。保留所有权利。 公钥(哈希算法: sha256):
002400000c800000940000000602000000240000525341310004000001000100f70211026bf0c5
04ec93bd52e3c7c14373e18f65d385e7151fc2de3559b50668cc8f4d5eae739745ead0d0e16036
d2aa033b8ec9366e92cf2d90a5a0d02ae00ee7a915df4e1eeb01d74a473063b741c0473c345254
211060134f626c30e3bb1057e43fd56ee04810713ba05101a32d591278d6a0497d14db70e488a3
1a731cbe 公钥标记为 47ea4c468f699f0b

在创建好公钥/私钥标记对后,就可以利用具体语言的具体命令来创建强命名程序集了。

3. 全局程序集缓存(GAC)

我们已经知道了如何创建强命名程序集了,强命名程序集可以私有部署,也可以全局部署(部署到GAC中)。

这里先介绍一下全局程序集缓存(Global Assembly Cache,GAC)的概念:由多个应用程序访问的程序集必须放到公认的目录,而且CLR在检测到该程序集的引用时,必须知道检查该目录,这个公认的位置就是GAC。

GAC一般在如下的位置:

%SystemRoot%\Microsoft.NET\Assembly

GAC的目录是结构化的:其中包含许多子目录,子目录名称用算法生成。永远不要将程序集手动复制到GAC目录,相反应该用工具来完成。

开发和测试时在GAC中安装命名程序集最常用的工具是GACUtil.exe,该工具一般在 C:\Program Files (x86)\Microsoft SDKs\Windows 的子目录下面。

4. 如何查看程序集的信息

我们已经知道了一个程序集由四部分标识,分别为:文件名(不计扩展名)、版本号、语言文化和公钥标记(公钥很大,一般不使用)。弱命名程序集没有公钥(自然也没有公钥标记),若命名程序集经过公钥/私钥对签名后,就称为了强命名程序集。

当我们知道一个程序集后,如果获得这些标识呢?在程序集中,没有直接给我们相关的信息,这些信息都是分散的,需要我们去分别查找。

使用ILDASM反编译一个程序集,点击“视图”->“元信息”->“显示!”,然后查找“Assembly”的定义部分(Assembly一般位于文档最底部),如图:

其中Name代表文件名;Version代表版本号;Locale代表语言文化,如果空,则表明是中性语言(neutral);Public Key则表示是公钥。

现在我们知道了程序集全部信息,图片中的public Key是完整的公钥而不是公钥标记。可以按照下面的过程得到公钥标记,

利用sn.exe程序的 -T参数
比如:

sn -T System.Data.dll

然后就可以看到如下的输出:

Microsoft(R) .NET Framework 强名称实用工具 版本 4.0.30319.17929
版权所有(C) Microsoft Corporation。保留所有权利。 公钥标记为 b77a5c561934e089

除此之外,若强命名程序集安装在GAC中的话,直接通过文件夹名称的后缀就可以看出:

5. 强命名程序集防篡改

用私钥对程序集进行签名,并将公钥和签名嵌入程序集,CLR就可验证程序集未被修改或损坏。程序集安装到GAC时候,系统对包含清单的那个文件内容进行哈希处理,将哈希值与PE文件中嵌入的RSA数字签名进行比较(在用公钥解除了签名之后)。如果两个值完全一致,表明文件内容未被篡改。此外,系统还对程序集的其他文件的内容进行哈希处理,并将哈希值与清单文件的FileDef表中存储的哈希值进行比较。任何一个哈希值不匹配,表明至少有一个文件被篡改,程序集将无法安装到GAC。

应用程序需要绑定到程序集时,CLR根据被引用程序集的属性(名称、版本、语言文化和公钥)在GAC中定位查找该程序集。如果被引用的程序集不在GAC中,CLR会查找引用程序的基目录,然后查找应用程序配置文件中的任何私有路径,如果还找不到就会抛出System.IO.FileNotFoundException成一行。

如果强命名程序集文件从GAC之外的位置加载(通过应用程序的基目录,或者通过配置文件中的codeBase元素),CLR会在程序集加载后比较哈希值。也就是说,每次应用程序执行并加载程序集时,都会对文件进行哈希处理,以牺牲性能为代价,保证程序集文件中的内容没有被篡改。

下面这张图可以帮助理解该流程:

通过这张图片可以清楚的看出,MyLibrary.dll文件进行强命名签名时,会把MyLibrary.dll文件进行哈希值处理,并且将结果值用秘钥进行处理,再将结果值嵌入到CLR头部中。把公钥嵌入到元数据中。

当MyLibrary.dll被加载时,程序会用清单中的公钥对CLR头中的数字签名进行解密操作,和再次对MyLibrary.dll进行哈希处理,然后比较这两个结果值,如果这两个值不一致的话,说明有文件已经被篡改,将会阻止运行。

【CLR】详解CLR中的程序集的更多相关文章

  1. 【转】详解C#中的反射

    原帖链接点这里:详解C#中的反射   反射(Reflection) 2008年01月02日 星期三 11:21 两个现实中的例子: 1.B超:大家体检的时候大概都做过B超吧,B超可以透过肚皮探测到你内 ...

  2. jQuery:详解jQuery中的事件(二)

    上一篇讲到jQuery中的事件,深入学习了加载DOM和事件绑定的相关知识,这篇主要深入讨论jQuery事件中的合成事件.事件冒泡和事件移除等内容. 接上篇jQuery:详解jQuery中的事件(一) ...

  3. 图文详解Unity3D中Material的Tiling和Offset是怎么回事

    图文详解Unity3D中Material的Tiling和Offset是怎么回事 Tiling和Offset概述 Tiling表示UV坐标的缩放倍数,Offset表示UV坐标的起始位置. 这样说当然是隔 ...

  4. 详解Webwork中Action 调用的方法

    详解Webwork中Action 调用的方法 从三方面介绍webwork action调用相关知识: 1.Webwork 获取和包装 web 参数 2.这部分框架类关系 3.DefaultAction ...

  5. 【转】详解JavaScript中的this

    ref:http://blog.jobbole.com/39305/ 来源:foocoder 详解JavaScript中的this JavaScript中的this总是让人迷惑,应该是js众所周知的坑 ...

  6. 深入详解SQL中的Null

    深入详解SQL中的Null NULL 在计算机和编程世界中表示的是未知,不确定.虽然中文翻译为 “空”, 但此空(null)非彼空(empty). Null表示的是一种未知状态,未来状态,比如小明兜里 ...

  7. java 乱码详解_jsp中pageEncoding、charset=UTF -8"、request.setCharacterEncoding("UTF-8")

    http://blog.csdn.net/qinysong/article/details/1179480 java 乱码详解__jsp中pageEncoding.charset=UTF -8&quo ...

  8. 详解Objective-C中委托和协议

    Objective-C委托和协议本没有任何关系,协议如前所述,就是起到C++中纯虚类的作用,对于“委托”则和协议没有关系,只是我们经常利用协议还实现委托的机制,其实不用协议也完全可以实现委托. AD: ...

  9. 举例详解Python中的split()函数的使用方法

    这篇文章主要介绍了举例详解Python中的split()函数的使用方法,split()函数的使用是Python学习当中的基础知识,通常用于将字符串切片并转换为列表,需要的朋友可以参考下   函数:sp ...

  10. 详解Java中的clone方法

    详解Java中的clone方法 参考:http://blog.csdn.net/zhangjg_blog/article/details/18369201/ 所谓的复制对象,首先要分配一个和源对象同样 ...

随机推荐

  1. 【BZOJ4927】第一题 双指针+DP

    题解: 虽然是过了,不过做的十分智障 首先是有 2根 2 1 1 , 3根 1 1 1 这两种方法 然后考虑2 2 1 1 two-point-two没啥好说的 3 1 1 1 我很智障的以为数据范围 ...

  2. 微信WebView关闭后本地cookie无法清除问题

    问题背景 在微信WebView下的页面中登录后,关闭WebView返回后再次进入页面,发现登录态还存在,原因是微信不会主动清除cookie以及其他的缓存. 期望是关闭窗口后会清除cookie,重新进入 ...

  3. 069 Hue协作框架

    一:介绍 1.官网 官网:http://gethue.com/ 下载:http://archive.cloudera.com/cdh5/cdh/5/,只能在这里下载,不是Apache的 手册:http ...

  4. QT学习之windows下安装配置PyQt5

    windows下安装配置PyQt5 目录 为什么要学习QT 命令行安装PyQt5以及PyQt5-tools 配置QtDesigner.PyUIC及PyRcc 为什么要学习QT python下与界面开发 ...

  5. Spring框架学习04——复杂类型的属性注入

    代码示例如下: 创建BeanClass实体类 public class BeanClass { private String[] arrs;//数组类型 private List<String& ...

  6. CSS之文本溢出隐藏,不定宽高元素垂直水平居中、禁止页面文本复制

    1.如何让不固定元素宽高的元素垂直水平居中 .center { position: absolute; top: 50%; left: 50%; background-color: #000; wid ...

  7. 漫谈可视化Prefuse(六)

    可视化一路走来,体会很多:博客一路写来,收获颇丰:代码一路码来,思路越来越清晰.终究还是明白了一句古话:纸上得来终觉浅,绝知此事要躬行. 跌跌撞撞整合了个可视化小tool,零零碎碎结交了众多的志同道合 ...

  8. Web前端性能优化进阶——完结篇

    前言 在之前的文章 如何优化网站性能,提高页面加载速度 中,我们简单介绍了网站性能优化的重要性以及几种网站性能优化的方法(没有看过的可以狂戳 链接 移步过去看一下),那么今天我们深入讨论如何进一步优化 ...

  9. 洛谷P1432 倒水问题(CODEVS.1226)

    To 洛谷.1432 倒水问题 题目背景 In the movie "Die Hard 3", Bruce Willis and Samuel L. Jackson were co ...

  10. 潭州课堂25班:Ph201805201 第十二课 new方法,定制属性访问,描述符与装饰器 (课堂笔记)

    1,new方法: 类每次实例化时都会创建一个新的对象, class Textcls: # cls 是指类本身, def __new__(cls, *args, **kwargs): # 在 __ini ...