【CLR】详解CLR中的程序集
目录结构:
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中的程序集的更多相关文章
- 【转】详解C#中的反射
原帖链接点这里:详解C#中的反射 反射(Reflection) 2008年01月02日 星期三 11:21 两个现实中的例子: 1.B超:大家体检的时候大概都做过B超吧,B超可以透过肚皮探测到你内 ...
- jQuery:详解jQuery中的事件(二)
上一篇讲到jQuery中的事件,深入学习了加载DOM和事件绑定的相关知识,这篇主要深入讨论jQuery事件中的合成事件.事件冒泡和事件移除等内容. 接上篇jQuery:详解jQuery中的事件(一) ...
- 图文详解Unity3D中Material的Tiling和Offset是怎么回事
图文详解Unity3D中Material的Tiling和Offset是怎么回事 Tiling和Offset概述 Tiling表示UV坐标的缩放倍数,Offset表示UV坐标的起始位置. 这样说当然是隔 ...
- 详解Webwork中Action 调用的方法
详解Webwork中Action 调用的方法 从三方面介绍webwork action调用相关知识: 1.Webwork 获取和包装 web 参数 2.这部分框架类关系 3.DefaultAction ...
- 【转】详解JavaScript中的this
ref:http://blog.jobbole.com/39305/ 来源:foocoder 详解JavaScript中的this JavaScript中的this总是让人迷惑,应该是js众所周知的坑 ...
- 深入详解SQL中的Null
深入详解SQL中的Null NULL 在计算机和编程世界中表示的是未知,不确定.虽然中文翻译为 “空”, 但此空(null)非彼空(empty). Null表示的是一种未知状态,未来状态,比如小明兜里 ...
- 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 ...
- 详解Objective-C中委托和协议
Objective-C委托和协议本没有任何关系,协议如前所述,就是起到C++中纯虚类的作用,对于“委托”则和协议没有关系,只是我们经常利用协议还实现委托的机制,其实不用协议也完全可以实现委托. AD: ...
- 举例详解Python中的split()函数的使用方法
这篇文章主要介绍了举例详解Python中的split()函数的使用方法,split()函数的使用是Python学习当中的基础知识,通常用于将字符串切片并转换为列表,需要的朋友可以参考下 函数:sp ...
- 详解Java中的clone方法
详解Java中的clone方法 参考:http://blog.csdn.net/zhangjg_blog/article/details/18369201/ 所谓的复制对象,首先要分配一个和源对象同样 ...
随机推荐
- centos6.5上安装配置telnet服务
https://blog.csdn.net/wx5040257/article/details/78327915
- Shell 错误输出重定向
转自:https://www.cnblogs.com/vijayfly/p/6234575.html shell将标准错误输出重定向到 其他地方 经常可以在一些脚本,尤其是在crontab调用时发现如 ...
- BZOJ1965 [Ahoi2005]SHUFFLE 洗牌 快速幂
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1965 题意概括 对于扑克牌的一次洗牌是这样定义的,将一叠N(N为偶数)张扑克牌平均分成上下两叠,取 ...
- 项目的整体框架,以及Topology的设计
一:说明 1.项目的整体框架 2.Topology的设计 3.记录 0. 89.201.10.122 - - [1528033390201] "GET /edit.php HTTP/1.1& ...
- 洛谷 P1057 传球游戏 【dp】(经典)
题目链接:https://www.luogu.org/problemnew/show/P1057 题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏. 游 ...
- Hash值破解工具Hashcat使用
Hash值破解工具Hashcat使用 Hashcat介绍 HashCat系列软件拥有十分灵活的破解方式,可以满足绝大多数的破解需求. Hashcat系列软件是比较牛逼的密码破解软件,系列软件包含Has ...
- IE8 margin:0 auto 不能居中显示的问题
ie8下面margin:0 auto;不能居中的解决方案,ie8兼容性代码 今天写了个div,用margin:0 auto:来定义他的属性,让他居中,结果,竟然无效. 一开始以为是css里的代码冲突了 ...
- JavaScript_几种创建对象(2017-07-04)
理解对象 1.创建Object实例 var clock = new Object(); clock.hour = 12; clock.minute = 10; clock.showHour = fun ...
- webstorm更改字体大小
webstorm是一款不错的开发软件,一起来看看webstorm怎么更改字体大小. 1,打开该软件后,点击上面菜单栏的“文件”/File,找到其子菜单中的“设置”/Setting,点击打开. 2,在新 ...
- Codeforces Round #407 div2 题解【ABCDE】
Anastasia and pebbles 题意:你有两种框,每个框可以最多装k重量的物品,但是你每个框不能装不一样的物品.现在地面上有n个物品,问你最少多少次,可以把这n个物品全部装回去. 题解:其 ...