⚠️前言⚠️
本文仅用于学术交流。
学习探讨逆向知识,欢迎私信共享学习心得。
如有侵权,联系博主删除。
请勿商用,否则后果自负。
网址
aHR0cHM6Ly93d3cubHV4aS5nb3YuY24vY29sL2NvbDQ0NDQvaW5kZXguaHRtbA==
- 本网站数据均通过webSocket协议传输
一. WebSocket简介 引用 -【K哥】WebSocket 协议爬虫
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,WebSocket 使得客户端和服务器之间的数据交换变得更加简单。
在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。WebSocket 协议简称为 WS 或者 WSS(WebSocket Secure),其发送请求的 URL 以 ws:// 或者 wss:// 开头,WSS 是 WS 的加密版本,
类似于 HTTP 与 HTTPS。WebSocket 协议的最大特点就是:服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,
属于服务器推送技术的一种。
- 数据传输对比图
二. 网站分析
1. 先来分析一下 webSocket 链接的构成,主要分析一下这两个字是怎么生成的,其他暂可固定
2. 通过查看cookie,我们知道这两个值分别是 cookie
- dGg2aCfMMK97Ro270mqBFu5qjC8TQbL2opnHvbEpM: 大概率是由session响应的加密信息解密之后得到
- FW9uCWqlVzC22m1KfCMCjfvFHpRMsgt: 由session接口返回
- session 接口
- session 接口响应内容
三. session 接口 data
1. 参数密文生成逻辑分析
-
加密位置,ajax断点调试,找到如下位置,h值即为加密data的生成位置
-
参数T分析如下,其中 cid,tabId需要搞一下,其他可固定
-
最终调用 this下的 _dynamicEncrypt 生成
2. 参数 T 中 cid 的生成
- 需要注意的是 cid 其实就是 localStorage 中的 uuid 属性,调试之前清空浏览器缓存,找到值的生成逻辑
- 最终 cid 其实就是这个 i 值
- 代码改写一下
function getCid(){return Math["random"]()['toString'](36)['slice'](-8)}
3. 参数 T 中 tabId 的生成
- 回到参数 T 组装的位置看一下,发现 tabId 值存在于 对象 o 中
- 通过堆栈找到 tabId 的生成位置
- 生成逻辑
- 至此 参数 T 组装完成
4. 加密方法 _dynamicEncrypt
- 回到参数 data 的生成位置,我们来看一下这个加密方法
- 就是这里了
- 参数1:明文 T 参数
- 参数2:priKey 加密 Key 固定
- 参数3:iv 动态生成
- js文件 ob 混淆 + webpack,根据webpack扣代码思路,缺那个模块补那个模块就可以
- 7万多行代码758个模块,没有复杂的环境,这里扣代码细节就不多说了
- 注意:找对应模块的时候,可以把断点定位在加载器,找起来更方便
5. iv 值
- 生成位置,就在刚才加密 方法的上方, _dynamicEncrypt 搞定之后,iv 微调一下也就出来了
- 需要注意的是 session 请求发送时,请求头中有个 Etag 值,其实就是iv值,不对应的话请求会发送失败
6. 结果
四. session 接口响应解密
- 参数 data 的加密方法 是 _dynamicEncrypt
- 大胆猜测一下,在对象中可能会存在一个类似名称的解密 方法,这个方法有可能就是用来解密响应内容的
- 果然,我们直接进方法调试一下看看
- 参数 t 就是session中返回的密文,iv 和 data 生成时保持一致即可
- 结果
五. WebSocket
1. 收发信息
-
直接在network中看收发信息时以乱码的形式展示的
-
所以我还需要找到js中 websocket 收发位置,看看是怎么加密与解密的
-
我们可以用webSocket中的一些关键字通过全局检索的方式来定位:
-
信息发送明文位置
-
信息发送位置,信息发送前通过 r.encode() 转化了一下,所以我们在 network 中看到的才是乱码
-
信息接收位置,最终通过 r.decode() 转化成明文
-
信息接收位置,日志断点
-
收发日志信息
六. 模拟 webSocket 请求
1. nodejs 模拟简易代码
// 客户端
const WebSocket = require('ws');const options = {headers: {"Sec-WebSocket-Version": "13","Upgrade": "websocket",'Sec-WebSocket-Key': '5ZH2HCR7sxXbypI96Bixqg==','Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits'}
};const socket = new WebSocket('wss链接', [], options);// 当连接建立时触发
socket.onopen = () => {console.log('Connected to server');// 在此处添加发送消息的逻辑...// 模拟心跳setInterval(() => {console.log('send ' + JSON.stringify([-1,["","",32,62,!1]]))socket.send(window.r.encode([-1,["","",32,62,!1]])); // 发送心跳消息以保持连接活跃}, 3000); // 每3秒发送一次心跳消息
};// 当接收到服务器发送的消息时触发
socket.onmessage = (event) => {console.log(`Received: ${window.r.decode(event.data)}`);
};// 当连接关闭时触发
socket.onclose = () => {console.log('Connection closed');
};
2. webSocket特殊 headers 字段说明
- Upgrade: websocket:表明这是 WebSocket 类型请求;
- Sec-WebSocket-Version:告诉服务器所使用的 Websocket Draft(协议版本),必须是 13;
- Sec-WebSocket-Extensions:协议扩展,某类协议可能支持多个扩展,通过它可以实现协议增强;
- Sec-WebSocket-Key:是 WebSocket 客户端发送的一个 base64 编码的密文,是浏览器随机生成的,要求服务端必须返回一个对应加密的 - Sec-WebSocket-Accept 应答,否则客户端会抛出 Error during WebSocket handshake 错误,并关闭连接。
3. 模拟心跳保持链接活跃,每 3s 一次,上述代码使用定时器实现
4. 模拟链接服务器
- 这里不再过多展示了,需要获取特定数据的,可以根据日志模拟信息发送接收
没有来的及模拟真实数据接收那一块,来需求了,我要去当牛马了
欢迎私信交流。。。