在维护老旧系统或分析第三方PHP程序时,我们常会遇到内容被反复加密过的文件。这类文件通常不是只用一种算法处理一次,而是base64、AES、异或甚至自定义混淆连续叠加。要还原数据,就必须弄清加密顺序并反向操作。

一、理解多层加密的基本结构
多层加密并不会改变加密的数学本质,只是把处理流程串行化。假设原始字符串先经过AES-256-CBC加密,再把结果做base64编码,最后用异或混淆,那么最终文件内容就是这三步的输出。如果只拿base64_decode去解,自然得不到任何可读信息,因为最外层还裹着异或层。
在分析时,我们可以先观察文件特征:纯字母数字且长度为4的倍数,多半最外层是base64;如果出现不可见字符且长度规整,可能是AES密文;若每字节都有固定规律偏移,则考虑异或。理清顺序是解密的第一步,也是最关键的一步。
1.1 常见加密堆叠方式
实际项目中,下面几种组合出现频率很高:第一,base64 + AES,用于配置文件防泄露;第二,异或 + base64 + 自定义替换,多见于早期PHP木马;第三,openssl_encrypt连续调用两次不同算法。无论哪种,解密函数调用的顺序必须与加密完全相反。
我们可以用一张表来归纳典型层次与对应解开动作:
| 外层位置 | 可能形式 | 逆操作 |
|---|---|---|
| 第一层(最外) | base64编码 | base64_decode |
| 第二层 | AES密文 | openssl_decrypt |
| 第三层(最内) | 明文或异或 | 异或还原 |
二、实战:三层加密文件解密示例
下面模拟一个被异或、AES、base64连续处理过的字符串,并给出完整解密代码。加密时顺序是明文->异或->AES->base64,因此解密必须倒着来:先base64_decode,再openssl_decrypt,最后异或。
2.1 加密端参考代码
为了验证解密正确,我们先写出加密逻辑。注意异或密钥和AES密钥应分开管理,避免混淆。
<?php
$plain = 'db_config_content';
$xor_key = 'abc';
// 第一层:异或
$xored = '';
for ($i = 0; $i < strlen($plain); $i++) {
$xored .= chr(ord($plain[$i]) ^ ord($xor_key[$i % strlen($xor_key)]));
}
// 第二层:AES-256-CBC
$method = 'AES-256-CBC';
$aes_key = '1234567890abcdef1234567890abcdef';
$iv = 'abcdefghijklmnop';
$encrypted = openssl_encrypt($xored, $method, $aes_key, OPENSSL_RAW_DATA, $iv);
// 第三层:base64
$out = base64_encode($encrypted);
file_put_contents('secret.txt', $out);
?>
2.2 对应的多层解密代码
读取文件后,严格逆序执行。任何一步参数错误都会导致最终得到乱码,因此建议每层解密后都打印中间结果辅助排查。
<?php
$data = file_get_contents('secret.txt');
// 逆第三层:base64解码
$step1 = base64_decode($data);
// 逆第二层:AES解密
$method = 'AES-256-CBC';
$aes_key = '1234567890abcdef1234567890abcdef';
$iv = 'abcdefghijklmnop';
$step2 = openssl_decrypt($step1, $method, $aes_key, OPENSSL_RAW_DATA, $iv);
// 逆第一层:异或还原
$xor_key = 'abc';
$plain = '';
for ($i = 0; $i < strlen($step2); $i++) {
$plain .= chr(ord($step2[$i]) ^ ord($xor_key[$i % strlen($xor_key)]));
}
echo $plain;
?>
运行上述脚本,控制台会输出原始的db_config_content。如果某层使用了OPENSSL_ZERO_PADDING等非默认填充,解密时也要保持一致,否则末尾会出现多余字符。
三、处理未知加密文件的排查思路
当拿到一个没有任何文档的加密文件,不要急于写解密函数。先用hexdump看字节分布,判断最外层是否base64;再试常见AES模式。很多PHP程序把密钥硬编码在调用openssl_encrypt的同文件里,搜索关键词能快速定位。
若文件经过自定义函数混淆,比如把字符顺序反转再异或,就需要先还原反转逻辑。此时可把疑似加密函数单独抽出来,用已知短字符串跑一遍,对比输入输出,反推规则。耐心和分层验证是处理多层加密的核心能力。
3.1 避免常见误区
一个容易犯的错误是认为base64也算加密,从而在外层base64之后又套一层自以为的加密,实际只是编码。解密时若多解一次base64,会得到二进制乱码。另一个坑是IV长度不符,AES-256-CBC要求16字节IV,写成其他长度在某些PHP版本下会静默截断,导致解密不全。
建议在写多层加解密工具时,把每层输入输出写入日志,出现问题时能立刻看到是哪一层断裂。这样比盲目修改密钥效率更高。
四、小结
PHP多次加密文件的解密核心就是逆序与参数对齐。只要按顺序拆掉每一层外壳,并保证算法、密钥、填充方式一致,再复杂的堆叠也能还原。面对遗留系统,结合代码搜索和分层验证,基本可以搞定绝大多数多层加密场景。
掌握上述方法后,你不仅能处理配置文件,也能在安全审计中快速识别恶意脚本的隐藏逻辑,提升日常问题排查效率。