chrisvpearse/phpcrypter

PHP源代码加密器。

v0.1.1 2024-01-13 19:18 UTC

This package is auto-updated.

Last update: 2024-09-13 21:01:07 UTC


README

此开源软件包的目标是通过隐蔽性实现安全。

它旨在提供一种替代方案,用于在明文(plaintext)中交付您的闭源项目。相反,您可以选择以密文(加密)的形式交付它们,同时提供一个二进制PHP扩展,该扩展将即时解密它们。

此软件包使用对称加密,因此AES-256密钥(只有您作为开发者知道),可以每个项目/发布都是唯一的。为了避免被十六进制编辑器(例如Hex Fiend)和strings命令检测到,密钥以XOR密码的形式存储在二进制文件中,分成32部分。此外,XOR密钥也分成32部分。然后将所有64个密钥部分与64个随机密钥部分(总共128个部分)一起打乱,以确保AES-256和XOR密钥部分永远不会出现在同一位置两次。

为什么是加密而不是混淆(obfuscation)?

如果您搜索混淆软件包,几乎总是有一个互补的解混淆软件包可用(由其他人编写),这使得原始软件包过时(不幸的是)。另一方面,AES-256加密尚未被破解(尚无)!

话虽如此,我当然会考虑混淆作为加密的补充。如果您的源代码首先(在加密之前)被混淆,然后有人试图通过查看操作码并逐步执行来逆向工程您的项目,那么将更加困难。

通常,混淆侧重于更改源代码的执行流程,并结合对类、方法、函数、变量和字符串字面量的名称进行混淆。由于混淆本质上重写了您的代码,因此不可避免地会带来一些“陷阱”。另一方面,加密则保留了您的代码(与您编写的一模一样)。

要求

macOS/Linux

  1. PHP ^8.2
  2. phpize

Windows

此软件包考虑到对Windows的支持,但尚未进行测试。

安装

以下假设您目前处于应用程序的根目录。

$ composer require chrisvpearse/phpcrypter --dev

用法

生成密钥

$ ./vendor/bin/phpcrypter generate [--clean] [--] <name> [<payload>]

以下命令将生成一个唯一的AES-256-CBC对称密钥,名为foo

$ ./vendor/bin/phpcrypter generate foo

此外,将在应用程序的根目录中创建一个.phpcrypter/foo目录,其中包含PHP扩展骨架。对称密钥是骨架的❤️ - 它们都将用于稍后构建同名的二进制PHP扩展(foo.so)。

一个好的经验法则是每个项目一个密钥(因此一个PHP扩展)。

上述命令的输出将类似于以下内容

Success!
Payload: pAYL0AD==

❗ 请记住将/.phpcrypter添加到您的.gitignore文件。

‼️ 此外,保存负载到密码管理器(如1Passwordpass)非常重要。

构建PHP扩展

macOS/Linux

$ cd .phpcrypter/foo
$ phpize
$ ./configure
$ make
$ make install

上述命令将构建一个名为 foo.so 的 PHP 扩展,并将其复制到您的 PHP 扩展目录中。您可以通过以下命令找到该目录:

$ php -i | grep ^extension_dir

接下来,您应该将以下行添加到您的 php.ini 配置文件中:

extension=foo.so

加载的 php.ini 配置文件的路径可以通过以下命令找到:

$ php -i | grep "Loaded Configuration File"

接下来,验证扩展是否已 加载

$ php -m | grep foo
foo

加密目录和/或文件

$ ./vendor/bin/phpcrypter encrypt <payload> <path>...

以下命令可以一次性加密多个目录和文件。您必须指定之前获得的 payload 作为第一个参数。

$ ./vendor/bin/phpcrypter encrypt "pAYL0AD==" \
  "dir-1" \
  "dir-2" \
  "file-1.php" \
  "file-2.php"

❗ 在上述路径中找到的任何 PHP 文件的内容将被覆盖。强烈建议您为这些文件创建一个新的 Git 分支。

$ git checkout -b encrypted

解密

如果您只是进行实验,能够随意加密和解密很有用。以下命令可以解密使用 payload 参数先前加密的任何目录和/或文件。

$ ./vendor/bin/phpcrypter decrypt <payload> <path>...

❗ 再次提醒,上述路径中找到的任何 PHP 文件的内容将被覆盖。

加密文件看起来像什么?

<?php // @foo
if (! extension_loaded('foo')) exit('The "foo" extension is not loaded');
#pAYL0AD==

PHP 代码块应该是自解释的,然而,最后一行包含一个 base64 编码的字符串,其中包含 phpcrypter 版本、IV(初始向量)和加密源代码。

它是如何工作的?

默认情况下,当扩展 加载 时,它只是钩入 PHP 的内部结构,即 zend_compile_file() 函数,但它不执行任何操作,除非将 foo.decrypt 配置选项设置为 1(默认设置为 1)。

如果您在 php.ini 配置文件中将 foo.decrypt 设置为 0,建议您在任何包含/要求加密文件的未加密 PHP 文件中使用 ini_set('foo.decrypt', 1)。例如,如果您想加密一个控制器,您应该在未加密的基本控制器中使用 ini_set()。您不能在加密的 PHP 文件中使用 ini_set(),因为 zend_compile_file() 的工作级别更低。

以下是autocannon 基准测试(10 个连接,持续 10 秒):

部署

当您准备部署加密文件时,如果您的工作站平台与目标平台不同(例如,Linux 与 macOS),则应构建适用于该平台的应用程序扩展。

全局安装

如果您需要在同一服务器上安装多个扩展(用于不同的项目),应考虑全局安装 phpcrypter

$ composer global require chrisvpearse/phpcrypter

使用带有有效载荷的 PHP 扩展骨架

您必须指定之前获得的 payload 作为第二个参数,以便相同的密钥也成为此骨架的 ❤️。

$ cd ~/.composer

$ export HISTCONTROL=ignorespace
$  ./vendor/bin/phpcrypter generate foo "pAYL0AD=="
$ unset HISTCONTROL

💡 使用 HISTCONTROL=ignorespace 可以防止带有前缀空格的任何命令出现在您的 shell 历史记录中。

再次构建 PHP 扩展

您应该参考上一节,遵循适用于该特定平台的适当步骤。

部署

您现在可以部署您的加密 PHP 文件了!🚀

鸣谢

许可证

MIT 许可证(MIT)。