一般地,用.NET编写的程序集在发布前,通常需要对代码进行混淆和强签名,下面简要介绍一下程序集的混淆和强签名的步骤及在实际开发中的实施。
首先,需要创建一个公钥/私钥对。密钥如果有密码保护,则生成pfx文件,没有密码生成snk文件,pfx比snk文件较大些,在Visual Studio命令提示符下:
Sn -k Certify.snk
该.snk文件应该由专门人员用专门设备保存起来。
然后,运用如下命令,从该公私密钥对中,提取出公钥,公钥发给每一个开发人员。
sn -p Certify.snk Certify.public.snk
为了掩饰如何对程序进行签名和混淆,首先创建一个控制台应用程序,名为Sign.exe,为了更好地说明签名及混淆前后代码的变化,我们使用ILDASM来查看程序的原信息。如下图,运行ILDasm,然后载入生成的Sign.exe,然后选择“视图”|“元信息”|“显示!”或者直接按Ctrl+M组合键。
可以看到程序没有签名之前,Public Key是空的。
一般滴,在开发的时候采用延迟签名技术,所有的工程属性里面勾上延迟签名这一项,然后,指定签名的文件为上一步骤生成的公钥Certify.public.snk,并勾选延迟签名。
可以看到,延迟签名之后,程序是不能直接运行的,原因后面会解释,如果直接运行,会提示如下错误。
这个问题先放着,现在我们再使用ILDasm来查看元信息。
可以看到,程序集中,现在有Public Key了。
完成之后,不能直接运行的,我们需要使用SN的-Vr命令告诉CLR在加载我们的程序时,不要对哈希值进行检查:
SN.exe –Vr Sign.exe
告诉CLR,不要去验证程序集中的hash信息。该命令只需要执行一次即可。该操作只需要执行一次,目的是在本机的CLR上注册一下,不要验证程序集的安全性。
现在运行Sign.exe能够正常输出Hello Word,到这一步延迟签名算是完成了。
经过延迟签名之后,如果需要混淆的话,就需要对延迟签名后的程序集进行混淆,混淆能够保护源代码以提高反编译的难度。这种模糊处理并不改变程序执行的逻辑。为了演示混淆前后代码的变化,在混淆之前,我们使用Reflector对代码进行反编译一下。
可以看到,反编译还是非常完整的,基本就是我们在源代码里面输入的内容,而且方法名都是一样的。
现在我们使用微软推荐的DotConfucation来对代码进行混淆。如下图。
然后我们可以点击混淆后的程序,还是可以正常运行的。现在我们再使用Reflector来进行反编译一下:
可以看到,一些方法名称和类名名字被改了。这个程序很简单,如果一个程序复杂一点,效果就比较明显。
待所有的程序开发完成之后,进行混淆之后,发布之前。发布的管理人员,在使用之前生成的公/私钥对Certify.snk,对所有的dll进行统一的签名。
SN.exe -Ra Sign.exe Certify.snk
这样,所有的程序集就都是强签名的了,拥有了防篡改的安全性保护了。就是说如果使用弱名称,一些别有用心的人更改了dll之后,CLR不去验证完整性,导致程序运行会产生一些不确定性的结果。如果强名称,CLR每一次加载运行都回去验证程序集,如果哈希值和之前生成的公私钥不匹配,则认为程序已经被篡改,就会阻止运行。
之所以采用延迟签名是因为,一般公司生成的 公/私钥对(Certify.snk),其中私钥是严格保密,由专人保管存放在固定介质上的(一般放在保险箱中)。公钥(Certify.public.snk)就分发给开发人员。待程序开发完成之后,统一的使用私钥进行签名(因为生成的公/私钥对中只能提取公钥,私钥没法提取,所以这一步直接使用公/私钥对即可)
对于一些大的程序一般是分组分模块开发的。这样的话,需要从最底层的一些dll开始延迟签名,这些dll延迟签名后,引用这些dll的dll才能进行延迟签名。
本文简单得介绍了程序的混淆和强签名,以及在实际开发中的实施,一般地.NET程序集的签名和混淆的步骤为:延迟签名 -- 开发完成 -- 混淆 -- 重新签名 (即先延迟签名,混淆后再签名) ,希望本文对您了解.NET程序的混淆和签名有所帮助。