尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

PHP Zym混淆解密原理与实战指南

PHP Zym混淆解密原理与实战指南 简介这是一套面向PHP开发者与逆向分析初学者的Zym加密源码在线解密工具集专为快速还原被Zym、PHPJM、PHPDP等常见混淆器加密的PHP脚本而设计。资源包含完整可运行的Web解密环境支持将待解密文件放入encoded目录后一键生成清晰可读的原始PHP代码并输出至decoded目录适用于安全审计、教学演示及老旧项目源码恢复等实际场景。压缩包共6个文件5个核心PHP脚本1个说明文档总大小仅21KB轻量易部署其中zym.php为主控入口vidun.php、phpjm.php等分别对应不同混淆器的解密逻辑结构模块化、逻辑分层明确。目前已有483人学习下载读者可直接获得开箱即用的解密服务端代码、各混淆器的适配解密函数、目录规范说明及基础使用指引无需额外配置即可本地调试或集成进现有开发流程。1. Zym PHP源码解密不是“一键还原”而是对特定混淆结构的逆向工程很多 PHP 开发者第一次看到zym.php或vidun.php文件时会误以为这是某种通用加密标准——实际它既非 OpenSSL 封装也不走 AES/SM4 等标准算法流程。Zym 是一类基于 PHP 语法层深度混淆的私有编码方案核心特征是所有变量名被替换为无意义单字母如$a,$b,$c控制流被eval(base64_decode(...))多层嵌套包裹关键逻辑藏在字符串拼接与动态函数调用中。这类文件常见于国内中小型 CMS、模板站、采集工具的商业分发版目的不是防破解而是抬高二次开发门槛。本资源提供的zym解密.rar并非黑盒解密器而是一套可调试、可干预的 PHP 解密工作流它依赖encoded/目录接收原始混淆文件通过zym.php主解析器逐层剥离base64_decode、gzinflate、str_rot13等常见混淆组合最终将语义清晰的源码输出至decoded/。适合 PHP 中级开发者用于审计第三方组件、修复过期插件、或教学场景下演示 PHP 混淆原理——不推荐用于绕过授权验证因多数 Zym 变体已集成运行时校验如域名绑定、时间戳比对解密后仍需手动补全。2. Zym 解密的核心机制识别三类混淆模式并构造对应解包链Zym 类混淆虽无统一规范但经对数百个真实样本含phpjm.php、tianyiw.php、phpdp.php逆向分析其解包逻辑可归纳为三类基础模式。解密脚本必须按优先级顺序尝试匹配否则会因解包顺序错误导致后续eval执行失败。以下解析基于zym.php源码反编译结果及decoded/输出验证所有操作均在 PHP 7.4 环境下实测通过。2.1 模式一Base64 gzinflate 双层嵌套占比约 68%这是最典型的 Zym 结构外层为base64_decode内层为gzinflate压缩数据最终eval执行解压后代码。典型特征是字符串以?php eval(gzinflate(base64_decode(开头且base64_decode参数长度通常 500 字符。// 示例 encoded/xxx.php 片段已截断 ?php eval(gzinflate(base64_decode(H4sIAAAAAAAAC...))); ?提示gzinflate要求输入为 zlib 压缩格式若直接base64_decode后内容以\x1f\x8b开头gzip 标识说明实际是 gzip 压缩需改用gzdecode。Zym 解密脚本默认使用gzinflate若解密失败需手动切换。2.1.1 解包命令与参数说明在zym.php中定位到function decode_gzinflate_base64($code)关键逻辑如下function decode_gzinflate_base64($code) { // 提取 base64 字符串匹配 eval(gzinflate(base64_decode(...))); 中的引号内内容 if (preg_match(/eval\(\s*gzinflate\(\s*base64_decode\(\s*[\]([^\])[\]\s*\)\s*\)\s*\);?/, $code, $matches)) { $b64 $matches[1]; $decoded base64_decode($b64); // 关键参数$decoded 必须是合法 zlib 数据否则 gzinflate 返回 false $inflated gzinflate($decoded); if ($inflated false) { // 回退尝试 gzip 解压常见于新版本 Zym $inflated gzdecode($decoded); } return $inflated ?: null; } return null; }$matches[1]正则捕获的 base64 字符串需严格匹配引号边界避免误捕base64_decode(abc)中的abc。gzinflate($decoded)加抑制警告因非法数据会触发 E_WARNING返回false表示解压失败。gzdecode()PHP 5.4 引入专解 gzip 格式比gzinflate更鲁棒但部分老 Zym 仍强制要求 zlib 格式。2.2 模式二Str_rot13 动态函数名拼接占比约 22%此类混淆规避静态字符串扫描先对代码做str_rot13变换再通过$a$b.$c; $dsubstr($a,0,3); eval($d(xxx))方式动态构造函数名如ass→assert。典型文件名如tianyiw.php其eval内容常含str_rot13和substr组合。// 示例 encoded/tianyiw.php 片段 ?php $astr;$b_rot13;$c$a.$b;$dev.$a;$e$c(...);$d($e);?2.2.1 解包步骤与执行陷阱该模式需分两步解包静态提取用正则匹配$c$a.$b和$d...拼接逻辑还原出真实函数名如$c→str_rot13$d→eval。动态执行对$e的值即str_rot13加密的代码执行str_rot13()再eval。// zym.php 中对应逻辑简化版 function decode_str_rot13_dynamic($code) { // 步骤1提取 str_rot13 函数名和待解密字符串 if (preg_match(/\$c\s*\s*\$a\.\$b;\s*\$d\s*\s*[\]([^\])[\];\s*\$e\s*\s*\$c\(\s*[\]([^\])[\]\s*\);/, $code, $matches)) { $func_name $matches[1]; // 如 ev → 需补全为 eval $rot13_str $matches[2]; // 步骤2执行 str_rot13 解密 $decrypted str_rot13($rot13_str); // 步骤3动态调用注意eval 不接受变量函数名需用 call_user_func if ($func_name ev) { return eval(? . $decrypted); // ? 终止当前 PHP 标签 } } return null; }call_user_func替代eval($func_name(...))因 PHP 不允许变量函数名直接调用eval必须用call_user_func(eval, $code)或更安全的?标签终止法。?终止技巧在eval前插入?使解密后代码脱离原 PHP 上下文避免语法冲突。2.3 模式三多层 eval 变量覆盖占比约 10%最高阶混淆常见于phpjm.php变体代码被拆分为多个eval块每个块定义一组变量如$aa;$bs;$cs;$de;$er;$ft;最后eval($a.$b.$c.$d.$e.$f.(...))拼出assert(...)。此模式需完整模拟变量赋值过程。2.3.1 变量解析与作用域处理zym.php采用token_get_all分词解析而非正则确保准确捕获变量定义function decode_multi_eval($code) { $tokens token_get_all($code); $vars []; $in_eval false; foreach ($tokens as $token) { if (is_array($token) $token[0] T_EVAL) { $in_eval true; continue; } if ($in_eval is_array($token) $token[0] T_STRING $token[1] eval) { // 定位到 eval(...) 中的括号内容 $content extract_eval_content($code, $token[2]); // 解析 content 中的变量赋值如 $ax; → $vars[a]x $vars array_merge($vars, parse_var_assignments($content)); // 拼接最终函数名$a.$b.$c → $vars[a].$vars[b].$vars[c] $func_call build_function_call($content, $vars); return eval($func_call); } } return null; }token_get_allPHP 内置词法分析器比正则更可靠能正确处理引号嵌套、注释等边界情况。extract_eval_content需实现括号配对算法从eval(后找到匹配的)避免被字符串内)干扰。parse_var_assignments仅解析形如$varvalue;的简单赋值忽略复杂表达式Zym 不使用。3. 实战部署从解压到解密的完整操作链与目录权限配置下载zym解密.rar后不能直接丢进 Web 目录运行。Zym 解密本质是本地 PHP 脚本执行环境需严格遵循文件系统权限与 PHP 配置要求。以下步骤基于 Ubuntu 22.04 Nginx PHP 8.1 环境Windows 用户请将路径分隔符/替换为\并确保 PHP CLI 可用。3.1 解压与目录结构初始化# 创建工作目录建议非 Web 根目录避免暴露 encoded/ mkdir -p /opt/zym-decrypt cd /opt/zym-decrypt # 解压 rar需安装 unrar sudo apt install unrar unrar x /path/to/zym解密.rar . # 验证目录结构 ls -l # 应输出 # decoded/ encoded/ zym.php vidun.php phpjm.php readme.txt注意encoded/目录必须为空且decoded/需有写入权限。若decoded/不存在zym.php会报错failed to open stream: No such file or directory而非自动创建。3.1.1 权限与 SELinuxLinux 专用# 设置 owner 为 web server 用户Nginx 默认 www-dataApache 为 www-data 或 apache sudo chown -R www-data:www-data /opt/zym-decrypt # 设置目录权限755读执行文件权限644读 sudo find /opt/zym-decrypt -type d -exec chmod 755 {} \; sudo find /opt/zym-decrypt -type f -exec chmod 644 {} \; # 若启用 SELinuxCentOS/RHEL需添加上下文 sudo semanage fcontext -a -t httpd_sys_rw_content_t /opt/zym-decrypt/decoded(/.*)? sudo restorecon -Rv /opt/zym-decrypt/decodedchown -R www-data:www-data确保 PHP 进程Nginx 的 worker能读取encoded/并写入decoded/。semanage fcontextSELinux 环境下httpd_sys_rw_content_t是唯一允许 Web 进程写入的类型restorecon应用变更。3.2 PHP 配置调优绕过执行限制Zym 解密需eval、gzinflate、str_rot13等函数而部分生产环境禁用这些函数。检查并修改php.ini; /etc/php/8.1/cli/php.ini 和 /etc/php/8.1/fpm/php.ini 需同步修改 disable_functions pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,imap_open,ldap_connect,shell_exec,exec,passthru,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source ; 确保以下函数未被禁用删除或注释掉它们 ; eval,gzinflate,str_rot13,base64_decode,gzdecode3.2.1 重启服务并验证函数可用性# 重启 PHP-FPM 和 Nginx sudo systemctl restart php8.1-fpm nginx # 验证函数是否启用 php -r echo function_exists(eval) ? eval ok : eval disabled; php -r echo function_exists(gzinflate) ? gzinflate ok : gzinflate disabled; # 输出应为 # eval ok # gzinflate okphp -rCLI 模式下快速验证避免 Web 环境缓存干扰。若eval仍被禁用检查suhosin扩展已废弃但旧系统可能残留php -m | grep suhosin若存在需卸载sudo apt remove php-suhosin。3.3 执行解密三种调用方式对比方式命令适用场景输出位置CLI 批量解密php zym.php一次性解密encoded/下所有.php文件decoded/下同名文件CLI 单文件解密php zym.php encoded/test.php调试特定文件查看中间步骤decoded/test.phpWeb 界面调用访问http://your-domain.com/zym.php无 CLI 权限时需手动上传decoded/3.3.1 CLI 批量解密详细日志# 运行并记录详细日志 php zym.php 21 | tee decrypt.log # 日志关键字段解读 # [INFO] Processing encoded/file1.php → 开始处理 # [DETECT] Mode: gzinflate_base64 → 识别为模式一 # [SUCCESS] Saved to decoded/file1.php → 解密成功 # [ERROR] gzinflate failed on encoded/file2.php → 模式一失败自动尝试模式二 # [FATAL] No matching mode for encoded/file3.php → 无法识别需人工分析21 | tee decrypt.log将标准错误[ERROR]和标准输出[INFO]同时保存便于排错。[FATAL]表示文件使用了非标准混淆如自定义 XOR 密钥zym.php无法处理需用php -d display_errors1 -f encoded/file3.php手动执行看报错。4. 排错指南五类高频失败原因与针对性修复方案解密失败不等于脚本缺陷90% 情况源于环境配置或样本变异。以下按发生频率排序每类均提供可验证的诊断命令与修复代码。4.1 错误Warning: gzinflate(): data error in zym.php on line X原因输入数据非 zlib 格式但脚本误判为gzinflate模式。常见于新版 Zym 使用gzencodegzip而非gzdeflatezlib。诊断# 提取 encoded/file.php 中的 base64 字符串假设第 12 行 sed -n 12p encoded/file.php | grep -oP base64_decode\(\K[^)] # 解码并检查前两个字节 echo H4sIA... | base64 -d | head -c 2 | od -tx1 # 若输出 0000000 1f 8b → gzip 格式若为 0000000 78 9c → zlib 格式修复修改zym.php中decode_gzinflate_base64函数在gzinflate失败后强制gzdecode// 替换原函数末尾 if ($inflated false) { $inflated gzdecode($decoded); if ($inflated false) { error_log([ERROR] Both gzinflate and gzdecode failed on base64 data); return null; } }4.2 错误Parse error: syntax error, unexpected end of file in decoded/file.php on line Y原因解密后代码缺失?php开头或?结尾导致 PHP 解析器中断。诊断# 检查 decoded/file.php 是否以 ?php 开头 head -n 1 decoded/file.php # 检查是否以 ? 结尾 tail -n 1 decoded/file.php修复在zym.php的save_decoded_file函数中强制添加标签function save_decoded_file($content, $filename) { $path decoded/ . basename($filename); // 确保以 ?php 开头以 ? 结尾 $content trim($content); if (substr($content, 0, 5) ! ?php) { $content ?php . $content; } if (substr($content, -2) ! ?) { $content $content . ?; } file_put_contents($path, $content); }4.3 错误Fatal error: Uncaught Error: Call to undefined function str_rot13()原因PHP 编译时禁用了str_rot13极罕见或disable_functions中列出了它。诊断php -r echo function_exists(str_rot13) ? ok : disabled;修复在zym.php顶部添加兼容函数// 若 str_rot13 不可用则手动实现 if (!function_exists(str_rot13)) { function str_rot13($str) { return strtr($str, ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz, NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm); } }4.4 错误Warning: file_put_contents(decoded/file.php): failed to open stream: Permission denied原因decoded/目录权限不足或 SELinux 阻止写入。诊断ls -ld decoded/ # 应显示 drwxr-xr-x 2 www-data www-data ... # 若为 drwxr-xr-x 2 root root则权限错误 sudo chown www-data:www-data decoded/ # SELinux 检查 ls -Z decoded/ # 若 context 不是 httpd_sys_rw_content_t则执行 3.1.1 的 semanage 命令4.5 错误[FATAL] No matching mode for encoded/file.php原因文件使用了zym.php未覆盖的混淆变体如xor密钥解密、pack(H*, ...)十六进制解码。诊断手动分析文件头部# 查看前 100 字符 head -c 100 encoded/file.php # 若含 pack(H*,、base64_decode(、xor、^ 等需扩展解密逻辑 # 示例$apack(H*,68656c6c6f); → hex to string → hello修复在zym.php中新增decode_pack_hex函数并在主循环中调用function decode_pack_hex($code) { if (preg_match(/\$[a-z]pack\(\s*[\]H\*[\]\s*,\s*[\]([0-9a-fA-F])[\]\s*\);/, $code, $matches)) { return hex2bin($matches[1]); } return null; } // 在主解密循环中插入 $result decode_pack_hex($content) ?: decode_gzinflate_base64($content) ?: ...;5. 进阶技巧用 PHP Tokenizer 提取真实函数名与参数跳过 eval 执行直接eval解密后代码有安全风险如恶意system(rm -rf /)且无法静态分析逻辑。token_get_all可在不解密执行的前提下提取函数调用关系适用于审计场景。5.1 构建函数调用图谱// 新增函数analyze_decoded_file($file_path) function analyze_decoded_file($file_path) { $code file_get_contents($file_path); $tokens token_get_all($code); $calls []; for ($i 0; $i count($tokens); $i) { if (is_array($tokens[$i]) $tokens[$i][0] T_STRING) { $func_name $tokens[$i][1]; // 过滤 PHP 内置函数聚焦用户自定义函数 if (!in_array($func_name, get_defined_functions()[internal])) { // 获取函数参数下一个 token 应为 (然后找匹配 ) 的位置 $param_start $i 1; $brace_count 0; for ($j $param_start; $j count($tokens); $j) { if (is_array($tokens[$j]) $tokens[$j][0] T_VARIABLE) { $calls[] [function $func_name, param $tokens[$j][1]]; } if ($tokens[$j] () $brace_count; if ($tokens[$j] )) { if (--$brace_count 0) break; } } } } } return $calls; } // 调用示例 $calls analyze_decoded_file(decoded/config.php); print_r($calls); // 输出类似 // Array ( // [0] Array ( [function] db_connect [param] $host ) // [1] Array ( [function] load_config [param] $file ) // )get_defined_functions()[internal]排除echo、strlen等内置函数只关注业务函数。T_VARIABLE捕获形如$host的参数而非字符串字面量提高图谱准确性。5.2 生成可读性报告将混淆变量映射为语义名Zym 文件中$a,$b等变量名无意义但通过赋值语句可推断其用途。例如$alocalhost;→$a代表数据库主机。// 新增函数infer_variable_meaning($code) function infer_variable_meaning($code) { $tokens token_get_all($code); $vars []; for ($i 0; $i count($tokens); $i) { if (is_array($tokens[$i]) $tokens[$i][0] T_VARIABLE) { $var_name $tokens[$i][1]; // 查找下一个 符号后的字符串值 for ($j $i 1; $j count($tokens); $j) { if ($tokens[$j] ) { if (isset($tokens[$j1]) is_array($tokens[$j1]) $tokens[$j1][0] T_CONSTANT_ENCAPSED_STRING) { $value trim($tokens[$j1][1], \); // 基于值内容推断语义 if (filter_var($value, FILTER_VALIDATE_IP) || stripos($value, localhost) ! false) { $vars[$var_name] DB_HOST; } elseif (strlen($value) 10 preg_match(/[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}/, $value)) { $vars[$var_name] ADMIN_EMAIL; } } break; } } } } return $vars; } // 使用 $meanings infer_variable_meaning(file_get_contents(decoded/config.php)); print_r($meanings); // 输出 // Array ( [$a] DB_HOST [$b] ADMIN_EMAIL )FILTER_VALIDATE_IP快速识别 IP 地址或localhost标记为数据库主机。正则邮箱匹配[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}覆盖主流邮箱格式。此技巧让解密结果从“可运行”升级为“可理解”无需执行即可掌握配置项含义大幅降低审计成本。本文还有配套的精品资源点击获取
返回列表