介绍

文件认证模板是 Crane · 第二代加密引擎为魔方+用户提供的功能。

常见的“文件认证”包括:

  • 检测服务器 IP 是否正确
  • 检测服务器主机名是否正确
  • 检测网站的域名是否正确
  • 检测当前时间是否在某个范围之内
  • 使用其它方法检测文件是否允许运行

与传统的实现方法不同,使用文件认证模板的步骤为:

  1. 编写不含任何认证代码的源文件
  2. 编写文件认证模板
  3. 将两个文件上传魔方加密进行加密,加密时两个文件将会自动融合

通过使用文件认证模板功能,魔方加密会把认证代码 随机数量、随机位置 嵌入到源文件中。两个文件融合的过程类似于“埋地雷”,认证代码的数量、位置都是随机的、不可预测的。这就意味着,攻击者若想破解文件,必须要将文件中埋设的所有认证代码全部破坏,否则只要遗留一处,认证代码依然有效。

编写方法

文件认证模板是一个合法的 PHP 文件。

以下是一个文件认证模板的例子:

  1. <?php
  2. #inline-invoke
  3. if(0) {
  4. // 初始化检测
  5. }
  6. #inline-invoke
  7. if(0) {
  8. // 检测代码 1
  9. if($_SERVER['HTTP_HOST'] != '127.0.0.1') return;
  10. }
  11. #inline-invoke
  12. if(0) {
  13. // 检测代码 2
  14. if(getenv('HTTP_HOST') != '127.0.0.1') return;
  15. }
  16. #inline-invoke
  17. if(0) {
  18. // 检测代码 3
  19. if(empty($_SERVER['HTTP_HOST'])) return;
  20. }
  21. #inline-invoke
  22. if(0) {
  23. // 检测代码 4
  24. if(getenv('HTTP_HOST') != $_SERVER['HTTP_HOST']) return;
  25. }
  26. #inline-return
  27. if(0) {
  28. // 错误提示 1
  29. exit('<i>文件 ', basename(__FILE__), ' 必须运行在 127.0.0.1 的域名下</i>');
  30. }
  31. #inline-return
  32. if(0) {
  33. // 错误提示 2
  34. exit('<b>文件 ', basename(__FILE__), ' 必须运行在 127.0.0.1 的域名下</b>');
  35. }

可以看出,文件认证模板中分为多个块,块的结构为:

  1. #inline-???
  2. if(0) {
  3. // 具体的实现代码
  4. }

块以 #inline-??? 开头,开头标识了下面的 if(0) { ... } 内部的代码的用途。

  • 认证块 #inline-invoke

    认证块中的代码应当是实际的认证代码。如果有多种实现认证的方法,可以编写多个认证块,每个块中实现一种检测。

    认证失败请调用 return,魔方加密会随机选择一个错误提示块的内容替换 return 语句。

  • 错误提示块 #inline-return

    错误提示块中的代码用以提示用户文件不可运行,或者实现其它记录操作。

    请注意,无论错误提示块中的代码是否调用了 exit,块中的代码执行完毕后 PHP 脚本都会终止。

文件认证模板应该含有至少 1 个认证块和 1 个错误提示块。

加密时,融合的过程如下:

  1. 编译上传的文件认证模板,提取所有认证块和错误提示块
  2. 遍历处理所有的认证块,将认证块代码中的 return 语句使用一个随机的错误提示块代码进行替换
  3. 编译需要加密的源文件,将认证块代码、错误提示块代码融合后得到的 Opcode 按照一定的概率随机数量、随机位置插入源文件编译得到的 Opcode 中
  4. 根据合并后的 Opcode 生成最后的加密文件

效率改进

认证块会被随机插入到文件的任何位置,尤其当被插入到循环内部时,代码执行效率可能会严重下降。

使用编译杂注 #inline-ignore 可以提示编译器,不要在某个语句块中插入认证块。

  1. <?php
  2. #inline-ignore
  3. for($i = 0; $i < 10; $i ++) {
  4. // do something
  5. }

在以上的待加密示例代码中,for 循环前使用编译杂注 #inline-ignore,使得在 for 循环内部不会被插入任何认证块。

更多提示

  • 第一个认证块仅会插入文件和函数的开头,并不会随机插入其它位置,因此,初始化认证相关代码应当放置在第一个认证块中
  • 切勿在编写过于庞大的代码,这会导致加密文件体积巨大,且执行效率降低
  • 不要轻易相信 $_SERVER 中的数据,因为这个数组可以被篡改
  • 检测时间时注意考虑时差问题