PHP中的代码混淆与去混淆:基于AST操作的防御与逆向工程

PHP代码混淆与去混淆:基于AST操作的防御与逆向工程

大家好,今天我们来深入探讨PHP代码混淆与去混淆技术,重点关注基于抽象语法树(AST)的操作。代码混淆旨在增加代码的复杂性,使其难以理解和逆向工程,从而保护知识产权。而相应的,去混淆则是逆向混淆的过程,试图恢复原始代码的可读性和逻辑。我们将从混淆技术入手,分析其原理和实现,然后讨论相应的去混淆策略,并结合代码示例进行说明。

代码混淆技术及其原理

代码混淆并非加密,它不会阻止代码执行,而是通过各种变换使代码更难阅读和理解。常用的混淆技术包括:

  1. 变量名和函数名替换: 将有意义的变量名和函数名替换为无意义的短字符串或随机字符串,降低代码的可读性。

  2. 字符串加密/编码: 对字符串进行加密或编码,使其在静态分析时不可见。运行时再进行解密/解码。

  3. 控制流平坦化: 将代码块的控制流打乱,使其不再按照线性顺序执行,增加代码逻辑的复杂性。

  4. 不透明谓词插入: 插入始终为真或始终为假的条件判断,扰乱代码的逻辑结构。

  5. 垃圾代码插入: 插入对程序执行没有影响的无用代码,增加代码量和复杂度。

  6. 指令替换: 将简单的操作替换为复杂的等效操作,例如将$a + $b替换为$a - (-$b)

  7. 资源混淆: 对图片,配置文件等资源进行混淆处理,增加逆向难度。

这些混淆技术可以单独使用,也可以组合使用,以达到更好的混淆效果。接下来,我们将针对其中几种常用的技术,结合AST操作进行详细讲解。

基于AST的变量名和函数名替换

AST(Abstract Syntax Tree,抽象语法树)是源代码的树形表示,它反映了代码的语法结构。通过操作AST,我们可以精确地修改代码的各个部分,而无需进行字符串级别的替换,从而避免引入语法错误。

PHP的nikic/php-parser库提供了一个强大的AST解析和操作工具。我们可以使用它来解析PHP代码,遍历AST,并替换变量名和函数名。

示例代码:

<?php

require 'vendor/autoload.php';

use PhpParserParserFactory;
use PhpParserNodeTraverser;
use PhpParserNodeVisitorAbstract;
use PhpParserNode;
use PhpParserPrettyPrinter;

// 自定义NodeVisitor,用于替换变量名
class VariableNameReplacer extends NodeVisitorAbstract {
    private $variableMap = [];

    public function enterNode(Node $node) {
        if ($node instanceof NodeExprVariable) {
            $originalName = $node->name;

            // 检查是否已经替换过
            if (isset($this->variableMap[$originalName])) {
                $node->name = $this->variableMap[$originalName];
                return null;
            }

            // 生成新的变量名
            $newName = 'var_' . md5($originalName);
            $this->variableMap[$originalName] = $newName;
            $node->name = $newName;

            return null;
        }

        if ($node instanceof NodeExprAssign) {
            // 处理赋值语句中的变量,确保左侧和右侧的变量名一致
            if ($node->var instanceof NodeExprVariable) {
                $originalName = $node->var->name;
                if (isset($this->variableMap[$originalName])) {
                    $node->var->name = $this->variableMap[$originalName];
                } else {
                     $newName = 'var_' . md5($originalName);
                     $this->variableMap[$originalName] = $newName;
                     $node->var->name = $newName;
                }

            }
        }

        return null;
    }
}

// 自定义NodeVisitor,用于替换函数名
class FunctionNameReplacer extends NodeVisitorAbstract {
    private $functionMap = [];

    public function enterNode(Node $node) {
        if ($node instanceof NodeStmtFunction_) {
            $originalName = $node->name->name;

            // 检查是否已经替换过
            if (isset($this->functionMap[$originalName])) {
                return null; // 避免重复替换函数定义
            }

            // 生成新的函数名
            $newName = 'func_' . md5($originalName);
            $this->functionMap[$originalName] = $newName;
            $node->name = new NodeIdentifier($newName);

            return null;
        }

        if ($node instanceof NodeExprFuncCall) {
            if ($node->name instanceof NodeName) {
                $originalName = $node->name->toString();

                if (isset($this->functionMap[$originalName])) {
                    $node->name = new NodeName($this->functionMap[$originalName]);
                }
            }
            return null;
        }
        return null;
    }
}

// 待混淆的PHP代码
$code = <<<'PHP'
<?php

function calculateSum($a, $b) {
    $sum = $a + $b;
    return $sum;
}

$x = 10;
$y = 20;
$result = calculateSum($x, $y);

echo "Result: " . $result;

?>
PHP;

// 解析PHP代码
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
$ast = $parser->parse($code);

// 创建NodeTraverser并添加NodeVisitor
$traverser = new NodeTraverser;
$traverser->addVisitor(new VariableNameReplacer);
$traverser->addVisitor(new FunctionNameReplacer);

// 遍历AST并进行替换
$ast = $traverser->traverse($ast);

// 将AST转换回PHP代码
$prettyPrinter = new PrettyPrinterStandard;
$obfuscatedCode = $prettyPrinter->prettyPrintFile($ast);

// 输出混淆后的代码
echo $obfuscatedCode;

?>

代码解释:

  1. 首先,我们使用nikic/php-parser库解析PHP代码,将其转换为AST。
  2. 然后,我们创建两个自定义的NodeVisitor,分别用于替换变量名和函数名。
  3. VariableNameReplacer类遍历AST,找到NodeExprVariable类型的节点,将其name属性替换为新的变量名。 为了避免重复替换,使用$variableMap存储已经替换过的变量名。 同时处理NodeExprAssign节点,确保赋值语句中变量名一致。
  4. FunctionNameReplacer类遍历AST,找到NodeStmtFunction_类型的节点,将其name属性替换为新的函数名。同时,也处理NodeExprFuncCall,替换函数调用中的函数名。为了避免重复替换函数定义,使用$functionMap存储已经替换过的函数名。
  5. 最后,我们使用PrettyPrinterStandard类将AST转换回PHP代码,并输出混淆后的代码。

混淆效果:

原始代码:

<?php

function calculateSum($a, $b) {
    $sum = $a + $b;
    return $sum;
}

$x = 10;
$y = 20;
$result = calculateSum($x, $y);

echo "Result: " . $result;

?>

混淆后的代码:

<?php

function func_79132c5a9a68460b50a19c41c389c3f3(var_356a192b7913b04c54574d18c28d46e6, var_da4b9237bacccdf19c0760cab7aec4a8)
{
    $var_a947e47047c1c0ad4e4216f3b1727495 = var_356a192b7913b04c54574d18c28d46e6 + var_da4b9237bacccdf19c0760cab7aec4a8;
    return $var_a947e47047c1c0ad4e4216f3b1727495;
}
$var_6f39f657d9456ead1c47b8f9689a3290 = 10;
$var_d72aa81509f410a0b27c454469c13a56 = 20;
$var_65a555a6e258c61094e6d72a526d1c76 = func_79132c5a9a68460b50a19c41c389c3f3(var_6f39f657d9456ead1c47b8f9689a3290, var_d72aa81509f410a0b27c454469c13a56);
echo "Result: " . $var_65a555a6e258c61094e6d72a526d1c76;

可以看到,变量名和函数名都被替换成了无意义的字符串,降低了代码的可读性。

字符串加密/编码

字符串加密/编码是一种常用的混淆技术,它可以隐藏代码中的敏感信息,例如数据库密码、API密钥等。

示例代码:

<?php

require 'vendor/autoload.php';

use PhpParserParserFactory;
use PhpParserNodeTraverser;
use PhpParserNodeVisitorAbstract;
use PhpParserNode;
use PhpParserPrettyPrinter;

// 自定义NodeVisitor,用于加密字符串
class StringEncrypter extends NodeVisitorAbstract {
    private $encryptionKey = 'my_secret_key';

    public function enterNode(Node $node) {
        if ($node instanceof NodeScalarString_) {
            $originalString = $node->value;
            $encryptedString = $this->encrypt($originalString, $this->encryptionKey);
            // 将加密后的字符串替换为一个函数调用,该函数负责解密字符串
            $node->value = 'ENCRYPTED_STRING_' . md5($originalString); // 使用唯一标识符,便于解密
            return new NodeExprFuncCall(
                new NodeName('decryptString'), // 假设存在一个名为 decryptString 的函数
                [
                    new NodeArg(new NodeScalarString_($encryptedString)),
                    new NodeArg(new NodeScalarString_($this->encryptionKey))
                ]
            );
        }

        return null;
    }

    private function encrypt($string, $key) {
        $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
        $encrypted = openssl_encrypt($string, 'aes-256-cbc', $key, 0, $iv);
        return base64_encode($iv . $encrypted); // 使用 base64 编码,方便存储
    }
}

// 待混淆的PHP代码
$code = <<<'PHP'
<?php

$username = "admin";
$password = "password123";

echo "Username: " . $username . "n";
echo "Password: " . $password . "n";

?>
PHP;

// 解析PHP代码
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
$ast = $parser->parse($code);

// 创建NodeTraverser并添加NodeVisitor
$traverser = new NodeTraverser;
$traverser->addVisitor(new StringEncrypter);

// 遍历AST并进行替换
$ast = $traverser->traverse($ast);

// 将AST转换回PHP代码
$prettyPrinter = new PrettyPrinterStandard;
$obfuscatedCode = $prettyPrinter->prettyPrintFile($ast);

// 输出混淆后的代码
echo $obfuscatedCode;

// 解密函数 (需要包含在混淆后的代码中,或者通过其他方式引入)
function decryptString($data, $key) {
    $data = base64_decode($data);
    $ivlen = openssl_cipher_iv_length('aes-256-cbc');
    $iv = substr($data, 0, $ivlen);
    $ciphertext = substr($data, $ivlen);
    return openssl_decrypt($ciphertext, 'aes-256-cbc', $key, 0, $iv);
}

?>

代码解释:

  1. 我们创建了一个名为StringEncrypterNodeVisitor,它遍历AST,找到NodeScalarString_类型的节点,即字符串字面量。
  2. 对于每个字符串,我们使用openssl_encrypt函数对其进行加密,并使用base64_encode函数对其进行编码,以便存储。
  3. 我们将加密后的字符串替换为一个函数调用,该函数负责解密字符串。在这个例子中,我们假设存在一个名为decryptString的函数,它接受加密后的字符串和密钥作为参数,并返回解密后的字符串。
  4. decryptString函数使用openssl_decrypt解密字符串,并返回原始字符串。

混淆效果:

原始代码:

<?php

$username = "admin";
$password = "password123";

echo "Username: " . $username . "n";
echo "Password: " . $password . "n";

?>

混淆后的代码:

<?php

$username = decryptString("...", "my_secret_key");
$password = decryptString("...", "my_secret_key");
echo "Username: " . $username . "n";
echo "Password: " . $password . "n";
function decryptString($data, $key) {
    $data = base64_decode($data);
    $ivlen = openssl_cipher_iv_length('aes-256-cbc');
    $iv = substr($data, 0, $ivlen);
    $ciphertext = substr($data, $ivlen);
    return openssl_decrypt($ciphertext, 'aes-256-cbc', $key, 0, $iv);
}

可以看到,原始字符串被加密并替换为decryptString函数的调用,从而隐藏了敏感信息。

控制流平坦化

控制流平坦化是一种高级的混淆技术,它可以将代码块的控制流打乱,使其不再按照线性顺序执行,从而增加代码逻辑的复杂性。其核心思想是将所有的代码块放入一个大的switch语句中,并通过一个状态变量来控制代码块的执行顺序。

示例代码:

<?php

require 'vendor/autoload.php';

use PhpParserParserFactory;
use PhpParserNodeTraverser;
use PhpParserNodeVisitorAbstract;
use PhpParserNode;
use PhpParserPrettyPrinter;

class ControlFlowFlattener extends NodeVisitorAbstract {
    private $stateVariable = 'state';
    private $stateValue = 0;
    private $cases = [];
    private $defaultCase = null;
    private $statements = [];

    public function enterNode(Node $node) {
        if ($node instanceof NodeStmtFunction_ || $node instanceof NodeStmtClassMethod) {
            $this->statements = $node->getStmts(); // 获取函数或方法的语句块
            $this->cases = [];
            $this->stateValue = 0;
            $this->defaultCase = null;

            if (empty($this->statements)) {
                return null; // 如果函数/方法为空,则不进行处理
            }

            // 创建 switch 语句的 case
            foreach ($this->statements as $statement) {
                $this->cases[] = new NodeStmtCase_(
                    new NodeScalarLNumber($this->stateValue++),
                    [$statement, new NodeStmtBreak_()]
                );
            }

            // 添加 default case,使其回到第一个 case
            $this->defaultCase = new NodeStmtCase_(null, [
                new NodeExprAssign(
                    new NodeExprVariable($this->stateVariable),
                    new NodeScalarLNumber(0) // 设置 state 为初始值
                ),
                new NodeStmtBreak_()
            ]);

            $this->cases[] = $this->defaultCase;

            // 创建 switch 语句
            $switchStmt = new NodeStmtSwitch_(
                new NodeExprVariable($this->stateVariable),
                $this->cases
            );

            // 初始化 state 变量
            $initState = new NodeExprAssign(
                new NodeExprVariable($this->stateVariable),
                new NodeScalarLNumber(0)
            );

            // 将新的语句块设置回函数或方法
            $node->stmts = [$initState, $switchStmt];
        }
        return null;
    }
}

// 待混淆的PHP代码
$code = <<<'PHP'
<?php

function calculateArea($width, $height) {
    $area = $width * $height;
    echo "Area: " . $area . "n";
    if ($area > 100) {
        echo "Area is large.n";
    } else {
        echo "Area is small.n";
    }
}

calculateArea(10, 15);

?>
PHP;

// 解析PHP代码
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
$ast = $parser->parse($code);

// 创建NodeTraverser并添加NodeVisitor
$traverser = new NodeTraverser;
$traverser->addVisitor(new ControlFlowFlattener);

// 遍历AST并进行替换
$ast = $traverser->traverse($ast);

// 将AST转换回PHP代码
$prettyPrinter = new PrettyPrinterStandard;
$obfuscatedCode = $prettyPrinter->prettyPrintFile($ast);

// 输出混淆后的代码
echo $obfuscatedCode;

?>

代码解释:

  1. 我们创建了一个名为ControlFlowFlattenerNodeVisitor,它遍历AST,找到NodeStmtFunction_类型的节点,即函数定义。
  2. 对于每个函数,我们将函数体内的所有语句提取出来,并将其放入一个大的switch语句中。
  3. switch语句使用一个状态变量$state来控制代码块的执行顺序。每个case对应一个原始的语句,并且在执行完该语句后,会使用break语句跳出switch语句。
  4. 我们添加一个default case,使其回到第一个 case,从而实现循环执行。
  5. 最后,我们在函数体的开头添加一个初始化$state变量的语句。

混淆效果:

原始代码:

<?php

function calculateArea($width, $height) {
    $area = $width * $height;
    echo "Area: " . $area . "n";
    if ($area > 100) {
        echo "Area is large.n";
    } else {
        echo "Area is small.n";
    }
}

calculateArea(10, 15);

?>

混淆后的代码:

<?php

function calculateArea($width, $height)
{
    $state = 0;
    switch ($state) {
        case 0:
            $area = $width * $height;
            break;
        case 1:
            echo "Area: " . $area . "n";
            break;
        case 2:
            if ($area > 100) {
                echo "Area is large.n";
            } else {
                echo "Area is small.n";
            }
            break;
        case 3:
            $state = 0;
            break;
    }
}
calculateArea(10, 15);

可以看到,原始的函数体被转换成了一个大的switch语句,代码的执行顺序不再是线性的,从而增加了代码逻辑的复杂性。请注意,这个例子简化了控制流平坦化的实现,实际应用中会更复杂,包括随机化 case 的顺序,增加不透明谓词,以及使用更复杂的控制流转移方式。

代码去混淆技术及其原理

代码去混淆是逆向混淆的过程,其目的是恢复原始代码的可读性和逻辑。去混淆技术通常包括:

  1. 静态分析: 分析代码的结构和逻辑,识别混淆模式。
  2. 动态分析: 运行代码,观察其行为,收集运行时信息。
  3. 符号执行: 使用符号值代替具体值,模拟代码的执行,推导代码的逻辑。
  4. 模式匹配: 识别已知的混淆模式,并应用相应的去混淆规则。
  5. 反编译: 将代码反编译成更高级的中间表示,例如伪代码,从而更容易理解代码的逻辑。

针对前面介绍的混淆技术,我们可以采取相应的去混淆策略。

变量名和函数名还原

对于变量名和函数名替换,我们可以通过以下方法进行还原:

  1. 代码分析: 观察变量和函数的使用情况,尝试推断其含义。
  2. 重命名: 根据变量和函数的含义,手动将其重命名为更有意义的名称。
  3. 自动化工具: 开发自动化工具,根据变量和函数的使用模式,自动推断其含义,并进行重命名。

例如,如果一个变量被频繁地用于存储数组的长度,那么我们可以将其重命名为arrayLength

字符串解密/解码

对于字符串加密/编码,我们需要找到加密/编码算法和密钥,然后使用相应的解密/解码算法还原原始字符串。

  1. 查找解密函数: 在代码中查找解密函数,例如decryptString
  2. 分析解密函数: 分析解密函数的实现,了解其使用的加密算法和密钥。
  3. 提取密钥: 从代码中提取密钥。密钥可能被硬编码在代码中,也可能从配置文件或其他地方读取。
  4. 执行解密: 使用提取到的密钥和解密算法,解密加密后的字符串。

可以使用静态分析找到解密函数,然后使用动态分析或符号执行来提取密钥。 例如,如果解密函数使用了硬编码的密钥,那么我们可以直接从代码中提取密钥。

控制流解平坦化

控制流解平坦化是去混淆中最具挑战性的任务之一。我们需要恢复代码的原始控制流结构。

  1. 识别状态变量: 识别控制switch语句的状态变量,例如$state
  2. 构建控制流图: 根据switch语句中的case,构建代码的控制流图。每个case对应图中的一个节点,break语句对应图中的一条边。
  3. 简化控制流图: 简化控制流图,例如删除不透明谓词,合并线性执行的节点。
  4. 重建代码结构: 根据简化后的控制流图,重建代码的原始控制流结构,例如将switch语句转换回if-else语句或循环语句。

这个过程通常需要手动分析和干预,并且需要对代码的逻辑有深入的理解。自动化工具可以辅助完成一些重复性的任务,例如构建控制流图和简化控制流图。

基于AST的去混淆

与混淆类似,我们也可以使用AST操作来进行去混淆。例如,我们可以编写一个NodeVisitor来自动重命名变量和函数,或者解密加密后的字符串。

示例:基于AST的变量名还原

假设我们已经分析了混淆后的代码,并确定了变量的含义。我们可以编写一个NodeVisitor来自动重命名变量。

<?php

require 'vendor/autoload.php';

use PhpParserParserFactory;
use PhpParserNodeTraverser;
use PhpParserNodeVisitorAbstract;
use PhpParserNode;
use PhpParserPrettyPrinter;

// 自定义NodeVisitor,用于还原变量名
class VariableNameRestorer extends NodeVisitorAbstract {
    private $variableMap = [
        'var_6f39f657d9456ead1c47b8f9689a3290' => 'x',
        'var_d72aa81509f410a0b27c454469c13a56' => 'y',
        'var_65a555a6e258c61094e6d72a526d1c76' => 'result',
        'var_356a192b7913b04c54574d18c28d46e6' => 'a',
        'var_da4b9237bacccdf19c0760cab7aec4a8' => 'b',
        'var_a947e47047c1c0ad4e4216f3b1727495' => 'sum'
    ];

    public function enterNode(Node $node) {
        if ($node instanceof NodeExprVariable) {
            $originalName = $node->name;
            if (isset($this->variableMap[$originalName])) {
                $node->name = $this->variableMap[$originalName];
            }
        }

        if ($node instanceof NodeExprAssign) {
            // 处理赋值语句中的变量,确保左侧和右侧的变量名一致
            if ($node->var instanceof NodeExprVariable) {
                $originalName = $node->var->name;
                if (isset($this->variableMap[$originalName])) {
                    $node->var->name = $this->variableMap[$originalName];
                }
            }
        }
        return null;
    }
}

// 混淆后的PHP代码
$code = <<<'PHP'
<?php

function func_79132c5a9a68460b50a19c41c389c3f3(var_356a192b7913b04c54574d18c28d46e6, var_da4b9237bacccdf19c0760cab7aec4a8)
{
    $var_a947e47047c1c0ad4e4216f3b1727495 = var_356a192b7913b04c54574d18c28d46e6 + var_da4b9237bacccdf19c0760cab7aec4a8;
    return $var_a947e47047c1c0ad4e4216f3b1727495;
}
$var_6f39f657d9456ead1c47b8f9689a3290 = 10;
$var_d72aa81509f410a0b27c454469c13a56 = 20;
$var_65a555a6e258c61094e6d72a526d1c76 = func_79132c5a9a68460b50a19c41c389c3f3(var_6f39f657d9456ead1c47b8f9689a3290, var_d72aa81509f410a0b27c454469c13a56);
echo "Result: " . $var_65a555a6e258c61094e6d72a526d1c76;

?>
PHP;

// 解析PHP代码
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
$ast = $parser->parse($code);

// 创建NodeTraverser并添加NodeVisitor
$traverser = new NodeTraverser;
$traverser->addVisitor(new VariableNameRestorer);

// 遍历AST并进行替换
$ast = $traverser->traverse($ast);

// 将AST转换回PHP代码
$prettyPrinter = new PrettyPrinterStandard;
$deobfuscatedCode = $prettyPrinter->prettyPrintFile($ast);

// 输出去混淆后的代码
echo $deobfuscatedCode;

?>

在这个例子中,我们使用一个$variableMap来存储混淆后的变量名和原始变量名之间的映射关系。VariableNameRestorer类遍历AST,找到NodeExprVariable类型的节点,并根据$variableMap将其name属性替换为原始变量名。

去混淆效果:

混淆后的代码:

<?php

function func_79132c5a9a68460b50a19c41c389c3f3(var_356a192b7913b04c54574d18c28d46e6, var_da4b9237bacccdf19c0760cab7aec4a8)
{
    $var_a947e47047c1c0ad4e4216f3b1727495 = var_356a192b7913b04c54574d18c28d46e6 + var_da4b9237bacccdf19c0760cab7aec4a8;
    return $var_a947e47047c1c0ad4e4216f3b1727495;
}
$var_6f39f657d9456ead1c47b8f9689a3290 = 10;
$var_d72aa81509f410a0b27c454469c13a56 = 20;
$var_65a555a6e258c61094e6d72a526d1c76 = func_79132c5a9a68460b50a19c41c389c3f3(var_6f39f657d9456ead1c47b8f9689a3290, var_d72aa81509f410a0b27c454469c13a56);
echo "Result: " . $var_65a555a6e258c61094e6d72a526d1c76;

?>

去混淆后的代码:

<?php

function func_79132c5a9a68460b50a19c41c389c3f3(a, b)
{
    $sum = a + b;
    return $sum;
}
$x = 10;
$y = 20;
$result = func_79132c5a9a68460b50a19c41c389c3f3(x, y);
echo "Result: " . $result;

?>

可以看到,变量名被还原成了原始的名称,提高了代码的可读性。

案例分析:一个简单的混淆与去混淆的流程

假设我们有以下代码:

<?php

$apiKey = "YOUR_API_KEY";

function fetchData($url) {
  // ...
  return $data;
}

$data = fetchData("https://api.example.com?key=" . $apiKey);

echo "Data: " . $data;

?>
  1. 混淆:

    • 替换变量名: $apiKey -> $a, $data -> $b
    • 字符串加密:YOUR_API_KEY使用base64编码 eW91cl9hcGlfa2V5https://api.example.com?key= 也进行base64 编码aHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20/a2V5PQ==

    混淆后的代码:

    <?php
    
    $a = base64_decode("eW91cl9hcGlfa2V5");
    
    function fetchData($url) {
      // ...
      return $data;
    }
    
    $b = fetchData(base64_decode("aHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20/a2V5PQ==") . $a);
    
    echo "Data: " . $b;
    
    ?>
  2. 去混淆:

    • 变量名还原: $a -> $apiKey, $b -> $data
    • 字符串解密:使用base64解码还原字符串。

还原后的代码:

<?php

$apiKey = "YOUR_API_KEY";

function fetchData($url) {
  // ...
  return $data;
}

$data = fetchData("https://api.example.com?key=" . $apiKey);

echo "Data: " . $data;

?>

PHP代码混淆与去混淆是一个持续对抗的过程

PHP代码混淆与去混淆是一个持续对抗的过程。混淆技术的不断发展推动着去混淆技术的发展,而去混淆技术的进步又反过来促进了混淆技术的改进。我们需要不断学习和探索新的混淆和去混淆技术,才能更好地保护和分析PHP代码。AST是实现PHP

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注