本文仅供学习交流,只提供关键思路不会给出完整代码,严禁用于非法用途,若有侵权请联系我删除!
目标网站:aHR0cHM6Ly93d3cuemhpaHUuY29tLw==
目标接口:aHR0cHM6Ly93d3cuemhpaHUuY29tL2FwaS92NC9zZWFyY2hfdjM=
一、引言
今天主要来分析下某乎的搜索接口,熟练打开控制台抓包,定位到search_v3接口,发现该接口的请求头中存在X-Zse-96,X-Zst-81两个加密参数,每次请求都会变。
经过本人的调试分析,发现X-Zst-81不带也可以正常请求,我们清除cookie后重新加载页面,抓到的包也是不带X-Zst-81参数的。所以我们主要来看看X-Zse-96这个参数。怎么通过RPC的方式直接生成该加密值,免去抠代码补环境。
二、加密分析
全局搜索X-Zse-96,将所有可疑位置打下断点后,刷新页面。很快定位到如下关键代码:
td.set("x-zse-96", t0 + "_" + tT)
往上找找,定位到生成的位置,跟进去发现这边传进去的是请求的path,返回值就是我们需要的加密参数。
tE = ef(te, tl.body, {
zse93: ty,
dc0: tS,
xZst81: t_
}, tv)
继续跟着往下走,我们会发现代码有非常明显的jsvmp混淆,这时候我们有三种方式来解决。
1、RPC方式(需要保持浏览器)
2、将代码抠出来,慢慢补环境(麻烦)
3、继续跟进去,将算法还原出来(大佬做法)
因为本人水平有限 + 项目时间紧张,本次我采用RPC的方式搞定该参数。
三、强烈安利黑脸大佬的工具 :JsRPC
JsRpc: jsrpc,在浏览器开启一个ws和服务连接,以请求http接口的形式来和浏览器通信 ,浏览器端收到调用通信执行原先设置好的js代码并获得返回值。
基本介绍云云可以直接查看大佬的git,我这里直接开始实现远程调用:
1、下载win64-localhost.exe。双击运行,如下图就是正确启动了。
2、将仓库中 JsEnv.js文件下载到本地。并按照官方Git教程,将该js文件注入某乎网站 - 连接通信 - 测试远程调用成功。
四、分析某乎X-Zse-96参数远程调用的位置
1、基于JsRPC的学习。我们知道只要传入参数为明文,返回值为该加密值的地方都可以作为远程调用的位置。定位到如下关键代码:
具体看看这行代码:(0, tq(ti).encrypt)(tg()(td)) ,将代码中的变量值打印出来,其中主要的方法就两个 :tq(ti).encrypt() , tg() 。还有一个td参数由三段组成 "101_3_3.0+" + path + "+" + d_c。其中d_c0是cookie中的值
五、在控制台直接调用该关键代码生成加密值
1、首先我们要知道的是,我们直接注入的代码因为作用域不同,不一定直接访问到该关键代码,我们需要将核心方法赋值给window,达到全局访问的目的。(重要)
2、将断点达到关键代码处,将核心方法赋值给window。这里我选择将tq(ti),和tg()分别赋值,例:
window.mytg = tg()
window.mytq = function(tt) {
return tt && tt.version && "function" == typeof tt.encrypt ? tt : {
encrypt: th.ZP,
version: th.XL
}
}
3、完成赋值后,我们可以在任意位置通过window去访问该关键代码,例:
window.mytq().encrypt(window.mytg(''))
4、注入JsENV.js,示例代码:
// 连接通信
let client = new Hlclient("ws://127.0.0.1:12080/ws?group=match&name=mantou");
// 第二个参数为函数,resolve里面的值是想要的值(发送到服务器的)
// param 是可传参参数,与调用侧命名保持一致
client.regAction("sign96", function (resolve, param) {
// 被调用后这部分代码会被执行, resolve是回传给服务器的值
console.log('param:' + param)
let list = window.mytq().encrypt(window.mytg(param))
// let list = 'res' + param
console.log("res: " + list)
// 返回给服务器的值
resolve(list)
})
5、远程调用示例代码:
import requests
def getParam():
params = {
"group": "match",
"action": "sign96",
"name": "mantou",
"param": str('101_3_3.0+/api/v4/search_v3?gk_version=gz-gaokao&t=general&q=%E4%BA%AC%E4%B8%9C&correction=1&offset=0&limit=20&filter_fields=&lc_idx=0&show_all_topics=0&search_source=Normal+ACBXXWDlKxePTm5zHvHwS1dF3tqm2EDkCzw=|1690862802') # 与在脚本中的方法参数名保持一致
}
print("start send request")
# 调用服务中的方法,根据 group action name 匹配
# str = "http://127.0.0.1:12080/go?group=match20&name=yuanrenxue&action=ShiGuang¶m=123456789"
res = requests.get("http://127.0.0.1:12080/go", params = params).json()
print("end...")
# 2.0_
print(res)
getParam()
6、效果:搜索关键字:航海王,示例数据
最后:发送请求时,cookie中的d_c0参数必须与参与加密的参数完全保持一致(重要)