【JS逆向】破解B站登录加密策略
2021-01-04 21:50
417 查看
昨天还立flag说今天不摸鱼了,结果又摸了半天,稍微总结一下。GitHub上有一个叫做「哔哩哔哩-API收集整理」[1]的仓库,这个仓库是之前破解第三方B站视频下载方式的时候明一gg发给我的,当时没有看的很仔细,今天又找出来看了看里面的文档,解决了很多之前的疑惑。
返回Network请求列表,仔细查找,果然在登录前面找到这样一个请求:
获取key和challenge的API)这次请求的响应包含了
旁边的师兄看到我又在不务正业,在写这些确实没什么卵用的代码,教育我说道:“霏霏你这样每天不科研是没法毕业的,你看看人家大师兄顶会一篇接一篇地发,你不惭愧吗?”。我留下了不务正业的眼泪,泪水打湿了板烧鸡腿堡[3]。
登录有什么用——获取cookie
上一篇推文里,随口提了一句登录的作用。登录以后可以获得更多的权限,比如发帖、收藏等功能,此外有些内容只有登录以后才能访问。对于B站来说,注册成为正式会员以后可以点赞、投币、收藏喜欢的视频,也算对up主小小的鼓励。此外,不管通过什么途径(插件、客户端等等),想要下载720P及以上的视频,都需要保持登录状态,如果想要下载的是大会员的专属视频,那么需要的就是大会员的cookie。
而那些第三方的下载网站,原理无非是网站的管理员持有多个账号,然后用这些账号登录后的cookie来获取视频的下载链接。而显然,一个个账号手动登录再把cookie保存下来是不现实的,所以才需要用爬虫程序来完成登录。关于视频流会员鉴权:
- 获取720P及以上清晰度视频时需要登录(Cookie)
- 获取高帧率(1080P60)/高码率(1080P+)视频时需要有大会员的账号登录(Cookie)
- 获取会员专属视频时需要登录(Cookie)
找齐所需参数
首先按照之前提到的套路,用错误的密码进行登录。 登录B站的Form Data需要的参数如下:captchaType
、keep
、goUrl
为固定参数username
:用户名,这里填的是手机号password
:加密过后的密码,看到最后的=可以猜测是加密以后再用Base64编码key
、challenge
、validate
、seccode
:加密参数,来源暂时未知
key和
challenge都是从B站的API获取的,而
validate和
seccode是从「极验」获取的。
参数名 | 类型 | 内容 | 必要性 | 备注 |
---|---|---|---|---|
captchaType | num | 6 | 必要 | 必须为6 |
username | str | 用户登录账号 | 必要 | 手机号或邮箱地址 |
password | str | 加密后的带盐密码 | 必要 | base64格式 |
keep | bool | true | 必要 | 必须为true |
key | str | 登录秘钥 | 必要 | 从B站API获取 |
challenge | str | 极验challenge | 必要 | 从B站API获取 |
validate | str | 极验结果 | 必要 | 从极验获取 |
seccode | str | 极验结果 | 必要 | 从极验获取 |
key和
challenge,此外还有一个参数
gt。响应中的key和challenge那么剩下的
validate和
seccode是怎么来的呢?在请求列表中继续往下找,可以找到这样一个请求: 获取验证码的POST请求它的响应包含了刚才登录时弹出的验证码: 响应中包含验证码地址将
image_servers中的任意一个字符串和
pic字符串拼接后就得到了验证码的图片地址: 验证码图示按照顺序点击“越”、“橘”、“红”后生成一个
w参数,再次发起请求得到
validate和
seccode(
seccode就是
validate后面拼接一个
|jordan): 响应中的validate到这里我们已经知道所有参数的来源了,我画了一张图来表示这个过程: 参数生成流程图
破解加密策略
全局搜索password关键字,可以找到11个文件,注意到这个login开头的js文件,相当可疑。 全局搜索password在文件中再次搜索
password,找到这个地方,不出意外应该就是
password赋值的地方,打上一个断点: 定位到加密处打上断点以后,重新点击登录, 确认是在这里加密可以看出密码是在
s = this.encryptPassword(this.password)这行代码中被加密的,加密函数为
this.encryptPassword
进入函数内部
加密函数可以看到这里用到了JSEncrypt库,这个库是专门用来做
RSA加密的,
hash和
key包含在另一个响应中: 响应中的公钥现在分析一下密码加密的逻辑:
- 通过GET https://passport.bilibili.com/login?act=getkey&r=随机数这个API来获取
RSA
加密的参数hash
和key
- 将
key
设置为公钥 - 将字符串
hash
和原始密码拼接,然后进行RSA加密
import random
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
password = 'xxxxxx'
r = requests.get('https://passport.bilibili.com/login?act=getkey&r={}'.format(random.random()))
key, _hash = r.json()['key'], r.json()['hash']
rsa_key = RSA.importKey(key)
cipher = Cipher_pkcs1_v1_5.new(rsa_key)
crypted_password = base64.b64encode(cipher.encrypt((_hash + password).encode("utf-8"))).decode('utf8')
“破解”验证码
之所以加了引号是因为我走了个后门,并没有实际解决验证码的加密流程——如何获取参数w。经过一番网上冲浪,我查到有一个叫「2captcha」[2]的网站专门处理各种各样的验证码,其中就有「极验」。 2captcha提供的服务收费是每1000次请求2.99美元,用支付宝就可以支付,于是我为了试一试这个服务就付了3美元。 优埃斯刀了
超时——hash是有寿命的
我把刚才的想法实现完以后,得到的响应是这样的: 提交超时这个「提交超时」是咋回事呢?我测试了一下输入错误的密码和错误的验证信息都会得到不同的报错信息。 账号密码错误 验证码参数错误于是只能再次求助「哔哩哔哩-API收集整理」[1]了,一番查阅之后查到了如下内容: hash是有寿命的到这里我终于搞明白我之前失败的原因了——每次验证都需要30秒左右的时间,hash早就过期了。于是调整一下顺序,先进行验证,再对密码进行加密,然后就成功啦。 成功登录之后整理一下代码,会发在原文链接指向的GitHub仓库中。
旁边的师兄看到我又在不务正业,在写这些确实没什么卵用的代码,教育我说道:“霏霏你这样每天不科研是没法毕业的,你看看人家大师兄顶会一篇接一篇地发,你不惭愧吗?”。我留下了不务正业的眼泪,泪水打湿了板烧鸡腿堡[3]。
相关文章推荐
- 【JS逆向】破解知乎登录加密策略
- 【JS逆向】破解第三方B站视频下载加密策略
- 【JS逆向】破解DeepL和有道翻译加密策略
- python 反反爬虫策略之js动态加密url破解
- 兄弟,别再爬妹子图了整点JS逆向吧--陆金所密码加密破解
- 【JS逆向破解】爬虫抓取哦oh漫画实例Java/Python实现
- 破解极验验证码之模拟登录B站
- 用js一招破解所有网页的加密源代码的方法
- 爬虫(js加密)-关于有道翻译的js加密简单破解
- node.js 登录跳转(无加密,无session,ajax,post)
- 逆向小程序破解js-(逆向篇)
- iOS逆向工程-静态分析-破解登录
- 基于角色的权限管理系统--前端登录数据js加密后端解密(DES)
- Python爬虫—破解JS加密的Cookie
- PCASClass.js破解加密
- 用js一招破解所有网页的加密源代码的方法
- 使用KRPano资源分析工具强力加密KRPano项目(XML防破解,切片图保护,JS反调试)
- 二.爬虫--破解网站通过js加密生成cookie(二)
- 加密Js的破解显示
- app逆向实战强化篇——破解某安卓APP请求加密参数