已经有大半年没有水帖子了,是真的没时间啊
今天水一下抖音web端的直播wss的 signature 参数,这玩意出来,貌似是几个月之前的事情了,搞完之后一直也没时间记录。
打开网页可以看到如下信息。
从这个地方进去
那么你就会进到这个位置
下断点,然后重新刷心,会在此处断下,断下之后,单步进入到函数内部,然后,在return的地方打上断点
然后你就会看到他是从这个地方计算出来的
知道了出处,知道了位置,下面就是分析他的计算过程
c变量接的是一个函数,函数传了2个参数,一个是u,一个是s
c = ((t, e = []) => {
var r, n, o;
let i = "";
for (const {
param_name: u
} of e)
i += `,${u}=${null != (r = t[u]) ? r : ""}`;
const s = {
"X-MS-STUB": D()(i.substring(1))
};
let a = {};
return window.byted_acrawler && (a = null == (n = null == window ? void 0 : window.byted_acrawler) ? void 0 : n.frontierSign(s)), {
signature: null != (o = a["X-Bogus"]) ? o : ""
}
})(u, s);
s是一个写死的数组
在 D()(i.substring(1)) 中,像这种调用,就不要去跟D函数了,直接进到 D() 里面,进到函数里面就是下面这样,在return处下断点
var n = r.wordsToBytes(s(e, t));
有个s函数,先跟进去看下是什么,他的2个参数,一个是哦,一个是t,如下所示
进去之后会发现进到这里面,到了这里就是熟悉的webpack了,我们要将这些调用先跑起来。
PS:关于 webpack 逆向,网上有很多优秀的教程。我这里就自己手动导出一下,因为数量不多,多的话,可以看看网上的自动输出方法,多学几种方法总是好的。
先在此处下一个断点,然后重新刷新一下,让他在这里断下
进去之后在return里面下断点,然后继续走到断点位置,然后,我们先把这当前的整个代码复制下来,放到本地运行,
然后在这里写一行,把他导出到全局
导出之后,我们就可以在全局上访问webpack里面打包的函数,到了这一步先别急,我们刚刚在前面看到的这几个就要添加进他到底大对象里面了,关于webpack的原理这里就不细说了,网上很多教程,毕竟我说了这是水贴
我这里是这样添加的,他第一个函数是 n(55535)
在断点的位置不要动,直接回到控制台输入u[‘55535’],他return后面跟的啥变量就用啥变量去获取,他是一个超大的对象
然后cv到你刚刚保存的那个文件里面的大对象里面,剩下的15353和4488以此类推
当你导进去之后,你就可以在控制台检测一下
到了这一步之后,回到前面,前面他是这么写的,r = n(55535), i = n(4488).utf8, o = n(15353),a = n(4488).bin,
这个n函数其实就是我们刚刚导出的 window.m
那么我们调用的时候就可以这样写了
然后呢,又因为我们刚刚的 var n = r.wordsToBytes(s(e, t)); 里面的 s 函数是来自这个84465的对象,并且他的入参就一个参数,我们要把这个84465的函数也给导出到webpack的对象里面,还是同理,cv到前面的那个地方。
可以打印看下结果,到了这一步就获取了X-MS-STUB的结果
继续回到原来的位置,可以看到,这里return都好表达式,最后数输出一个 Object 出来
继续回到开始的位置,在return的位置下断点,在控制台查输出看一下数据
会输出一个这样的东西,然后 signature: null != (o = a[“X-Bogus”]) ? o : “”,他又会去取X-Bogus 的value,作为他自己的值,进到 n.frontierSign,可以看到,是抖音的 jsvmp
进到函数里面,可以看到,他的入参,是刚刚我们通过**D()(i.substring(1))**计算出来的值
注意:到了这一步,先不要急,正常流程走的话,你应该要去验证一下这东西你分析了之后对不对,看生成出来的东西能不能用,而不是瞎鸡儿往下搞。(你也不知道他有没有给你埋其他的坑)
下面是一段nodejs的代码,方便后续验证signature的可用性
// webSocketUrl参数替换成你们自己浏览器的,除了signature不复制,其他都cv上去
const WebSocket = require('ws')
const signature = '' // 验证你的 signature
const userAgent = '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36'
const webSocketUrl = `wss://webcast5-ws-web-hl.douyin.com/webcast/im/push/v2/?app_name=douyin_web&version_code=180800&webcast_sdk_version=1.0.6&update_version_code=1.0.6&compress=gzip&device_platform=web&cookie_enabled=true&screen_width=1920&screen_height=1080&browser_language=zh-CN&browser_platform=Win32&browser_name=Mozilla&browser_version=5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/113.0.0.0%20Safari/537.36&browser_online=true&tz_name=Asia/Shanghai&cursor=t-1689264612798_r-1_d-1_u-1_h-1&internal_ext=internal_src:dim|wss_push_room_id:7255257051152730915|wss_push_did:7255323052254414347|dim_log_id:202307140010123EF135C24A944B5EF10A|fetch_time:1689264612798|seq:1|wss_info:0-1689264612798-0-0|wrds_kvs:WebcastRoomStatsMessage-1689264611462151237_WebcastRoomRankMessage-1689264389498438065&host=https://live.douyin.com&aid=6383&live_id=1&did_rule=3&endpoint=live_pc&support_wrds=1&user_unique_id=&im_path=/webcast/im/fetch/&room_id=7255257051152730915&identity=audience&heartbeatDuration=0&signature=${signature}`
const client = new WebSocket(webSocketUrl, {
headers: {
'User-Agent': `Mozilla/${userAgent}`,
cookie: 'ttwid=1|dx-bBu3gXE-OyfoylJsWuKrqnpFRomgwBejsAmhRGhA|1689177319|d2996fa9a0beb84f6fb390a33c270011682d5ea10cbf407ed1c592fc350a0a92;'
},
binary: true
})
client.on('open', () => {
console.log('########### WebSocket open ###########')
})
client.on('message', message => {
console.log(message)
})
client.on('close', async () => {
console.log('########### WebSocket close ###########')
})
client.on('error', err => {
console.log('########### WebSocket close ###########')
})
到了这里,下面就是分析 如何让 vmp 在本地调用,主要还是补环境,大佬的话可以搞纯算
进到vmp之后,首先将这个东西给cv保存到本地,初始化的时候先运行这个,这里还要稍微修改一下
找到那个vmp调用的函数,然后给他放到全局去
然后直接就是在全局调用
到了这里我们就算完成了80%,因为目前还是在浏览器运行的,剩下的就是nodejs补环境了。补的东西不多。修修补补,一下就能补好。他主要是对roomid进行了一个计算,每次只需要更换 roomid 然后计算出signature即可。