默认情况下, 微软C#编译器产生的代码都是安全的, 安全的代码可以通过验证的代码. 然而, 微软C#编译器允许开发者编写不安全的代码, 不安全的代码允许直接访问内存地址, 能直接操作这些地址对应的字节. 这是非常强大的功能, 当与非托管的代码互操作或者你想提高实时算法的性能时, 这是非常有用的功能.
然而, 使用不安全的代码将会导致重大的风险: 不安全的代码会破坏数据结构, 产生或者打开安全漏洞. 基于这个原因, C#编译器需要包含不安全代码的所有的函数用unsafe关键字标记. 此外, C#编译器要求你用/unsafe编译开关编译源代码.
当JIT编译器尝试编译一个不安全的函数时, 它会检查包含这个函数的程序集是否赋予System.Security.Permissions.SecurityPermission为SkipVerification标记集, 如果这个标记被设置了, 那么JIT编译器将会编译不安全的代码并允许其执行, CLR才会相信这个代码, 相信直接地址和字节操作不会造成伤害. 如果这个标记没有设置, 那么JIT编译器将会抛出异常: System.InvalidProgramException 或者System.Security.VerificationException, 从而阻止这个方法的执行. 实际上, 整个应用程序可能会终止, 但是至少不会产生危害.
>>注意: 默认地, 在用户的计算机上显示地安装程序集非赋予完全的可信度, 这意味着它们能做任何事情, 包括执行不安全的代码. 然而在默认情况下, 来自局域网或者Internet的程序集不能执行不安全的代码, 如果它们包含这不安全的代码, 将抛出一个aforementioned异常. 管理员和终端用户可以改变这个默认设置, 然而, 管理员对代码的行为负全责.
微软提供了一个工具PEVerify.exe, 它能检查一个程序集的所有函数, 然后通知你包含不完全代码的任何函数. 你或许会想到对你所引用的程序集运行PEVerify.exe, 它将告诉你通过局域网或者Internet运行你的应用程序是否存在着问题.
你应该注意到验证过程需要访问程序集的metadata, 所以当你使用PEVerify来检查一个程序集时, 它必须能找到和载入所有被引用的程序集. 因为PEVerify使用CLR来定位依赖的程序集, 所以定位这些程序集所用到的绑定(bind)和探测(probe)规则和执行程序集时的规则相同. 我将在第2章和第3章讨论这些绑定和探测规则.
IL和知识产权保护
有人说IL没有为他们的算法提供足够的知识产权保护, 他们认为你build了一个托管的模块, 其他人可以使用像IL 反汇编器的工具, 很容易反编译出托管模块中的代码.
是的, IL代码确实比其他大多数汇编语言高级, 一般来说, 反汇编IL代码相对来说比较简单. 然而, 当实现服务器端代码(例如Web服务, Web表格, 或者存储过程)时, 你的程序集位于你的服务器上, 因为在你公司之外没人能访问你的程序集, 没人能使用任何工具看到IL——你的知识产权是非常安全的.
如果你关心你发布的任何程序集, 你可以从第三方获得一个obfuscator工具, 这个工具能”搅乱”程序集的meadata内所有私有符号的名称. 其他人很难破译被”搅乱”的名称并理解每个方法的含义. 注意这些obfuscator工具只能提供一点保护, 因为IL必须被CLR使用, 让JIT编译它.
如果你觉得obfuscator不能提供你所需要的知识版权保护, 你可以考虑用非托管的模块来实现敏感的算法, 这些非托管的模块包含着native CPU指令, 而不是IL和metadata. 然后, 你可以使用CLR的集成功能(假设你有足够的许可)来在托管和非托管的模块进行通讯. 当然, 这假设了你不担心其他人对你的非托管代码中的native CPU指令进行反工程.
将来, 微软将提供一个数字版权管理(DRM)解决方案来保护程序集内包含的IL代码.