看我如何玩转PHP代码加密与解密
字数 1332 2025-08-29 08:32:24
PHP代码加密与解密技术详解
一、前言
PHP代码加密与解密是Web安全领域的重要课题。所有PHP代码最终都需要在Zend Engine上执行,因此理论上所有PHP源码加密都可以被解密(不包括OpCode混淆/VMP等高级混淆技术)。
二、代码混淆技术
代码混淆是一种常见的代码保护方式,虽然不算严格意义上的加密,但常与加密技术结合使用。
混淆特点:
- 对变量进行复杂修改
- 大量使用动态函数处理
- 按照随机生成的套路替换明文函数
- 批量修改变量名
混淆目的:
- 增加代码阅读难度
- 延长逆向分析时间
- 与加密技术协同增强保护效果
三、代码加密与解密技术
1. 常见加密工具
- phpjiami等基于eval的加密工具
2. 加密流程:
- 源码处理:压缩、替换、BASE64编码、转义等
- 安全处理:验证文件MD5值、限制IP、限域名、限时间、防破解、防命令行调试
- 生成加密程序:密文源码 + 自解密外壳 = 最终加密代码
3. 解密原理
PHP加密代码最终需要通过eval等函数执行,因此可以Hook相关执行函数获取源码。
关键函数:
zend_compile_string:PHP内核中处理字符串编译的函数
解密步骤:
- 声明临时compile_string函数
- 在PHP_MINIT_FUNCTION中替换原函数
- 在PHP_MSHUTDOWN_FUNCTION中恢复原函数
- 提取compile_string中的代码并保存
示例代码:
static zend_op_array *(*orig_compile_string)(zval *source_string, char *filename TSRMLS_DC);
// 在PHP_MINIT_FUNCTION中替换
orig_compile_string = zend_compile_string;
zend_compile_string = phpjiami_decode_compile_string;
// 在PHP_MSHUTDOWN_FUNCTION中恢复
zend_compile_string = orig_compile_string;
// 提取代码并保存
static zend_op_array *phpjiami_decode_compile_string(zval *source_string, char *filename TSRMLS_DC) {
int c, len, yes;
char *content;
FILE *fp = NULL;
char fn[512];
if (Z_TYPE_P(source_string) == IS_STRING) {
len = Z_STRLEN_P(source_string);
content = estrndup(Z_STRVAL_P(source_string), len);
if (len > strlen(content))
for (c = 0; c < len; c++)
if (content[c] == 0) content[c] = '?';
sprintf(fn, "/tmp/%s.php", zend_get_executed_filename(TSRMLS_C));
fp = fopen(fn, "a+");
if (fp != NULL)
fprintf(fp, "<?php \n %s \n ?> \n\n", content);
fclose(fp);
}
return orig_compile_string(source_string, filename TSRMLS_CC);
}
四、扩展加密与解密技术
1. 常见工具
- pm9screw
- pm9screw_plus
2. 加密流程:
- 对源码进行加密处理(对称/非对称加密、自定义加密)
- 生成密文代码
- 扩展在运行时判断源码是否加密,如未加密则进行加密处理
3. 解密原理
Hook zend_compile_file函数获取解密后的内容。
关键点:
- PHP扩展按"栈"顺序加载,先加载的先Hook
- 需要确保解密插件先于加密插件加载
- 可在INI配置中调整加载顺序
示例配置:
extension = "decode.so"
extension = "encrypt.so"
示例代码:
static zend_op_array *(*orig_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
// 在PHP_MINIT_FUNCTION中替换
orig_compile_file = zend_compile_file;
zend_compile_file = phpjiami_decode_compile_file;
// 在PHP_MSHUTDOWN_FUNCTION中恢复
zend_compile_file = orig_compile_file;
// 提取代码并保存
static zend_op_array *phpjiami_decode_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC){
char *buf;
size_t size;
if (zend_stream_fixup(file_handle, &buf, &size TSRMLS_CC) == SUCCESS) {
FILE *ff = NULL;
int i = 0;
php_printf("code size : \n %d \n\n source code : \n %s \n\n", size, buf);
ff = fopen("/tmp/decode.php", "a+");
if (ff != NULL)
for (i = 0; i <= size; i++)
fprintf(ff, "%c", buf[i]);
fclose(ff);
}
return orig_compile_file(file_handle, type TSRMLS_DC);
}
五、OpCode混淆技术
1. 代表工具
- Swoole Compile等
2. 技术特点:
- 部分脱离Zend虚拟机
- 对OpCode进行混淆
- 类似VMP(虚拟机保护)的实现方式
3. 解密难点:
- 需要深入理解Zend引擎和OpCode处理机制
- 目前尚无公开的通用解密方法
六、实战案例
1. PWNHUB公开赛/傻fufu的工作日
- 使用eval Hook技术解密
- 提取执行前的明文代码
2. SCTF2018 BabySyc - Simple PHP Web
- 使用扩展解密技术
- 通过Hook zend_compile_file获取源码
七、总结
PHP代码保护技术可分为多个层次:
- 代码混淆:增加阅读难度
- 代码加密:通过eval等函数动态执行
- 扩展加密:通过PHP扩展实现加解密
- OpCode混淆:最高级别的保护
对应的解密方法也从简单到复杂:
- 对于eval类加密:Hook执行函数
- 对于扩展加密:Hook编译函数并调整加载顺序
- 对于OpCode混淆:目前尚无通用解决方案
在实际应用中,往往需要结合多种技术进行综合防护,同时也需要根据具体加密方式选择相应的解密策略。