程序接入VMProtect以后,真正影响运行速度的往往不是有没有保护,而是保护了哪些函数、用了哪种编译方式。一个只在启动时执行几次的授权判断,即使做虚拟化,对整体性能影响也有限;如果把高频循环、数据处理、渲染或持续回调函数大范围加入保护,运行时间就可能明显拉长。VMProtect本身允许按函数或代码片段设置Mutation、Virtualization和Ultra,实际配置时把关键逻辑和高频代码分开处理,会比整批函数使用同一种方式更稳妥。
一、VMProtect怎么保护代码函数
VMProtect可以按照函数名、PDB/MAP符号或源码标记确定保护范围。项目有源码时,优先把真正敏感的函数挑出来,后面重新编译时也比较容易维护。
1、从函数列表加入需要保护的代码
程序带有可识别的符号信息时,可以直接按照函数名称添加,不必手工计算地址。
①、打开【VMProtect】并载入需要处理的【EXE】或【DLL】。
②、进入【Functions for Protection】。
③、点击【Add Function】。
④、在【Functions】列表中搜索目标函数名称。
⑤、选中需要保护的函数并确认添加。
⑥、保存当前【VMProtect Project】。
2、用源码标记保护函数中的关键片段
①、在开发工程中加入【VMProtect SDK】。
②、在关键代码开始位置加入【VMProtectBeginVirtualization】、【VMProtectBeginMutation】或【VMProtectBeginUltra】。
③、在保护区域结束位置加入【VMProtectEnd】。
④、重新编译原始程序。
⑤、把新生成的【EXE】或【DLL】重新载入VMProtect。
⑥、检查【Functions for Protection】中识别出的Marker。
源码标记更适合函数比较长、但真正需要保护的逻辑只有其中一段的情况。这样不必把整个函数都交给保护模块处理。
3、根据函数特点选择Compilation type
①、选中【Functions for Protection】中的目标函数。
②、打开【Compilation type】。
③、对执行频繁、保护要求相对普通的函数选择【Mutation】。
④、关键判断或核心算法根据需求选择【Virtualization】。
⑤、对执行次数少且保护要求较高的代码片段再考虑【Ultra】。
⑥、点击【Compile】生成保护后的程序。
二、VMProtect函数保护后性能下降如何调整
VMProtect官方说明中,Mutation执行开销相对较轻,Virtualization会把代码转换为虚拟机字节码,Ultra还会在虚拟化前增加Mutation处理。程序变慢以后,可以先看哪些函数使用了Virtualization或Ultra,再结合调用频率缩小范围。
1、先找出是哪一个保护函数拖慢运行
一次保护很多函数时,不容易直接看出影响来自哪里,可以先做减法。
①、复制一份当前【VMProtect Project】作为测试工程。
②、进入【Functions for Protection】。
③、暂时关闭部分函数的保护。
④、只保留一个或一小组目标函数。
⑤、重新执行【Compile】。
⑥、按照相同操作路径运行保护后的程序。
⑦、逐批恢复保护函数并记录运行差异。
2、调整Virtualization和Ultra的使用范围
①、找出当前设置为【Ultra】的高频函数。
②、将测试对象改为【Virtualization】。
③、重新生成【Protected File】并运行相同任务。
④、仍然存在明显耗时时,再测试【Mutation】。
⑤、保留关键判断区域的虚拟化设置。
⑥、把普通计算和重复循环移出高开销保护范围。
Ultra本身包含Mutation和Virtualization,执行负担会比单独使用Mutation更重。对持续调用的代码,保护方式要和调用频率一起考虑。
3、缩小源码Marker覆盖的代码
有些性能问题并不是函数数量多,而是一对Marker把整段循环、文件处理或大量函数调用都包了进去。
①、打开加入【VMProtectBeginVirtualization】的源码位置。
②、找到真正需要隐藏的关键判断或计算代码。
③、把【VMProtectBeginVirtualization】移动到关键逻辑开始处。
④、把【VMProtectEnd】移动到关键逻辑结束处。
⑤、将循环外围、日志和普通数据处理留在保护区之外。
⑥、重新编译原程序并执行【Compile】。
4、重新编译程序后检查保护对象
①、重新生成当前程序使用的【PDB】或【MAP】文件。
②、载入新编译的【EXE】或【DLL】。
③、检查【Functions for Protection】中的函数名称。
④、确认保护对象仍然对应当前版本代码。
⑤、删除已经失效或不再需要的函数项。
⑥、保存新的【VMProtect Project】。
每次程序结构变化以后,函数地址也可能跟着变化。使用PDB、MAP或源码Marker维护保护范围,比长期依赖固定地址省事不少。
三、VMProtect函数保护调整后怎么验证
性能调整完成以后,不能只确认程序还能启动。保护范围缩小以后,关键代码有没有继续受到保护,原来的功能和运行时间有没有变化,都要再做一次对照。
1、用相同场景比较保护前后的运行情况
选一个能够稳定重复的操作场景来测试,数据更容易比较。
①、保留同一次构建生成的【Original File】。
②、使用调整后的工程生成【Protected File】。
③、分别运行两份程序的相同功能。
④、记录启动、计算或目标功能的执行时间。
⑤、重复测试被保护函数调用较多的操作。
⑥、出现明显差异时返回【Functions for Protection】继续检查。
2、保存已经验证的函数保护配置
①、保存当前【VMProtect Project】。
②、记录各函数使用的【Compilation type】。
③、保留当前使用的【PDB】或【MAP】。
④、整理源码中的【VMProtectBegin】系列Marker。
⑤、另存一份后续准备继续调整的工程。
以后程序增加新模块或者重新编译时,可以直接拿这份已经验证的配置作对照,不必重新判断每个函数之前采用了什么保护方式。
总结
VMProtect保护代码函数时,保护范围和执行频率往往要一起考虑。关键判断放进虚拟化区域比较合适,但频繁循环、持续计算这类代码如果大面积使用Ultra或Virtualization,性能变化会更明显。碰到保护后程序变慢,可以先缩小函数范围,再逐个调整编译方式,这样更容易找到真正带来耗时的位置。把已经测试过的保护工程和原始构建资料留好,后面程序版本变化时也方便继续调整。
