如何调用99%的知乎网页端API?知乎++逆向zse96 v2签名算法Rust实现深度解析
【免费下载链接】zhihu-plus-plusZhihu++ | 知乎++: Ad-free, low cost, AI powered zhihu android 3rd-party client. 去广告、占用低、AI大模型的新时代知乎安卓端体验项目地址: https://gitcode.com/gh_mirrors/zh/zhihu-plus-plus
知乎++(Zhihu++)是一款免费、去广告、低占用的知乎第三方客户端,支持 Android、macOS 和桌面端。它最硬核的能力之一,是完整逆向了知乎网页端的zse96 v2 签名算法,并用人人可审计的Rust 语言重新实现——这意味着知乎++能像浏览器一样合法访问知乎网页端 99% 的 API 接口,从而解锁搜索、话题、用户动态等大量原生 App 拿不到的数据。
为什么知乎网页 API 需要签名?
用浏览器打开知乎任意页面(如搜索、问题详情),你会发现每个请求都带着三个特殊请求头:
| 请求头 | 作用 |
|---|---|
x-zse-93 | 签名版本标识,固定为101_3_3.0 |
x-zse-96 | 核心签名值,格式为2.0_一长串密文 |
x-requested-with | 模拟fetch请求来源 |
服务器端会校验x-zse-96是否由当前 URL、你的设备 cookie(d_c0)、请求体计算而来。签名对了,网页端接口对你全部开放;签名错了,直接 403。这就是为什么很多第三方客户端只能调用 App 私有接口、功能受限,而知乎++可以做到"网页级"的完整体验。
🔑 关键洞察:签名算法并非黑盒魔法,而是藏在知乎前端加载的一个 JS 文件里(仓库中保留了逆向样本 misc/zse-ck-v4-24df2abbfcb1b98cd5ce1b519f02eeabea28c83ac9d9ec2778dc5b03a3b8b710.js)。知乎++团队逐行读懂了它的混淆逻辑,然后用 Rust 一行行还原。
zse96 v2 签名算法全流程拆解
整个签名可以浓缩成一条流水线,共 4 步:
1️⃣ 拼装签名原文
把 4 个要素用+号拼接:
zse93 + "+" + pathname + "+" + d_c0 + "+" + body其中pathname是请求 URL 去掉域名后的路径,body为 POST 请求体(GET 请求则为空)。拼接逻辑在 ZhihuFetchSignature.kt 中,不到 15 行代码。
2️⃣ MD5 摘要
对拼接结果做一次标准 MD5,得到 32 位十六进制字符串。知乎++的 ZhihuFetchSignature.kt 甚至手写了一个零依赖的 MD5 实现(md5Hex函数),保证跨平台行为完全一致。
3️⃣ 自定义块加密(算法核心)
这是整个算法最"反常规"的部分,全部由 Rust 实现,位于 rs-zse-sign/src/lib.rs:
ZK密钥表:32 个 32 位常量,相当于加密算法的"密钥轮";ZB置换表:256 字节的字节重排表,配合左移 2/10/18/24 位的异或运算构成混淆函数g_transform;r_block块加密:把 16 字节输入扩展成 36 个字的寄存器组,迭代 32 轮后取最后 4 字输出——结构上很像 AES 的轮函数,但完全是知乎自研。
多块数据之间还有"链式"依赖:每块的密文都作为下一块的初始化向量(见x_blocks函数 rs-zse-sign/src/lib.rs),任何一块被篡改都会导致后续全部校验失败。
4️⃣ 自定义 Base64 编码
最后用一张乱序的 64 字符表(6fpLRqJO8M/c3jnYxFkUVC4ZIG12SiH=5v0mXDazWBTsuw7QetbKdoPyAl+hN9rgE)做类 Base64 编码,并在编码时逐字节异或一个由常量58派生的滚动掩码(见custom_encode函数 rs-zse-sign/src/lib.rs)。即使你猜出了标准 Base64,也解不开这层"字符表+掩码"的双重伪装。
最终拼上版本前缀,就是你看到的请求头:
x-zse-96: 2.0_一段加密后的密文Rust 实现的三大亮点
🦀 双向加解密,自带验签工具
Rust 库不仅实现了encrypt_zse_v4(加密签名),还完整实现了逆运算decrypt_zse_v4(解密验证),位于 rs-zse-sign/src/decrypt.rs。配套的命令行入口 rs-zse-sign/src/main.rs 让你可以"输入密文 → 自动识别并解密",是调试签名问题的利器。
⚡ JNI 桥接,Android 零损耗调用
rs-zse-sign/src/lib.rs 通过jni库导出Java_com_github_zly2006_zhihu_util_ZseRustSigner_encrypt,Kotlin 侧一行external fun即可调用(见 ZseSigner.kt)。Rust 负责高性能字节运算,Kotlin 负责业务组装,各取所长。
🧪 单元测试守护正确性
decrypt.rs 内置了三组测试:ASCII 往返、中文 Unicode 往返、单块加解密互逆,保证算法实现与网页端 JS 版本逐字节一致。
在应用中的完整调用链
知乎++ App 发起 Web 请求时的完整链路非常清晰:
- Kotlin 扩展函数
signZhihuFetchRequest从 Cookie 中取出d_c0; - 调用
createZse96Header拼接原文并做 MD5; - 通过 JNI 调用 Rust 的
encrypt_zse_v4生成密文; - 写入
x-zse-96请求头,请求发出。
入口代码分布在 Utils.kt 和 WebviewComp.kt,单元测试 ZhihuFetchSignatureTest.kt 会断言签名头以2.0_开头。
自己动手:编译运行 Rust 签名器
克隆仓库即可在本地复现:
git clone https://gitcode.com/gh_mirrors/zh/zhihu-plus-plus cd zhihu-plus-plus/rs-zse-sign cargo run -- "https://www.zhihu.com/api/v4/search_v3?q=test"命令行工具会自动尝试解密;若输入不是合法密文,则原样输出加密结果。依赖只有一个jnicrate(见 rs-zse-sign/Cargo.toml),构建极快。
模块路径速查
| 模块 | 路径 |
|---|---|
| Rust 签名/解密库 | rs-zse-sign/src/lib.rs |
| Rust 解密实现 | rs-zse-sign/src/decrypt.rs |
| CLI 验证工具 | rs-zse-sign/src/main.rs |
| Kotlin 签名头组装 | shared/src/commonMain/kotlin/com/github/zly2006/zhihu/util/ZhihuFetchSignature.kt |
| JNI 桥接入口 | shared/src/commonMain/kotlin/com/github/zly2006/zhihu/util/ZseSigner.kt |
| 逆向 JS 样本 | misc/zse-ck-v4-24df2abbfcb1b98cd5ce1b519f02eeabea28c83ac9d9ec2778dc5b03a3b8b710.js |
| 油猴脚本参考 | misc/tampermonkey.js |
总结
知乎++通过逆向知乎的zse-ck/v4JS 加密脚本,拆解出"原文拼装 → MD5 → 自研块加密 → 乱序表编码"的完整 zse96 v2 签名流水线,并用约 400 行 Rust 代码高保真复现了它。这套实现让一个开源第三方客户端突破了原生 API 的能力边界,稳定调用网页端 99% 的接口——对于想学习接口逆向、密码学工程落地或 Rust 与 Android 互操作的同学来说,rs-zse-sign/ 目录本身就是一份难得的教科书级案例。
【免费下载链接】zhihu-plus-plusZhihu++ | 知乎++: Ad-free, low cost, AI powered zhihu android 3rd-party client. 去广告、占用低、AI大模型的新时代知乎安卓端体验项目地址: https://gitcode.com/gh_mirrors/zh/zhihu-plus-plus
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考