bilibili web端sign分析

环境:未登录
经过初步简单分析,在访问下面这个JS后,才生成的含有sign的链接:

https://static.hdslb.com/player/js/bilibiliPlayer.min.js?v=6b8deee3
https://bangumi.bilibili.com/player/web_api/v2/playurl?cid=34108497&appkey=84956560bc028eb7&otype=json&type=&quality=80&module=bangumi&season_type=4&qn=80&sign=873ad4e420b51ce157f31733353ba397

多次尝试发现,这个链接的sign是一个固定值,只有改变qn(清晰度)的时候,sign才发生改变
比如

https://bangumi.bilibili.com/player/web_api/v2/playurl?cid=34108497&appkey=84956560bc028eb7&otype=json&type=&quality=64&module=bangumi&season_type=4&qn=64&sign=52a7209153346b02983bc98a74d39ace

在其他浏览器下操作也是如此

https://bangumi.bilibili.com/player/web_api/v2/playurl?cid=34108497&appkey=84956560bc028eb7&otype=json&type=&quality=80&module=bangumi&season_type=4&qn=80&sign=873ad4e420b51ce157f31733353ba397

进一步分析
对JS格式化之后,搜索web_api/v2/ 很快可以定位到


image.png

继续顺藤摸瓜
再返回的json数据中开头是 accept_format
搜索得到


image.png

可以判断,这里是对接收到的数据解析,对视频地址进行播放
那么在这里添加一句,重定向JS
image.png

确实是对数据解析


image.png

把这个函数收起来,刚好可以发现这和最开始搜索的链接挨着的,同时发现调用了解析数据的函数,那么接口请求的链接也应该在这里
image.png

image.png

通过console可以看到
b就是接口链接
f.Hc值为true
f.reject是一个函数
this.url没有值
重新更改js,在这三个地方比较b的不同之处
image.png

image.png

可以看到后面两个地方b的值并没有改变,而在通过函数 b = c.a.B(b);后b直接成为了完整的接口链接 (实际上在执行这个函数前b的值为定值6330776) 输出函数c.a.B
image.png

该函数如下

function m(b, c) {
    if (0 === c || !b) return "";
    for (var d = 0, e, f = 0;;) {
        e = T[b + f >> 0];
        d |= e;
        if (0 == e && !c) break;
        f++;
        if (c && f == c) break
    }
    c || (c = f);
    e = "";
    if (128 > d) {
        for (; 0 < c;) {
            d = String.fromCharCode.apply(String, T.subarray(b, b + Math.min(c, 1024)));
            e = e ? e + d : d;
            b += 1024;
            c -= 1024;
        }
        return e
    }
    return v.IC(b)
}

同样的,多次console.log后,有以下结果:
无论何种清晰度都会执行下面这个函数来得到请求接口的完整链接
c.a.$B(b)
且b总是6330776
在被调用函数中

        for (; 0 < c;) {
            d = String.fromCharCode.apply(String, T.subarray(b, b + Math.min(c, 1024)));
            e = e ? e + d : d;
            b += 1024;
            c -= 1024;
        }

此循环只循环了一次,d的初始值是127;c的初始值是定值192;
第一次循环,自减1024位-832,循环结束。
e为完整链接,d在一次循环结束,即

d = String.fromCharCode.apply(String, T.subarray(b, b + Math.min(c, 1024)));

这一句执行了一次之后就是完整链接了
对于循环:

    for (var d = 0, e, f = 0;;) {
        e = T[b + f >> 0];
        d |= e;
        if (0 == e && !c) break;
        f++;
        if (c && f == c) break
    }

添加console.log(b);console.log(f);
有如下结果:


image.png

image.png

image.png

即,b的值没有变化,f的值从1增加到192
对于console.log(e)结果如下(紧跟for循环中括号后)


image.png

image.png

实际上关键就是e,这一些数字是ASCII码,将其对应转换为字母数字,就是完整的视频接口请求链接


image.png

绕了半天,这里才是sign的算法入口,但是我也就止步于此了,完全没有明白这个函数是什么操作...
比如在
console.log(e)
for (var d = 0, e, f = 0;;) {

使用console.log(e),e是undefined

console.log(e)
e = T[b + f >> 0];

但这样在循环内使用使用console.log(e)
e又是有值的,为104
更神奇的是就算按下面这样

e = T[b + f >> 0];
console.log(e)

e首次的值也是104(没学JS,有理解错误请指正)
那这个T呢,又是什么
通过alert显示是这个,数据太多,无法显示完整,就是用console也没法完整输出

101,109,115,99,0,0,0,0,136,1,0,0,153,1,0,0,170,1,0,0,187,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,180,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,108,96,97,101,97,62,61,60,98,100,51,63,102,57,100,61,0,12,85,86,87,15,85,80,86,87,92,84,6,1,84,84,82,0,121,116,38,122,112,40,116,120,114,122,114,121,45,35,32,38,0,5,6,13,89,2,80,81,11,86,...,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

看起来是一组数字序列
根据
e = T[b + f >> 0];
来看,b是定值,f每次加1,如果说T是固定的,那么无论如何返回的链接应该是一样的,但没有,所以是每一次请求T就会有变化,但是这是如何进行的,不知从何下手。。
用了一个循环

for (var prop in T) {console.log("T." + prop + " = " + T[prop]);}

然后一直输出到1.3W,网页卡了,后面基本全是0
换了个姿势


image.png

切换清晰度,发现是一样的


image.png

但增加循环次数。发现似乎...T很长,没有规律
设定为12000次
这是最末尾的输出
image.png

根据对代码的统计,应该有10240个数
+1就是1024*10个数,JS前面有T.set([])
这种的东西,[]内有10240个数,应该和这个是对应的,但是没有发现什么关联...



完整的T序列
2018-7-10 新进展
W是一个长为16777216的数组(2^24,应该是一个没有上限的数组),通过取W的6330680到6330872位,即共192位的值,即ASCII码,再转换为字符即是接口链接。
现在的问题是W是在怎么产生的

v.RC = W = new Uint8Array(I);

这里W初始化(?)的长度为16777216,全0

在25861行左右有m([136, 1, 0, 0, 153, 1, 0, 0, 170, 1, 0这样的序列


image.png

调用的是25191行左右function m(c, d, f, g) {这个函数


image.png

注意这一句
if ("i8" === h) return c.subarray || c.slice ? W.set(c, l) : W.set(new Uint8Array(c), l), l;

那么此处是会改变W的值的,另有一处


image.png

这里验证了,应该是没起作用
需要考察的是下面这几个地方


!!!

5处是前面说的初始值
3处验证过,在sign有了之后才执行的,也可以不管
2处就是取W从6330680到6330872的值,随后按ASCII对应字符转换就是接口链接
4处的两个从表面看是不会对W有影响(修改之类),除非这个函数嵌套了1处的函数。
下面图是1处所在函数的情况


image.png

关注这几个地方
image.png

第一个地方,G.n是定值8
image.png

第二个地方,也是固定的东西


image.png

第三个地方
image.png

这个地方貌似也没执行,第四个地方也是。
最后一个明显是会执行函数m,但是是"i32",那么不会对W产生影响。
现在关心第一个。
。。
不过突然发现有漏了的,26112也是执行了m的
image.png

是固定的
测试发现这两个地方都只执行了一次,那就是固定值。
那现在分析这个地方
image.png

Fa.push只是也执行了一次
4次W.set中 ma均为1052144,同时测试了这四个地方的W在中间范围都是0

到现在好像还是没找到哪里真正改了W的值
把全部大写W的地方都大概看了下,,没发现什么东西。。好奇怪啊
这个函数l似乎也没有地方调用


image.png

难道是其他JS脚本调用?

其他发现,这个地方里面列表供256个数字


image.png

这个地方供2958个数字


image.png

有趣的是:
image.png

另外video.min.js也是有很多一样的部分的


image.png

也许是这个js?
先折腾到这里吧~~

你可能感兴趣的:(bilibili web端sign分析)