"怎样保护我程序中的 DLL 不被别人盗用……"

当我看到这个问题的第一反应不是保护,而是满脑子的 IL 反编译代码。说实话,无论你用什么方法,都不能避免被有心人 "破解"。混淆也好,加壳也罢,不过是让别人多费些功夫而已。当然,这会大大缩减 "有心人" 的范围。要保护自己的 DLL 不被别人盗用,最好的办法是把它合并到 Entry EXE 中,然后无论是 public 还是 protected 都统统混淆(再加 n 层壳 ),这样自然没有 DLL 可供盗用了。(很遗憾,还是可以盗用的。使用 脱壳器 + dump 还原程序集,然后将 EXE 作为一个 Assembly 反射 Load 到程序域中调用执行,只不过要花点时间对付那些怪莫怪样的类型名称而已)

"你说的那些太复杂了,而且我不大熟悉混淆工具,听说容易出错…… 有没有简单点的方法…… 阻止普通人就行了…… 破解高手就算了吧……"

OK! 简单是吧?本文教的方法都简单到了极点,权作无聊时玩玩吧。

方法一. 调用验证

所谓调用验证,就是在 DLL 相关类型中验证调用者是不是某个特定的程序集,如果不是则抛出异常进行阻止。

核对 Entry Assembly Name,最好使用强签名,这样就不能简单通过相同程序集名冒充。

Code

另外一种情况是,这个 DLL 会被公司 n 个已知或未知的程序使用。我们自然不能把所有的 FullName 都写进去。解决方法是:判断 PublicKeyToken。通常一个公司的所有产品都会使用同一个签名密钥文件(snk/pfx),所生成的程序集 PublicKeyToken 都会相同。不要告诉我,你每个程序集的签名文件都是临时生成的…… [sad]

Code

这样,非法调用者无论是通过 "new MyClass()" 还是 "Activator.CreateInstance",都会抛出 TypeInitializeException。

如果你要保护的是整个 DLL,懒得为每个类型添加 .cctor 验证代码,可以将验证代码写到 <Module>.cctor 中,不过这有点麻烦。首先 ILAsm 反编译你的 DLL。

d:\temp> ildasm MyLib.dll /out:MyLib.il

然后用编辑器打开 MyLib.il,添加如下代码 (<Module>.cctor,IL 直接从 MyClass.cctor 中拷过来就行。如果 MyLib.dll 有 PublicKey,注意删除)。

Code

最后编译回去。

d:\temp> ilasm MyLib.il /dll /key=my.snk /optimize /out=MyLib.dll

<Module>.cctor 会在托管模块内任何成员或类型被调用前触发,所以完全能达到我们偷懒的目的。至于测试,就不需要我多说了吧。

我们既可以用 ILMerge 将 DLL 和 EXE 合并到一个 "标准程序集" 里面,也可以用类似 .NETZ 这样工具将 EXE 和 DLL 打包到到一个 "壳" 中。(有关 .NETZ 的原理,可参考 《.NETZ 原理分析 》)

ILMerge 演示

将 MyExe.exe 和 MyLib.dll 合并,输出新的程序集文件 MyExe2.exe

d:\temp> ILMerge /out:MyEXE2.exe /keyfile:my.snk MyExe.exe MyLib.dll

.NETZ 演示

.NETZ 的好处是 "壳" + "压缩",详细细节可参考软件帮助,或者源码。

Code

作者:Q.yuhen