当我看到这个问题的第一反应不是保护,而是满脑子的 IL 反编译代码
"你说的那些太复杂了,而且我不大熟悉混淆工具,听说容易出错…… 有没有简单点的方法…… 阻止普通人就行了…… 破解高手就算了吧……"
OK! 简单是吧?本文教的方法都简单到了极点,权作无聊时玩玩吧。
方法一. 调用验证
所谓调用验证,就是在 DLL 相关类型中验证调用者是不是某个特定的程序集,如果不是则抛出异常进行阻止。
核对 Entry Assembly Name,最好使用强签名,这样就不能简单通过相同程序集名冒充。
另外一种情况是,这个 DLL 会被公司 n 个已知或未知的程序使用。我们自然不能把所有的 FullName 都写进去。解决方法是:判断 PublicKeyToken。通常一个公司的所有产品都会使用同一个签名密钥文件(snk/pfx),所生成的程序集 PublicKeyToken 都会相同。不要告诉我,你每个程序集的签名文件都是临时生成的……
这样,非法调用者无论是通过 "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,注意删除)。
最后编译回去。
<Module>.cctor 会在托管模块内任何成员或类型被调用前触发,所以完全能达到我们偷懒的目的。至于测试,就不需要我多说了吧。
我们既可以用 ILMerge 将 DLL 和 EXE 合并到一个 "标准程序集" 里面,也可以用类似 .NETZ 这样工具将 EXE 和 DLL 打包到到一个 "壳" 中。(有关 .NETZ 的原理,可参考 《.NETZ 原理分析 》)
ILMerge 演示
将 MyExe.exe 和 MyLib.dll 合并,输出新的程序集文件 MyExe2.exe
.NETZ 演示
.NETZ 的好处是 "壳" + "压缩",详细细节可参考软件帮助,或者源码。
作者:Q.yuhen