上一节课我们已经找到了生成signature这个字段的代码位置,就是这个B函数,嗯......听起来好像有点奇怪,但是它确实叫B啊,笑死。不管了,看一下里面的逻辑是啥。
注意e参数的内容是:
{
"app_name": "douyin_web",
"version_code": "180800",
"webcast_sdk_version": "1.0.14-beta.0",
"update_version_code": "1.0.14-beta.0",
"compress": "gzip",
"device_platform": "web",
"cookie_enabled": true,
"screen_width": 1512,
"screen_height": 982,
"browser_language": "zh-CN",
"browser_platform": "MacIntel",
"browser_name": "Mozilla",
"browser_version": "5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
"browser_online": true,
"tz_name": "Asia/Shanghai",
"cursor": "t-1718942296076_r-1_d-1_u-1_h-7382800685396382772",
"internal_ext": "internal_src:dim|wss_push_room_id:7382777844734167858|wss_push_did:7347516590731134502|first_req_ms:1718942295989|fetch_time:1718942296076|seq:1|wss_info:0-1718942296076-0-0|wrds_v:7382800932146251064",
"host": "https://live.douyin.com",
"aid": "6383",
"live_id": 1,
"did_rule": 3,
"endpoint": "live_pc",
"support_wrds": 1,
"user_unique_id": "7347516590731134502",
"im_path": "/webcast/im/fetch/",
"identity": "audience",
"need_persist_msg_count": "15",
"insert_task_id": "",
"live_reason": "",
"room_id": "7382777844734167858",
"heartbeatDuration": "0"
}
注意t是很多参数的e里面的websocket_key数组,它里面是:
[
{
param_name: 'live_id',
param_type: 'string',
},
{
param_name: 'aid',
param_type: 'string',
},
{
param_name: 'version_code',
param_type: 'string',
},
{
param_name: 'webcast_sdk_version',
param_type: 'string',
},
{
param_name: 'room_id',
param_type: 'string',
},
{
param_name: 'sub_room_id',
param_type: 'string',
},
{
param_name: 'sub_channel_id',
param_type: 'string',
},
{
param_name: 'did_rule',
param_type: 'string',
},
{
param_name: 'user_unique_id',
param_type: 'string',
},
{
param_name: 'device_platform',
param_type: 'string',
},
{
param_name: 'device_type',
param_type: 'string',
},
{
param_name: 'ac',
param_type: 'string',
},
{
param_name: 'identity',
param_type: 'string',
},
]
有了这两个参数传递过来,那我们就可以安心研究B里面的逻辑了。
看一下这个for循环吧,它的逻辑就是取出e里面的参数(将t里面的参数名称),然后拼接到o这个字符串上,然后再把o传递给V()这个函数:
V()这个函数里面又做了什么事情呢?V()其实会返回一个函数,这个函数可以传递两个参数,
接下来继续看返回的这个函数里面代码逻辑:
其实这里继续深入研究,会发现是把e参数转为Bytes数组了:
这个转换函数也可以自己写一个:
const o =
',live_id=1,aid=6383,version_code=180800,webcast_sdk_version=1.0.14-beta.0,room_id=7382777844734167858,sub_room_id=,sub_channel_id=,did_rule=3,user_unique_id=7347516590731134502,device_platform=web,device_type=,ac=,identity=audience'
const substr = o.substring(1)
console.log('subStr----', substr)
// 将字符串转Bytes数组
const stringToBytes = (str) => {
var array = new Uint8Array(str.length)
for (var i = 0, l = str.length; i < l; i++) {
array[i] = str.charCodeAt(i)
}
return array
}
console.log('字符串转为Bytes数组', stringToBytes(substr))
转换完之后,又使用wordsToBytes函数将结果转成了另外一个形式:
然后再调用bytesToHex函数:
const bytesToHex = function (e) {
for (var t = [], r = 0; r < e.length; r++)
t.push((e[r] >>> 4).toString(16)), t.push((15 & e[r]).toString(16))
return t.join('')
}
转换之后的结果格式为:a5faced0e2965a966b9fde2044e3ff1e
然后再调用frontierSign函数将上面这串字符串转为signature的值:
但是这个frontierSign是啥呢?这是一个webmssdk.es5.js包里面的函数,所以需要将这个webmssdk.es5.js包下载到本地,然后集成到window对象上,就可以调用这个函数了,我这里写了一个demo:可以看到已经生成了值
demo代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="./vFun.js"></script>
<script src="./webmssdk.es5.js"></script>
</head>
<body>
<div>测试代码</div>
</body>
<script>
const config = [
{
param_name: 'live_id',
param_type: 'string',
},
{
param_name: 'aid',
param_type: 'string',
},
{
param_name: 'version_code',
param_type: 'string',
},
{
param_name: 'webcast_sdk_version',
param_type: 'string',
},
{
param_name: 'room_id',
param_type: 'string',
},
{
param_name: 'sub_room_id',
param_type: 'string',
},
{
param_name: 'sub_channel_id',
param_type: 'string',
},
{
param_name: 'did_rule',
param_type: 'string',
},
{
param_name: 'user_unique_id',
param_type: 'string',
},
{
param_name: 'device_platform',
param_type: 'string',
},
{
param_name: 'device_type',
param_type: 'string',
},
{
param_name: 'ac',
param_type: 'string',
},
{
param_name: 'identity',
param_type: 'string',
},
]
// 使用for便利试试
for (let { param_name: i } of config) {
console.log('i----', i)
}
const o =
',live_id=1,aid=6383,version_code=180800,webcast_sdk_version=1.0.14-beta.0,room_id=7382772251994655488,sub_room_id=,sub_channel_id=,did_rule=3,user_unique_id=7347516590731134502,device_platform=web,device_type=,ac=,identity=audience'
const substr = o.substring(1)
console.log('subStr----', substr)
// s函数就是stringToBytes
const sResult = sFunc(substr)
// V()函数就是
console.log('s函数stringToBytes结果', sResult)
// 有了s的返回结果,再调用i.wordsToBytes
// var r = i.wordsToBytes(s(e, t));
const r = wordsToBytes(sResult)
console.log('r----', r)
// 最后调用bytesToHex;
// return t && t.asBytes ? r : t && t.asString ? a.bytesToString(r) : i.bytesToHex(r)
const bytesRes = bytesToHex(r)
console.log('bytesRes----', bytesRes)
const frontierSignRes = window.byted_acrawler.frontierSign({
'X-MS-STUB': bytesRes,
})
console.log('frontierSignRes----', frontierSignRes)
</script>
</html>
vFun.js的代码如下:
var sFunc = function (e, t) {
// 判断e是不是string类型,是的话,把t赋值给e,然后
e.constructor == String
? stringToBytes(e)
: oFunc(e)
? (e = Array.prototype.slice.call(e, 0))
: Array.isArray(e) || e.constructor === Uint8Array || (e = e.toString())
for (
var r = bytesToWords(e),
l = 8 * e.length,
c = 1732584193,
u = -271733879,
p = -1732584194,
d = 271733878,
h = 0;
h < r.length;
h++
)
r[h] =
(((r[h] << 8) | (r[h] >>> 24)) & 16711935) |
(((r[h] << 24) | (r[h] >>> 8)) & 4278255360)
;(r[l >>> 5] |= 128 << l % 32), (r[(((l + 64) >>> 9) << 4) + 14] = l)
for (var m = sff, f = sgg, g = shh, _ = sii, h = 0; h < r.length; h += 16) {
var v = c,
C = u,
y = p,
T = d
;(c = m(c, u, p, d, r[h + 0], 7, -680876936)),
(d = m(d, c, u, p, r[h + 1], 12, -389564586)),
(p = m(p, d, c, u, r[h + 2], 17, 606105819)),
(u = m(u, p, d, c, r[h + 3], 22, -1044525330)),
(c = m(c, u, p, d, r[h + 4], 7, -176418897)),
(d = m(d, c, u, p, r[h + 5], 12, 1200080426)),
(p = m(p, d, c, u, r[h + 6], 17, -1473231341)),
(u = m(u, p, d, c, r[h + 7], 22, -45705983)),
(c = m(c, u, p, d, r[h + 8], 7, 1770035416)),
(d = m(d, c, u, p, r[h + 9], 12, -1958414417)),
(p = m(p, d, c, u, r[h + 10], 17, -42063)),
(u = m(u, p, d, c, r[h + 11], 22, -1990404162)),
(c = m(c, u, p, d, r[h + 12], 7, 1804603682)),
(d = m(d, c, u, p, r[h + 13], 12, -40341101)),
(p = m(p, d, c, u, r[h + 14], 17, -1502002290)),
(u = m(u, p, d, c, r[h + 15], 22, 1236535329)),
(c = f(c, u, p, d, r[h + 1], 5, -165796510)),
(d = f(d, c, u, p, r[h + 6], 9, -1069501632)),
(p = f(p, d, c, u, r[h + 11], 14, 643717713)),
(u = f(u, p, d, c, r[h + 0], 20, -373897302)),
(c = f(c, u, p, d, r[h + 5], 5, -701558691)),
(d = f(d, c, u, p, r[h + 10], 9, 38016083)),
(p = f(p, d, c, u, r[h + 15], 14, -660478335)),
(u = f(u, p, d, c, r[h + 4], 20, -405537848)),
(c = f(c, u, p, d, r[h + 9], 5, 568446438)),
(d = f(d, c, u, p, r[h + 14], 9, -1019803690)),
(p = f(p, d, c, u, r[h + 3], 14, -187363961)),
(u = f(u, p, d, c, r[h + 8], 20, 1163531501)),
(c = f(c, u, p, d, r[h + 13], 5, -1444681467)),
(d = f(d, c, u, p, r[h + 2], 9, -51403784)),
(p = f(p, d, c, u, r[h + 7], 14, 1735328473)),
(u = f(u, p, d, c, r[h + 12], 20, -1926607734)),
(c = g(c, u, p, d, r[h + 5], 4, -378558)),
(d = g(d, c, u, p, r[h + 8], 11, -2022574463)),
(p = g(p, d, c, u, r[h + 11], 16, 1839030562)),
(u = g(u, p, d, c, r[h + 14], 23, -35309556)),
(c = g(c, u, p, d, r[h + 1], 4, -1530992060)),
(d = g(d, c, u, p, r[h + 4], 11, 1272893353)),
(p = g(p, d, c, u, r[h + 7], 16, -155497632)),
(u = g(u, p, d, c, r[h + 10], 23, -1094730640)),
(c = g(c, u, p, d, r[h + 13], 4, 681279174)),
(d = g(d, c, u, p, r[h + 0], 11, -358537222)),
(p = g(p, d, c, u, r[h + 3], 16, -722521979)),
(u = g(u, p, d, c, r[h + 6], 23, 76029189)),
(c = g(c, u, p, d, r[h + 9], 4, -640364487)),
(d = g(d, c, u, p, r[h + 12], 11, -421815835)),
(p = g(p, d, c, u, r[h + 15], 16, 530742520)),
(u = g(u, p, d, c, r[h + 2], 23, -995338651)),
(c = _(c, u, p, d, r[h + 0], 6, -198630844)),
(d = _(d, c, u, p, r[h + 7], 10, 1126891415)),
(p = _(p, d, c, u, r[h + 14], 15, -1416354905)),
(u = _(u, p, d, c, r[h + 5], 21, -57434055)),
(c = _(c, u, p, d, r[h + 12], 6, 1700485571)),
(d = _(d, c, u, p, r[h + 3], 10, -1894986606)),
(p = _(p, d, c, u, r[h + 10], 15, -1051523)),
(u = _(u, p, d, c, r[h + 1], 21, -2054922799)),
(c = _(c, u, p, d, r[h + 8], 6, 1873313359)),
(d = _(d, c, u, p, r[h + 15], 10, -30611744)),
(p = _(p, d, c, u, r[h + 6], 15, -1560198380)),
(u = _(u, p, d, c, r[h + 13], 21, 1309151649)),
(c = _(c, u, p, d, r[h + 4], 6, -145523070)),
(d = _(d, c, u, p, r[h + 11], 10, -1120210379)),
(p = _(p, d, c, u, r[h + 2], 15, 718787259)),
(u = _(u, p, d, c, r[h + 9], 21, -343485551)),
(c = (c + v) >>> 0),
(u = (u + C) >>> 0),
(p = (p + y) >>> 0),
(d = (d + T) >>> 0)
}
return endian([c, u, p, d])
}
// (s._blocksize = 16)
// (s._digestsize = 16)
const sff = function (e, t, r, i, n, o, a) {
var s = e + ((t & r) | (~t & i)) + (n >>> 0) + a
return ((s << o) | (s >>> (32 - o))) + t
}
const sgg = function (e, t, r, i, n, o, a) {
var s = e + ((t & i) | (r & ~i)) + (n >>> 0) + a
return ((s << o) | (s >>> (32 - o))) + t
}
const shh = function (e, t, r, i, n, o, a) {
var s = e + (t ^ r ^ i) + (n >>> 0) + a
return ((s << o) | (s >>> (32 - o))) + t
}
const sii = function (e, t, r, i, n, o, a) {
var s = e + (r ^ (t | ~i)) + (n >>> 0) + a
return ((s << o) | (s >>> (32 - o))) + t
}
const stringToBytes = function (str) {
var array = new Uint8Array(str.length)
for (var i = 0, l = str.length; i < l; i++) {
array[i] = str.charCodeAt(i)
}
return array
}
const oFunc = function (e) {
return (
null != e &&
(t(e) ||
('function' == typeof e.readFloatLE &&
'function' == typeof e.slice &&
t(e.slice(0, 0))) ||
!!e._isBuffer)
)
}
const bytesToWords = function (e) {
for (var t = [], r = 0, i = 0; r < e.length; r++, i += 8)
t[i >>> 5] |= e[r] << (24 - (i % 32))
return t
}
const wordsToBytes = function (e) {
for (var t = [], r = 0; r < 32 * e.length; r += 8)
t.push((e[r >>> 5] >>> (24 - (r % 32))) & 255)
return t
}
const endian = function (e) {
if (e.constructor == Number)
return (16711935 & rotl(e, 8)) | (4278255360 & rotl(e, 24))
for (var t = 0; t < e.length; t++) e[t] = endian(e[t])
return e
}
const rotl = function (e, t) {
return (e << t) | (e >>> (32 - t))
}
const bytesToHex = function (e) {
for (var t = [], r = 0; r < e.length; r++)
t.push((e[r] >>> 4).toString(16)), t.push((15 & e[r]).toString(16))
return t.join('')
}