hksnow 发表于 2020-6-3 11:50

课后网登录+课程回放分析及代码实现

本帖最后由 hksnow 于 2020-6-3 11:55 编辑

# 课后网登录+课程回放分析及代码实现

## 0x01 前言
上课没跟上,准备看回放,登录过程中就想能不能搞一搞,写完笔记后就抓包分析了一下。我们上网课使用的是课后网(无限宝),于是就有了这篇帖子。分析+帖子排版耗时大概4h,肝到12:20。
## 0x02 工具及开发环境
- Charles(我叫它'插花瓶')
- Google Chrome
- Visual Studio Code
- Python 3.8.1
- JS调试工具
- nodejs


## 0x03 分析
### Login
**登录首页**
https://center.kehou.com/login.htm?serverId=1&url=https%3A%2F%2Fhljskzkt.db.kehou.com%2Findex.htm&platform=db&aid=3
- 获取验证码
https://center.kehou.com/scriptInit.htm?callback=onCallBack&scriptId=()&serverId=5&signature=()
这里获取验证码的scriptid对应**首页网页源码**script_id,signature对应init_req_sign

![](https://gitee.com/hkslover/blog_img/raw/master/2020/06/00/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20200602123352.png)

![](
https://gitee.com/hkslover/blog_img/raw/master/2020/06/00/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20200602123458.png)

```python
response = requests.get(url,headers = headers1)
html_content = response.text.replace(' ','').replace('\t','').replace('\n','').replace('\\','')
#signature = re.findall('id="signature"value="(.*?)"',html_content,re.S)
script_id = re.findall("script_id:\'(.*?)'",html_content,re.S)
init_req_sign = re.findall("init_req_sign:\'(.*?)'",html_content,re.S) # 获取验证码用的'signature'
login_init_sign = re.findall("login_init_sign:\'(.*?)'",html_content,re.S) # 登录用的'signature'
login_encry_key = re.findall("login_encry_key:\'(.*?)'",html_content,re.S) # 登录用的加密key
url = 'https://center.kehou.com/scriptInit.htm?callback=onCallBack&scriptId=' + script_id + '&serverId=5&signature=' + init_req_sign
response = requests.get(url,headers = headers2)
Token_id = re.findall('"Token_id":"(.*?)"',response.text,re.S)
verify_url = 'https://center.kehou.com/verifyCode.htm?tokenId=' + Token_id
response = requests.get(verify_url)
with open('verify.png','wb') as f:
    f.write(response.content)
```

-构造登陆数据

**登录网址**
https://center.kehou.com/scriptLogin.htm

账号111111111密码2222222222的登陆数据(get)
>loginType SCRIPT_LOGIN
callbackon CallBack
loginField 1111111111
password      2e3129c366b4455dfe50c587d94c122b
platform      db
serverId      5
verifyCode      2305
ruleId      DEFAULT
url      https://hljskzkt.db.kehou.com/index.htm
signature      2167c852971b961e31c8a76e5d0cc26e
aid      3
scriptId      91D3D5E14ECB42C98F2AA0F304C96CB6
tokenId      B5DCE5867EB347A38ECC775A894494FE
loginSign      ALWAYS_ASK
_      1591072403658

经前后检查,发现登陆数据signature为**登陆首页源码**的login_init_sign,tokenId为获取验证码时的tokenId。

**可以看到只有一个数据是加密的:password,这里浏览器调试工具搜索关键字**
![](
https://gitee.com/hkslover/blog_img/raw/master/2020/06/00/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20200602124854.png)
**跟踪scriptLogin**
![](
https://gitee.com/hkslover/blog_img/raw/master/2020/06/00/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20200602125022.png)
经前后检查,发现加密loginParam.login_encry_key为**登录首页**获取的login_encry_key,pw_id_val为密码明文
这里已经很明显了,password的加密过程,**把部分代码放到js调试工具,构造加密函数,获取加密返回值**
![](
https://gitee.com/hkslover/blog_img/raw/master/2020/06/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20200602001009.png)

- 提交登陆数据后

**返回响应内容**
> onCallBack('{"Status":true,"Multil":false,"LoginType":"SCRIPT_LOGIN","Users":[{"realName":"","agencyDomain":"hdb.kehou.com","agencyName":"省空中课
堂(db)","url":"https://login.db.kehou.com/centerFastLogin.htm?serverId=5&loginField=9327C569571DB040410CB3A61DDBE9A4B884BD1D0E781FDF7754F966385485AD041AB947B97D408F3C&loginSign=ALWAYS_ASK×tamp=159100430&signature=c5316eca4ba83e81936&url=%2F%2Fhljskzkt.db.kehou.com","username":"18198"}],"Section":"login"}');

(部分内容已经清理,涉及个人信息)

抓包分析下一步访问的网址在相应内容的基础上增加了Token和script_id

```python
url = re.findall('"url":"(.*?)"',response.text,re.S) + '&tokenId=' + Token_id + '&scriptId=' + script_id
```
访问这个新构造的url,即可完成登录过程
```python

headers3 = {
      'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36',
      'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
      'sec-fetch-site': 'same-site',
      'sec-fetch-mode': 'navigate',
      'sec-fetch-user': '?1',
      'sec-fetch-dest': 'document',
      'referer': 'https://center.kehou.com/login.htm?serverId=1&url=https%3A%2F%2Fhljskzkt.db.kehou.com%2Findex.htm&platform=db&aid=3'
    }
    response = requests.get(url,headers = headers3)

```

再次访问课程网页可以看到已经可以获取点播课程,说明登录获取的cookie生效
![](
https://gitee.com/hkslover/blog_img/raw/master/2020/06/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20200602000853.png)

### login细节说明及问题

1,上文可以看到我在js调试工具里已经获取到pwd的加密内容,但在python里却不能正常获取。

![](https://gitee.com/hkslover/blog_img/raw/master/2020/06/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20200602113230.png)

<u>**解决办法:在运行目录执行npm install cryptojs,再在js里引用模块**</u>

```python
def get_password(login_encry_key,password):
    with open('getpwd.js','r') as f:
      js_code = f.read()
    encrypt_password = execjs.compile(js_code).call('getpwd',login_encry_key,password)
    return encrypt_password
```
```js
function getpwd(login_encry_key, password) {
    var CryptoJS = require('crypto-js');
    var key = CryptoJS.enc.Hex.parse(login_encry_key);
    var iv = CryptoJS.enc.Hex.parse("30313233343536373839414243444546");
    var securityPwd = CryptoJS.AES.encrypt(password, key, {
      iv: iv,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7
    }).ciphertext.toString();
    return securityPwd;
}
```
<u>**另外这里应该可以用python直接实现加密,奈何本人不会,直接用现成的js代码实现,如果有大神会的话希望可以分享下代码,谢谢!**</u>
2,使用
```python
requests = requests.session()
```
帮助处理cookie,避免**
3,这类登录实现一定要注意headers,尤其referer字段,如果错误,访问无法继续,**耽误我最长时间的就是这个referer**

### 完整的登录代码(python配合js)
```python

import requests
import execjs
import re
import time
requests = requests.session()
headers2 = {
      'referer': 'https://center.kehou.com/login.htm?serverId=1&url=https%3A%2F%2Fhljskzkt.db.kehou.com%2Findex.htm&platform=db&aid=3',
      'sec-fetch-dest': 'script',
      'sec-fetch-mode':'no-cors',
      'sec-fetch-site': 'same-site',
      'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36'
}
def login(user,password,verify,Token_id,login_init_sign,login_encry_key,script_id):
    url = 'https://center.kehou.com/scriptLogin.htm'
    encrypt_password = get_password(login_encry_key,password)
    params = {'loginType': 'SCRIPT_LOGIN','callback': 'onCallBack','loginField': user,'password': encrypt_password,'platform': 'zj','serverId': '5','verifyCode': verify,'ruleId': 'DEFAULT','url': 'https://hljskzkt.db.kehou.com/index.htm','signature': login_init_sign,'aid': '-1','scriptId': script_id,'tokenId': Token_id,'loginSign': 'ALWAYS_ASK','_': str(int(round(time.time() * 1000)))}
    response = requests.get(url,params = params,headers = headers2)
    print(response.text)
    url = re.findall('"url":"(.*?)"',response.text,re.S) + '&tokenId=' + Token_id + '&scriptId=' + script_id
    headers3 = {
      'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36',
      'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
      'sec-fetch-site': 'same-site',
      'sec-fetch-mode': 'navigate',
      'sec-fetch-user': '?1',
      'sec-fetch-dest': 'document',
      'referer': 'https://center.kehou.com/login.htm?serverId=1&url=https%3A%2F%2Fhljskzkt.db.kehou.com%2Findex.htm&platform=db&aid=3'
    }
    response = requests.get(url,headers = headers3)
   
    headers4 = {
      'sec-fetch-dest': 'document',
      'sec-fetch-mode': 'navigate',
      'sec-fetch-site': 'none',
      'sec-fetch-user': '?1',
      'upgrade-insecure-requests': '1',
      'referer': 'https://vod.db.kehou.com/vod/myVideoCenter.htm',
      'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36'
    }
    response = requests.get('https://vod.db.kehou.com/vod/myVideoCenter.htm',headers = headers4)
    print(response.text)
def login_initialize():
    headers1 = {
      'sec-fetch-dest': 'document',
      'sec-fetch-mode': 'navigate',
      'sec-fetch-site': 'none',
      'sec-fetch-user': '?1',
      'upgrade-insecure-requests': '1',
      'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36'
    }
    url = 'https://center.kehou.com/login.htm?serverId=1&url=https%3A%2F%2Fhljskzkt.db.kehou.com%2Findex.htm&platform=db&aid=3'
    response = requests.get(url,headers = headers1)
    html_content = response.text.replace(' ','').replace('\t','').replace('\n','').replace('\\','')
    #signature = re.findall('id="signature"value="(.*?)"',html_content,re.S)
    script_id = re.findall("script_id:\'(.*?)'",html_content,re.S)
    init_req_sign = re.findall("init_req_sign:\'(.*?)'",html_content,re.S) # 获取验证码用的'signature'
    login_init_sign = re.findall("login_init_sign:\'(.*?)'",html_content,re.S) # 登录用的'signature'
    login_encry_key = re.findall("login_encry_key:\'(.*?)'",html_content,re.S) # 登录用的加密key
    url = 'https://center.kehou.com/scriptInit.htm?callback=onCallBack&scriptId=' + script_id + '&serverId=5&signature=' + init_req_sign
    response = requests.get(url,headers = headers2)
    Token_id = re.findall('"Token_id":"(.*?)"',response.text,re.S)
    verify_url = 'https://center.kehou.com/verifyCode.htm?tokenId=' + Token_id
    response = requests.get(verify_url)
    with open('verify.png','wb') as f:
      f.write(response.content)
    verify = input("请输入验证码:")
    login('185账号','(密码)',verify,Token_id,login_init_sign,login_encry_key,script_id)
def get_password(login_encry_key,password):
    with open('getpwd.js','r') as f:
      js_code = f.read()
    encrypt_password = execjs.compile(js_code).call('getpwd',login_encry_key,password)
    return encrypt_password
if __name__ == "__main__":
    login_initialize()
```
![](
https://gitee.com/hkslover/blog_img/raw/master/2020/06/00/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20200602131359.png)

### 课程回放(没有python实现,只有分析过程)

在登录解决后,回放获取数据就比较容易了。

**课程主页**
https://vod.db.kehou.com/vod/myVideoCenter.htm

- **获取课程vodid**(课程主页网页源码)
![](
https://gitee.com/hkslover/blog_img/raw/master/2020/06/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20200602120413.png)

- 通过vodid获取课程详情
![](
https://gitee.com/hkslover/blog_img/raw/master/2020/06/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20200602120510.png)

- 通过**详情id**获取视频播放权限状态及信息
![](
https://gitee.com/hkslover/blog_img/raw/master/2020/06/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20200602121232.png)

**获取othermsg以及repoterid**

- 获取视频播放地址post(指定播放器)
![](
https://gitee.com/hkslover/blog_img/raw/master/2020/06/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20200602121256.png)

**这里的uid对应上面获取的othermsg**

**返回的数据去掉':'后面的内容然后通过注册表注册协议打开播放器**

![](
https://gitee.com/hkslover/blog_img/raw/master/2020/06/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20200602121702.png)

## 0x04 其他
1,这个课程回放开始观看后视频1天后失效,无法观看。我刚开始觉得是像服务器提交观看时间,然后计算失效时间,可以突破视频时效。结果并不是这样。
2,Charles(插花瓶)真的好用,安装ssl证书非常简单(包括手机端),界面简洁。目前我使用别人的激活码,后续会支持正版的。
3,这个登录过程感觉用手机user-agent模拟后再分析可能会简单。
4,**加密password调用js绝对不是最好的办法,完全可以用python库解决,如果有大神会的话希望可以分享下代码,再次感谢。**
## 0x05 结尾
网课盼开学,开学想网课。我是东三省的学生,还要过一段时间开学,网课期间学习还是没有在学校认真的。希望大家可以珍惜每一次的学习机会,这次网课经历绝对可以载入史册的(滑稽)。
另外闲谈一句,**感觉网课回放功能有依赖**,哈哈哈上课不认真听了,建议切除。

### 最后祝大家学习进步,工作顺利,多多评分评论哦!

hyzhangyong 发表于 2020-6-3 17:27

python AES解密?
from Crypto.Cipher import AES
key = "xxxxxxxxxx"
iv = "xxxxxxxx"
mode = AES.MODE_CBC
cryptos = AES.new(key, mode, iv)
plain_text = cryptos.decrypt(a2b_hex(text))
securityPwd =bytes.decode(plain_text).rstrip('\0')

hksnow 发表于 2020-6-3 18:19

本帖最后由 hksnow 于 2020-6-3 18:21 编辑

hyzhangyong 发表于 2020-6-3 17:27
python AES解密?
from Crypto.Cipher import AES
key = "xxxxxxxxxx"

出现了 大佬出现了
https://ftp.bmp.ovh/imgs/2020/06/cf726052249f23aa.png
请问这种怎么解决
https://i.loli.net/2020/06/03/S5l9qXkYsDUr8gy.png

kxykxy157 发表于 2020-6-3 13:34

小白看完后直觉大神真牛,第二直觉就是要是能放个成品软件试试就好了?

nightring 发表于 2020-6-3 14:23

膜拜大神啊
支持

hj170520 发表于 2020-6-3 15:11

{:301_986:}又学会了一招“爬虫”,
感谢楼主

hyzhangyong 发表于 2020-6-3 19:54

hksnow 发表于 2020-6-3 18:19
出现了 大佬出现了

请问这种怎么解决

key的位数不足?需要补零。错误提示不够完整。

ciker_li 发表于 2020-6-4 06:34

厉害,厉害

hshcompass 发表于 2020-6-4 10:47

真牛!腾讯课堂可以做吗?

hksnow 发表于 2020-6-4 12:09

hyzhangyong 发表于 2020-6-3 19:54
key的位数不足?需要补零。错误提示不够完整。

我百度了很久也没有解决啊,求个完整的加密代码
页: [1] 2
查看完整版本: 课后网登录+课程回放分析及代码实现