给程序配置保护时,有些计算密集的代码需要保留原有执行方式,有些业务函数则希望单独做虚拟化处理。Themida中,这两类需求主要涉及保护宏的范围和启用状态,不能简单理解为把函数放进一个“排除列表”。如果指定函数看起来没有变化,还要确认它是否进入本次构建、是否被正确识别,以及检查的是不是新生成的文件。
一、Themida怎么设置保护排除项
这里讨论的是让某段代码不参与指定的宏保护或虚拟化,不代表取消程序文件的其他保护。以下使用Themida英文界面名称。
1、在保护宏列表中调整范围
①载入目标程序,打开【Protection Macros】,查看已经识别到的保护块。
②选中准备排除的条目,在下方查看汇编范围,确认它对应需要保留原执行方式的代码。
③在【Protection Macros】中禁用该保护块,再检查其他需要保护的条目是否仍处于启用状态。
④重新生成保护文件,运行涉及该代码的功能,观察行为和耗时。
禁用保护块适合临时定位兼容性问题,也可以帮助比较性能影响。但整个块被禁用后,其中的其他代码也会受到影响。如果只想排除循环中的一小段,应回到源代码重新划分宏范围。
2、使用MAP文件选择或移除函数
没有在源代码中插入保护宏时,可以通过MAP文件选择函数。MAP必须与当前二进制来自同一次构建。
①在【Protection Macros】点击【Select from MAP file】,载入配套MAP文件。
②在函数列表中选择需要保护的函数;已经加入的函数,可以通过相应条目移除。
③返回【Protection Macros】,逐项检查实际加入的范围,不要只凭函数名判断选择是否正确。
④保存工程设置,再生成输出文件进行验证。
UNPROTECTED_START和UNPROTECTED_END不能用来表示“这段代码正常运行,但不做虚拟化”。它们标记的代码在保护后会被跳过并破坏原内容,适用于不同用途。仅仅想保留性能敏感代码时,不应把它们当作普通排除宏使用。
二、Themida指定函数未受到保护如何检查
先看Themida是否识别到了目标,再判断保护是否生效。函数没有列入处理范围,与处理后仍能看到部分原生指令,是不同的问题。
1、确认载入的是本次构建
①在Themida中核对输入程序的位置,确认不是另一个目录里的旧版EXE或DLL。
②使用MAP选择函数时,通过【Select from MAP file】重新载入本次构建生成的文件。
③在【Protection Macros】中查看函数地址和汇编内容,与当前程序的实际实现对应起来。
④生成后打开输出文件的【属性】,核对路径和修改时间,再进行后续检查。
重新编译后,函数地址可能变化。旧MAP里即使还能搜到同名函数,也不能证明地址仍然有效。
2、检查目标条目是否被禁用
①在【Protection Macros】找到目标保护块,确认它没有保留上次排查时的禁用状态。
②打开【Select from MAP file】,检查目标函数是否确实被选中,而不是仅仅出现在可选列表中。
③查看本次保护日志,确认目标块是否被处理,并阅读与它有关的警告或失败信息。
④如果工程同时使用源代码宏和MAP选取,核对范围是否重复,避免同一段代码被两种方式交叉覆盖。
排查过程中暂时禁用的条目,容易随工程一起保存下来。重开工程后看见函数名称,不等于它仍在参与保护。
3、检查宏标记是否完整保留下来
源码中写了宏,不代表编译后的文件里一定存在完整标记。条件编译、提前返回以及编译器优化,都可能改变结果。
①检查目标源文件是否参与当前构建,以及插入宏的代码是否被条件编译排除。
②核对START与END标记是否配对,避免把END放在return之后等不可达位置。
③在【Protection Macros】中查看识别出的汇编范围,确认业务代码确实位于标记之间。
④如果提示END缺失或宏嵌套,先检查控制流和优化影响,必要时对相关函数局部关闭优化后重新构建。
⑤标记恢复识别后,再逐步恢复编译设置,确认问题出现在哪一步。
关闭整个工程的优化可以帮助做对照,但不宜用它替代定位。尤其是尾调用等优化造成的标记问题,应结合所用编译器和Themida版本处理。
4、确认保护覆盖的是函数体还是调用位置
①在【Protection Macros】中选中调用者,查看范围内是否只有一次函数调用。
②如果需要保护被调用函数的实现,为该函数单独设置保护宏,或通过【Select from MAP file】选择它。
③区分VM与MUTATE等处理方式,再判断生成代码是否符合所选方式。
④字符串仍可见时,检查【Protection Options】中的字符串选项,并查看【Protection Macros】下的【Ansi Strings】、【Unicode Strings】。
调用位置位于VM宏内,不会自动让外部被调用函数的整个函数体虚拟化。MUTATE处理后仍是原生机器码,也不能用“还能看到汇编”认定保护失效。字符串是否加密则需要另外核对。
三、Themida保护范围怎么兼顾性能和验证
函数不必一律采用相同处理方式。频繁执行的循环和偶尔调用的业务判断,对运行时间的要求可能相差很大。
1、把性能敏感部分单独划出来
①测量原程序中目标功能的耗时,确认时间主要消耗在哪个函数或循环。
②将不准备虚拟化的热点代码放到保护宏范围之外,在需要保护的业务片段周围重新安排标记。
③重新构建后打开【Protection Macros】,核对新的边界,再生成文件复测。
④如果程序行为变化,逐块禁用进行对照,找到相关范围后检查代码结构及当前版本的支持限制。
只看函数名称,很难判断它适合怎样保护。一次调用内部执行大量循环的函数,也可能是性能热点,需要结合实际耗时作决定。
2、给排除项留下可追查的理由
①保存工程前,在【Protection Macros】中复查暂时禁用的条目,区分测试设置和准备保留的设置。
②记录排除原因、涉及功能及验证结果,并保留配套二进制和MAP文件。
③发布前使用最终输出完成回归测试,确认功能路径没有因保护范围调整而遗漏。
总结
Themida允许按代码范围安排保护,适合在业务逻辑、运行性能和兼容性之间作具体选择。排除一个保护块,意味着需要清楚它包含什么;判断函数是否受到保护,也要结合识别范围、处理方式和本次输出,不能只看文件体积或几条汇编。希望这些内容能帮助大家把保护范围设置得更明确,遇到指定函数未生效时,能够沿着构建和处理记录找到原因。如果后续有相关需求,欢迎联系我们咨询了解。
