本帖最后由 a3341736201 于 2026-7-10 11:24 编辑
最近在玩WP,但是不会设置,找了论坛也没有合适我的WP,无意中看到这套主题!某wp主题9.0逆向过程,这个主题在已往历史版本都没有加密混淆很好做开心版,但是9.0开始增加了许多混淆以及删除暗装***
本文会尽量脱敏,仅做技术参考分析,建议还是支持正版!
---------------------------------------------
一分析加密机制
该主题使用 Z5Encrypt 对核心 PHP 文件进行加密。每个加密方法的结构为:
函数签名 + 左花括号 + 密文字符串赋值 + return eval(解密函数调用) + ;$_SERVER; + 右花括号
实际代码示例(不可读的二进制数据):
public static
function is_aut(){$éåå='uVMO\x14A\x10}³\x88°ì\x08\x0a...数百字节二进制密文...'."\0".'...';return eval(解密函数调用(加密变量));$_SERVER;}
**关键特征**:
1. 每个加密方法以 `);$_SERVER;}` 结尾 — 这是定位方法边界的唯一锚点
2. 解密函数在文件开头的全局混淆代码中定义,整个文件是一个巨大的 gzinflate 压缩块
3. 方法内的加密变量名每次不同(`$éåå`、`$¾©Љ`、`$òŒÙ`),是随机生成的 latin1 字符串
4. 返回的 eval 执行后会动态定义函数、注册 Hook、执行业务逻辑
1.1 理解加密方法的解剖结构
选 `code.php` 中的 `is_local()` 方法做解剖样本。在原始文件中,它长这样---------------
...前一个方法结束: );$_SERVER;}
public static
function is_local(){$加密变量='uVMO\x14A\x10}³\x88°...';return eval(解密引擎($加密变量));$_SERVER;}
public static
function is_aut(){$加密变量='uVMO\x14A\x10~ZD>...';return eval(解密引擎($加密变量));$_SERVER;}
---------------
**解剖结构**:
[前一个方法的终止符]
[可选的 public static 修饰符,可能单独一行]
[function 方法名(参数)] {
[$变量名 = '二进制密文';]
[return eval(解密函数($变量名));]
[$_SERVER;] ← 这是混淆尾巴,PHP 会把它当作一个无害的表达式求值
}
[下一个方法的修饰符]
**理解**:我们不能直接读加密方法体中的 PHP 代码(因为它是加密的),但我们可以**替换整个方法体**。只要保留函数签名,把花括号内的所有内容换成 ` return 我们想要的值; }`,PHP 就能正常执行。
二、文件的结构
**总计**:15 个文件,约 **149 个加密方法**。
三 开始分析安装主题后台页面代码
options-module.php 中的关键判断
if (!ZibAut::is_local()) {
// 不是本地环境 → 显示授权状态面板
return array('type' => 'content', 'content' => $con);
} else {
// 是本地环境 → 显示"您当前正处于本地环境,暂时无需授权!"
return array('type' => 'content', 'style' => 'info', 'content' => '...');
}
这里我的怀疑就是ZibAut::is_local() 先判断是不是本地环境,=true 就显示本地, false 开始远程验证
1.ZibAut::is_local() 检查是否已授权
2.ZibAut::is_ok() 远程验证授权码
3.ZibAut::curl_aut() 向 *** 发请求验证
4.ZibAut::is_singok() ← 验证数字签名
这个时候我们就推导一下
1- 如果把 `is_local()` 改为 `return false`,系统会认为不是本地,走远程验证路径
2- 但同时把 `is_aut()` 改为 `return true`,远程验证路径直接通过
3- 把 `curl_aut()` 等远程通信方法改为 `return `,阻止实际发起网络请求
4- 把 `noaut_notice()` 等通知方法改为 `return `,阻止弹窗
然后我直接让 `is_local()` 返回 `false`(走正式授权路径),同时让 `is_aut()` 返回 `true`(授权直接通过),拦截所有远程通信。
3.1 VM 运行时函数链
后面我分析的时候 发现他们加密方法不是独立运行的,它们之间存在一个隐式的运行时依赖链:
functions.php
└─ inc.php
├─ require.php
│ ├─ zib_init_add_action() [eval] → 动态定义 OB() V() Va() S() U() v() Z() Q()
│ └─ zib_admin_tool_action() [eval] → 注册 WordPress 管理后台钩子
├─ file.php
│ └─ ZibDB::query() [eval] → 内部调用 OB() V() Va() 等 VM 函数完成查询构建
├─ shop/class.setup.php [eval] → 商城初始化
└─ zibpay/ajax-class.php [eval] → 支付处理
`require.php` 中的 `zib_init_add_action()` 是整个 VM 的初始化入口。它的 eval 代码动态定义了 8 个短名称全局函数(`OB`、`V`、`Va`、`S`、`U`、`v`、`Z`、`Q`)——这些是 ZibDB 和其他业务代码的运行时依赖。因此 `require.php` **不能修改**。
我开始全把加密都干掉,结果全局崩了,后面仔细发现 ,接下来只修改授权/自毁相关方法,保留所有业务逻辑加密代码
3.2 核心修补工具:nuke() 函数
用于将一个加密方法体替换为自定义返回值:
const fs = require('fs');
const SERVER_END = ');$_SERVER;}';
function nuke(code, funcName, returnValue) {
// ① 找到函数签名:function 方法名(参数) {
const startPattern = new RegExp('function\s+' + funcName + '\s\([^)]\)\s*\{');
const m = code.match(startPattern);
if (!m) return code;
// ② 定位方法体开始位置({ 之后)
const openBrace = code.indexOf('{', m.index) + 1;
// ③ 找到加密体结束标记 );$_SERVER;}
const termIdx = code.indexOf(SERVER_END, openBrace);
if (termIdx === -1) return code;
// ④ 切除加密体,插入返回值
const before = code.substring(0, openBrace);
const after = code.substring(termIdx + SERVER_END.length);
return before + ' ' + returnValue + ' }' + after;
}
--------------------------------------------------------------
正文修补 不在啰嗦
一 开始核心文件修补 里面有很大的坑 !
上面已经说了大体修补思路,现在开始修补,
*inc/code/code.php核心授权文件主题授权的唯一入口 一共33 个加密方法。
1.`is_local()` — 授权显示控制
原始代码:
public static
function is_local(){$密文='uVMO.A.}...二进制密文...';return eval(解密($密文));$_SERVER;}
修补后:
public static function is_local(){ return false; }
为什么这么做:`is_local()` 返回 `true` 时显示"本地环境,暂时无需授权",返回 `false` 时走正式授权路径。改为 `false` 后系统始终进入授权面板分支。
2.`is_aut()` 授权状态
原始代码:
public static
function is_aut(){$密文='uVMO.A.~ZD>...二进制密文...';return eval(解密($密文));$_SERVER;}
修补后:
public static function is_aut(){ return true; }
这是主题内部判断"是否已授权"的核心方法。返回 `true` 后,所有依赖此方法的模块(前台付费内容、后台功能开关、商城/BBS 状态等)都认为已授权。
3.验证链参数
| 方法 | 修补后 | 说明 |
| -------------------- | -------------- | -------------- |
| `is_ok($data)` | `return true;` | 远程授权码验证 |
| `is_singok($data)` | `return true;` | 数字签名校验 |
| `aut_required()` | `return true;` | 授权必要条件 |
| `update_ok($result)` | `return true;` | 更新状态检查 |
4.远程通信拦截
| 方法 | 修补后 | 说明 |
| -------------------------- | ------------ | --------------------------- |
| `curl_aut($aut_code=null)` | `return "";` | 向 ****.com 发授权验证请求 |
| `http_request($url,$data)` | `return "";` | 通用远程 HTTP 请求 |
| `timing_aut()` | `return "";` | 定时自动授权检查 |
| `curl_aut_data($aut_code)` | (保留) | 数据处理,不发网络请求 |
这么特别说明 为什么远程通信返回 `""` 而不是 `false`**:调用方可能对返回值做字符串操作或数组访问。返回空字符串比 `false` 更安全——不会触发 `if ($result === false)` 这类严格比较。
5.后门暗装自毁机制
原始代码:
function delete(){$密文='...';return eval(解密);$_SERVER;}
修补后:
public static function delete(){ return ""; }
这里特别恶心,检测到篡改时调用此方法删除主题文件,我开始以为是我本地的环境问题,一直修补了半天
6.授权码操作拦截
| 方法 | 修补后 | 说明 |
| -------------------------- | ------------ | -------------------- |
| `save_aut_code($code)` | `return "";` | 保存授权码到数据库 |
| `get_aut_code()` | `return "";` | 从数据库读取授权码 |
| `get_aut_code_sign($code)` | `return "";` | 获取授权码的数字签名 |
| `get_aut_url()` | `return "";` | 获取远程授权验证 URL |
| `get_download_url()` | `return "";` | 获取更新包下载 URL |
7.BBS/商城兼容:添加 `public static` 修饰符
BBS 论坛和 Shop 商城模块通过 `ZibAut::is_aut()` 等方式**静态调用**授权方法。如果修补后的方法缺少 `static` 关键字,静态调用会失败。
// 为所有修补方法添加 static 修饰符
const staticMethods = [
'is_local', 'is_aut', 'is_ok', 'is_singok', 'aut_required', / ... /
];
for (const m of staticMethods) {
code = code.replace(
new RegExp('function\s+' + m + '\s*\(', 'g'),
'public static function ' + m + ' ('
);
}
同时需要清理原始代码中残留的单独 `public static` 行,否则会产生重复修饰符:
// 删除残留的单独 public static 行
code = code.replace(
/^(\s)public\s+static\s[\r\n]+(?=\s*(?:public\s+static\s+)?function)/gm,
''
);
8.inc/code/aut.php` — 处理远程服务器的授权码验证响应。6 个加密方法。
| 方法 | 原始代码(缩略) | 修补后 |
| --------------- | ------------------------------------- | ----------------------------------------------- |
| `isok($code)` | `{$密文;return eval(解密);$_SERVER;}` | `{ return md5("bypass"); }` |
| `is_token()` | `{$密文;return eval(解密);$_SERVER;}` | `{ return true; }` |
| `aut()` | `{$密文;return eval(解密);$_SERVER;}` | `{ return array("result"=>true,"msg"=>"ok"); }` |
| `update($data)` | `{$密文;return eval(解密);$_SERVER;}` | `{ return true; }` |
**`isok()` 为什么返回 hash 值**:调用方可能对返回值做 hash 比较。返回合法 md5 值比返回 `true` 更不容易触发异常路径。
**`aut()` 为什么返回数组**:返回值会经过 `json_encode()` 发送给前端。返回正确的数组结构确保 JavaScript 端不报错。
9.inc/code/tool.php` — 管理工具
| 方法 | 修补后 | 拦截目的 |
| ---------------------------- | ------------ | ----------------------------------- |
| `zib_admin_aut_add_action()` | `return "";` | 注册授权相关的 WordPress Hook |
| `zib_admin_curl_aut()` | `return "";` | 通过 curl 向 *****.com 发送授权请求 |
| `zib_admin_delete_aut()` | `return "";` | 删除文件(自毁入口) |
| `zib_is_local()` | `return "";` | 本地环境检测(已由 code.php 处理) |
10.inc/code/new_aut.php` — 新授权引擎(2 个方法全部替换)
| 方法 | 修补后 |
| ------------------------- | ------------ |
| `zib_init_add_action()` | `return "";` |
| `zib_admin_tool_action()` | `return "";` |
11.做事要做完美,inc/options/options-module.php 强制显示授权
// 原始代码
if (!ZibAut::is_local()) { ... }
// 修补后(双重保险)
if (true) { ... }
然后我们部署看看效果
后台:
如果没授权是无法保存内容
首页:
加密后的:论坛+商城板块
均正常的,也算是ok了
************************************
结语:但是有一点,别人说上传liunx报错,不正常,我本地是win小皮面板我就没去详细测过
我提供一个版本给大家试试,大家请在非正式环境下测试,仅供技术娱乐,不排除是否还有自毁机制没改到!不负责!
如能够帮忙得到各位,希望你们动动手指评分,另外我想找熟悉wp的朋友一起交流一下!感谢各位
应管理要求不得放成品,不过评论区大家应该知道是那个主题,想练手的朋友自己动动手即可!
|