关于VMProtect虚拟化函数到底要怎样去选择,还有虚拟化处理之后程序运行变慢了这个情况要怎么去处理,这个问题在软件保护做配置的时候,是一个需要被认真去权衡的事情。虚拟化这种技术,它是会把原生的那些机器指令,给转换成一堆由内置的虚拟机去负责执行的字节码,这样做,是能够把关键逻辑的分析难度给加上去的,可同时它也会带来一些额外的执行上面的开销。VMProtect这个东西,它还提供了像Mutation,还有Ultra这样子的几种编译类型,不一样的模式,它在保护的强度、程序体积的大小,还有运行起来的速度这些方面,相互之间都是有取有舍的,所以说,是不能把所有的函数,都给统一设成那种最高强度的虚拟化的。
一、VMProtect虚拟化函数怎么去选择
在去挑选函数的时候,这里面的重点,并不是说函数加得越多效果就越好,而是要去把那些真正对授权、业务规则,还有核心算法产生影响的关键代码给找出来。要是把初始化的过程、界面的刷新动作、文件目录的遍历操作,连同那些被高频次调用的计算循环,全都不加区分地拿去进行虚拟化处理,那么性能上头的损失,是会变得比较明显的,那些真正需要被重点保护起来的地方,反而就不容易突出出来了。
1、关键业务函数要被优先选择
在软件的那个【Functions】列表当中,那些负责对授权结果进行处理的,处在了核心算法入口位置上的,用来对关键配置信息进行解密的,还有承担着重要业务逻辑判断的函数,是要被优先挑出来的。
这些函数,一旦被绕过去,就会直接影响到软件保护所能起到的效果,对于那些被关键入口所调用的,普通的、起辅助性质的工具函数,就不一定全都需要去重复地做一遍虚拟化了。保护的范围要是铺得太大了,不但会把运行的速度给拖慢,跟着也会让测试和兼容性验证这一类的工作量变多。
2、高频循环和底层热路径要尽量被避开
图像编解码的处理、音频视频的编码转换、那种大规模的数组运算、实时的画面渲染、网络数据收发时的循环动作,还有那些会被频繁调用的短小函数,对于这些东西,是不太适合被直接施加很重度的虚拟化保护的。
这些指令在被虚拟化过后,是需要经过虚拟机去解释一次才能执行的,那些高频函数里面的开销,是会被调用发生的次数给不断地放大开来的。VMProtect官方的相关说明里头,也是在强调,说应当要针对不一样的对象,去给它选配合适的那种编译类型,要在代码的安全防护,跟实际的运行性能之间,想办法去求取一个平衡点才行。
3、照着风险的不同层次去挑选保护的类型
对于那些普通的、来自库里面的函数,或者只需要把代码的形态特征给变动一下的区域,是可以去考虑选用Mutation这种模式的;处在核心位置,但是对运行性能表现又很敏感的函数,可以先试着去用Virtualization;至于那些被调用的次数不太多,可是保护的要求却被提得很高的,用来做关键判断的函数,再接着去考虑Ultra这个级别的模式。
Ultra这个东西,它是会在做了变异处理的代码基础上面,再接着去进行虚拟化的,一般来讲,这么做所带出来的开销,是要比单单只用Virtualization来得更高的。不能因为看到某个函数它很重要,就不管三七二十一,直接连它自己,带它底下的全部调用链,都给一股脑地设成了同一种类型的保护模式。
二、VMProtect虚拟化后程序运行变慢要怎么办
程序在被处理过以后,一旦跑起来变慢了,就应当先被确定下来的事情是,发生耗时加剧的情况,是产生在软件刚启动的那个时候,还是出在了具体功能被执行的过程里面,又或者说是贯穿了整个的运转阶段,在不一样的位置上面所耗费时间,它对到的原因也是不相同的,处理的时候,不能光是想着通过把虚拟机的复杂度给降下来,就打算完事。
1、保护被加上前后的耗时状况要被拿来对比
先是要去把那个没有加保护的原程序,和保护处理过后的程序,它们在启动的那一下所花的时间、核心操作被做完的耗时、CPU被占用的比率,还有内存使用的变化,这些东西都给分别地记录下来,完了之后,再去看看到底是哪一处具体的功能,发生了明显的性能倒退。
如果只是在某个单一的操作上头变慢了,这种情况,往往就是那个功能它本身,或者是藏在它循环内部的东西被进行了虚拟化;要是变得是启动过程明显慢了下来,那就要动手去查一查程序的入口函数、静态初始化那部分、资源被加载的地方,还有启动阶段里头,保护范围是不是被划得太大了一些。
2、被虚拟化处理的代码范围要被缩小
回到【Functions】那边去,把那些并不是处在关键位置上的函数的虚拟化给勾掉取消掉,只留下一小部分真正核心的入口还保持着保护,完成这些之后,再去重新生成出来一份受到保护的执行文件,拿来跑一下测试看看。
如果在项目中是用了源代码标记的那种形式,在做标记的时候,那个开头和结束的标记位置,也要给安放在,确实是需要被保护起来的那一小块代码片段的边边上。VMProtect它是支持靠着SDK标记这个途径,去把单独的函数,或者是某一片代码区域给特别指定出来的,这种标记自己在保护处理的时候就会被拿掉移除了。
3、过大的函数还有循环结构要被拆开
要是在那个关键函数的内部,它既有授权逻辑的判断,又同时包含了大量的数据计算工作,那么,就可以考虑把那部分负责做关键判断的代码,拆分成一个单独的小函数,再对它去施加虚拟化,至于那部分负责处理数据,还有高频循环计算的代码,就让它们继续留在原生的状态下。
这样操作下来,比起把整段的函数都给一锅端地保护起来,在性能这个方面是要更加容易被控制住的。拆开完成了以后,还要当心一点,就是不要去让循环的里面,频繁地发生跑进虚拟化函数和跑出虚拟化函数的行为,要不然的话,光是函数调用出入边界的这个过程本身,也会形成一种持续不断的额外开销。
三、VMProtect在保护配置上要怎么把稳定性给兼顾到
对性能进行调整的时候,光盯着运行的速度看是不行的。虚拟化的覆盖范围被变动过了以后,接下来的事情,还要去把异常处理有没有效、多线程下面的情况、插件调用的表现,还有在不一样的系统环境里跑起来怎么样,都给重新验证上一遍,这么做,是为了防止被保护之后的程序,它会在使用的过程里,出现那种时有时无的崩溃,或者是在功能上产生差异。
1、保护的范围要被一步一步地加上去
在一开始,可以先只针对一个很关键的函数施加保护,等到性能和功能上的测试都给完成了,再去把下一个目标区域给添加上,千万不要一次性就选中一大串的函数,然后才去进行统一的大排查,要不然,等到卡顿的现象真出现了,到那个节骨眼上,是很难去把具体的来源给找清楚的。
2、多组的测试方案要被保留下来
是比较建议去分别建好这样三套配置方案的,一套是【基础保护】,一套是【关键函数虚拟化】,还有一套是【高强度保护】,这几套配置,要用一样的测试用例,去把运行的速度、生成文件的体积,还有稳定性,放到一块去进行比较。
用来做保护的工程文件,也一定要跟程序的实际版本给对应着保存好,这样才可以避免,在程序版本更新了之后,还在那里继续沿用着旧的函数地址,或者是老早以前用过的符号配置。
3、调用的频率和线程带来的影响要被检查
要借用性能分析的工具,去仔细看一看,那些被保护起来的函数,它们被调用的频次到底是多少,累积下来所花费的时间又有多少,有的函数它单次执行起来虽然只慢了一点点,但要是每一秒钟它都会被执行上几千次的话,那一样是有可能成为拖慢整个系统的一个主要瓶颈的。
对于多线程的程序,在做完虚拟化之后,还要再额外去观察一下,看看是不是出现了线程之间相互争抢资源,导致界面反应卡顿,或者是那些需要实时处理的任务,被延迟给耽误了的问题,不能只是简单地验证一下,看程序它能不能被正常启动起来就结束了。
总结
总的来讲,关于VMProtect虚拟化函数怎么选择,以及VMProtect虚拟化后程序运行变慢怎么办,这当中最为要紧的一条,就是把保护力量集中在授权判断、核心算法,还有关键业务入口这些东西上面,而避开那些高频的循环、实时的计算任务,以及数量庞大的普通辅助函数。程序一旦跑慢了,应该先通过性能的前后对比去把消耗的热点给找出来,然后再着手去把虚拟化的覆盖范围给缩小、把那种体量很大的函数给拆开,并且照着风险的不同,把Mutation、Virtualization,还有Ultra这三种模式给搭配起来使用。靠着一步一步地去做保护、分好组别来展开测试,还有把版本信息给记录清楚,这样的一种做法,才有办法在保护强度、运行性能,还有程序稳定性这三者之间,去摸到一个更加合理的平衡位置。
