在 per method 的dotNet加密中首要解决的方法体对应关系即在运行时加密壳如何确定当前要解密的方法体所对应的加密信息
目前大部分加密壳都直接利用了dotNet的元数据来保存这种对应关系我们知道在元数据中每个方法都会对应一个RVA值加密壳可以直接把这个关系记录在RVA的地址处在框架运行中RVA处的数据会被作为方法体在处理流程中直接传递加密壳通过拦截框架处理流程中的函数来对方法体进行分流处理即先判断RVA处的数据是否方法体加密对应信息如果是进入加密壳运行库的内部处理不是则按原框架流程处理
对于这个方法体加密对应信息最简单的方式是指记录一个指针信息指向另一处数据块四字节空间就够了但是为了和普通没有加密的方法体进行区分除了这个之外还需要增加一些唯一标识以便能被运行库在运行时安全无误的区分出来
大家可以用UE打开加密后的程序集看看一个方法体RVA处的数据应该能很容易分别出来哪些是记录的方法体加密对应信息
正是这个原因所以DNGuard v和同类处理方式的加密壳对方法体小于某个指定字节数的就不能进行加密
因为方法体加密对应信息的大小超过的方法体的空间大小写入的话会覆盖到后面方法体的信息这实际上也是因为偷懒造成的可以通过对方法体进行重排来解决这个问题当然要麻烦很多了
这种模式实际上就是在元数据保存了一个虚拟表实现了 MethodToken => 方法体加密对应信息 的对应记录这个表可以看着是公开的
在DNGuard 中我没有选择使用对方法体重排的方式来解决这个问题而是选择了另一个方法自己记录一个 虚拟表实现MethodToken => 方法体加密对应信息 的对应记录
因为这样有一个好处就是 这个虚拟表也可以进行加密后保存另外就是方法体加密对应信息中不需要添加标识符 和普通没有加密的方法体进行区分
在 DNGuard 试用版 中没有使用真正的加密算法来对程序集加密只是采用了代码直接挪位的方式运行库的解密操作只是从另一个位置直接读取的操作
有个朋友分析到DNGuard 试用版里面有一个虚拟表记录了MethodRid => ILCode这个就是 虚拟表MethodToken => 方法体加密对应信息 在 试用版中退化的模式
另外因为方法体只是挪位所以它实际上还是在程序集文件内加载到内存中后也在程序集模块的内存空间中而不是那位朋友说的 运行库在解密后将 IL代码 填回到内存里面去了
试用版只是提供给用户验证 DNGuard 是否适合自己的软件项目以及系统发布环境请不要用试用版 加密程序集后直接分发