65.9K
CodeProject 正在变化。 阅读更多。
Home

PHP 混淆器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.74/5 (19投票s)

2006年8月10日

6分钟阅读

viewsIcon

159916

downloadIcon

9795

一个用C#为.NET 2.0编写的基础PHP混淆器。

Main Obfuscator Screen

引言

我最近在Raizlabs的一个项目中,需要将PHP软件作为试用演示版分发给客户。我们希望客户能在购买前体验软件。为了限制盗版,我们希望保护PHP代码本身。

我们研究了各种PHP源代码保护方案,包括其他开源编码器和混淆器,以及一些闭源字节码编译器。我们对字节码编译器的顾虑是,它们要么要求随应用程序一起分发额外的运行时可加载模块,要么要求安装Zend等服务器扩展。考虑到我们无法保证脚本将要安装的服务器的功能状态,我们放弃了任何涉及字节码编译的解决方案。

流行的开源混淆器无一例外地破坏了我们的源代码,或者要求我们修改源代码以适应混淆器。相比之下,用C#编写我们自己的混淆器要快得多,也不需要改变我们所有的PHP代码来遵循混淆器强加的任意代码指南。当然,我们自己的混淆器也由于我们自己的编码风格和内部PHP编码实践,对它能够混淆的代码施加了我们自己的指导方针。如果使用这个混淆器来编码你的PHP脚本,主要规则是它不理解HTML主体中声明的PHP变量。这意味着,如果你将你的输入标签命名为foo,你不能在你的PHP代码中使用$foo变量,除非它被PHP Obfuscator应用程序的用户明确排除。当然,解决这个问题的方法是为所有HTML输入变量使用$_REQUEST$_POST$_GET数组,因为即使脚本被混淆后,$_REQUEST[‘foo’]仍然是有效的。

背景

这个混淆器主要是为了编码一个名为PHP Email Manager的PHP软件而编写的。这个应用程序要求我们能够从混淆过程中排除各种文件和变量,以便支持config.php文件中的用户自定义配置。这个文件将为应用程序的其余部分设置变量,但重要的是这个文件要保持可读性,并且这个文件中声明的变量名在应用程序的其余部分保持不变。

混淆应用程序有三个主要部分

  1. PHP Obfuscator GUI,允许用户选择要编码的源代码,要排除的源代码,要排除的函数和变量,以及混淆首选项。可以从GUI执行混淆,也可以将混淆项目文件以XML格式持久化,供命令行工具使用。
  2. PHP Obfuscator命令行工具,允许用户自动化脚本到他们的构建流程中进行混淆。命令行工具接受的一个命令行参数是混淆项目文件的文件名,该文件由GUI创建。
  3. Obfuscator类,GUI和命令行工具都使用它来对目标PHP代码执行混淆。

使用代码

使用Obfuscator类是一个简单的过程,实例化一个Obfuscator类实例,并将一个ObfuscatorUI对象作为参数,然后调用StartObfuscatorUI是一个IObfuscatorUI的接口实现,它为混淆器提供了以下函数:StatusUpdate(String)Done()Error(string)。通过这三个函数,Obfuscator类可以在编码源代码的过程中向调用它的任何组件进行通信。

混淆器上Start函数。的第一个参数是一个ObfuscatorConfig对象。这个对象所做的只是实例化GUI在用户选择保存项目文件时持久化的类。PHP混淆器项目文件是一个持久化的ObfuscatorConfig对象,使用了内置的.NET XML序列化。

ObfuscatorUI ui = new ObfuscatorUI();
Obfuscator obfuscator = new Obfuscator(ui);
obfuscator.Start(config, false);

在上面的例子中,ObfuscatorUI UI对象是一个简单的类,在Program.cs中定义,它只是将混淆器返回的状态输出到控制台窗口。

/// <summary>
/// UI implimentation for the Obfuscation class.
/// Through this class we will recieve and handle events
/// </summary>
class ObfuscatorUI : Obfuscation.IObfuscatorUI
{
    #region IObfuscatorUI Members

    public void StatusUpdate(string status)
    {
        Console.WriteLine(status);
    }

    public void Done()
    {
        Console.WriteLine("Done.");
    }

    public void Error(string errorText)
    {
        Console.WriteLine("Error: " + errorText);
    }
    #endregion
}

对于主PHP混淆器UI,IObfuscatorUI接口的实现实际上是在应用程序的主Form类中完成的。

仅作说明:混淆器上Start函数的第二个参数是异步操作标志。这将决定你的源代码的混淆是同步进行(如命令行工具的情况)还是异步进行(如GUI的情况)。这使得任何使用此类GUI的应用程序在编码进行时都能保持响应。

在混淆过程中用于检测变量名、函数调用、函数声明、类声明和字符串的所有正则表达式都存储在混淆DLL的Settings类中。

编码工作原理

Obfuscator类有三个功能组件

  1. 编码变量名
  2. 编码函数名
  3. 移除空格

通过应用这三个功能,源代码变得有些难以阅读,但仍然完全功能正常。

当混淆过程开始时,如果目标目录已经存在,用户会被提示以便移除它。它的移除是必不可少的,因为这是将源目录中的每个文件复制并修改到其中的目录。目标目录将成为源目录层次结构的精确副本,除了对所有文件执行的编码之外。

创建目标目录后,从源目录到目标目录进行递归复制。所有文件都会被复制,无论它们是否被选中进行编码。复制每个文件是为了使目标目录中的最终结果是一个完整的解决方案,而不仅仅是编码后的文件。

一旦目标目录中存在所有未编码的文件,混淆就开始了。打开每个被选中的文件,并提取PHP代码块。PHP文件的HTML部分不应被处理。从每个代码块中,首先移除注释,然后重命名变量(从它们的原始名称创建MD5),然后移除空格。然后使用正则表达式检测这个代码块中的函数和类声明,并将它们添加到列表中,以便在所有选定文件的第二遍中重命名,前提是它们不与PHP内置的函数名列表匹配(参见phpFunctions类)。

在将上述过程应用于文件中的所有块之后,文件将使用替换后的PHP代码块被重写,然后我们继续处理下一个文件。在所有文件都处理完毕后,对文件进行第二遍处理,重命名我们在第一遍中检测到名称的所有检测到的函数调用和类实例化。

关注点

没有一种“正确”的方式来编码PHP文件用于分发;每个人都有自己的偏好和自己的技术。我们为非常具体的情况开发了最适合我们的方案;其他人会有更适合他们独特情况的技术。这只是适合我们的方案,我希望其他人也能发现它有用,也许还能增加它的功能。

© . All rights reserved.