目前加密壳将核心转移到Jit层后,内核模式的强度增加空间已经很小了。目前市面上的加密壳至少有一个共同的缺陷,无法防止Jit底层截获IL字节码。
有些壳采用从周边增加强度(如 Anti Hook),由于hook的多样性再加上壳又需要考虑自己的兼容性,所以这个效果不是十分理想。 从防止脱壳入手,通过保护局部变量签名和异常处理表,来阻止方法体的脱壳还原。这样虽然不能阻止截获IL字节码,如果配合流程混淆还是能起到相对有效的保护。 这样仍然有些遗憾,能实现阻止Jit层截获完整的IL字节码就完美了。
DNGuard HVM 核心就是为了实现这一点——Jit层中无法截获完整正确的IL代码,它将保护的粒度从原来的"每方法体"降低到"每操作码(HVM伪代码)" 。实际原理也有不同,在Jit编译处理过程中HVM伪代码不会直接还原为IL代码,而是由HVM运行库参与编译实现直接 HVM伪代码-》本地代码。实际上就是HVM核心实现了IL代码一个子集的编译功能。
效率问题: 如果普通ILCode也需要经过HVM核心处理判断一面,是否会造成性能损失? 这个问题没有,HVM核心是利用Win32的异常处理机制动态装载的。只有HVM伪代码才会触发HVM核心的装载。在一个HVM方法编译完成之后,HVM核心会自动卸载。
HVM代码的编译相比ILCode的编译,是否会造成性能损失? 答案是肯定的,HVM提供了一个强度选项,可设置1-5.指示对ILCode进行伪代码替换的比例。 例如设置为1时,只对函数调用指令进行替换。对于函数调用指令的编译实际上是很简单的。 默认设置3,是一个实际性能损失比较小的设置,和纯加密方式相比,基本上可忽略。
伪代码动态性: HVM代码是动态的,静态模式下(强度小于等于3)每个加密模块会有5+种不同方案。每个加密模块的方案各不相同。方案是由模块标识码 + 客户标识码 来动态生成的。 动态模式下,会在HVM核心中对代码进行二次处理,每个方法都会有一个动态的随机方案。 在Jit中截获的伪代码是动态随机的,各个方法中截获的伪代码没有必然的对应关系。