吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 11385|回复: 139
收起左侧

[Web逆向] 智慧职教Mooc(icve-mooc)API分析

    [复制链接]
pengzhengchang 发表于 2022-11-10 20:59

适用https://icve-mooc.icve.com.cn/cms/

主要刷课API

URL:https://course.icve.com.cn/learnspace/course/study/learningTime_saveVideoLearnDetailRecord.action
请求方式:Post
参数:

limitId: 包含在网页的javascript中,每次刷新页面limitId也会刷新,可重复用
studyRecord: 通过crypto-js AES加密的一串数据,包含课程ID,视频ID,以及学习时长,学习起始秒数和学习结束的秒数。

返回结果:”保存状态成功“或者“参数不合法,超出时长”,学习时长越长,需要等待一定时间才能第再次保存学习状态。学习时长短不需要等待。

image-20221110204143266

获取limitId

URL:https://course.icve.com.cn/learnspace/learn/learn/templateeight/index.action?params.courseId=26ae32dc2dcd4c9cbace10894d9a172b___&params.templateType=8&params.templateStyleType=0&params.template=templateeight&params.classId=&params.tplRoot=learn

请求方式: Get

参数:url里面可以看到,主要包含一个课程id,其他的似乎默认就行,可以去浏览器里找到对应的url

返回结果:内容是html网页,直接通过正则搜索找到limitId

image-20221110204249701

studyRecord AES加密的学习状态参数

image-20221110175244805

官方加密功能函数和格式化函数的js文件URL: https://course.icve.com.cn/learnspace/resource/common/js/CommonUtil.js?v=2022042401

studyRecord参数就是将数据格式化后序列化再进行AES加密得到的字符串

主要的参数就只有courseId,itemId,stratTime,endTime:

courseId: 代表当前学习课程的16进制id

itemId: 对应课程中的每个视频或者文档也有一个16进制id

startTime: 对应视频时长进度

endTime: 对应视频的时长,表示当前视频从startTime秒学习到了endTime的秒数

文档内容完成学习API

url:https://course.icve.com.cn/learnspace/course/study/learningTime_saveCourseItemLearnRecord.action

参数:课程id,视频id,其他的参数固定即可

image-20221110205007663

获取itemId

url:https://course.icve.com.cn/learnspace/learn/learn/templateeight/courseware_index.action?params.courseId=26ae32dc2dcd4c9cbace10894d9a172b___

返回的html中包含itmeId,可以通过beautifulsoup搜索id=spoint.* 获得对对应的标签

image-20221110204525033

判断内容是否已经完成

url:https://course.icve.com.cn/learnspace/learn/learnCourseware/getSingleItemCompleteCase.json

返回json,completed等于1表示学习完成,2表示部分学习,0表示内容没有学习过。

image-20221110204811323

效果图

image-20221110205152355

image-20221110205228083

完整py+nodejs代码

py需要安装库: requests bs4

nodejs需要安装库: crypto-js

自行替换python代码中的Cookie,test.js主要是做参数加密,运行python文件即可

import requests
from bs4 import BeautifulSoup
import re
import os
import json
import sys

header = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36',
'Accept':"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
'Accept-Encodign':'gzip, deflate, br',
'Cookie':''
}
header['Cookie'] = ''

#获得limitId
res = requests.get(url='https://course.icve.com.cn/learnspace/learn/learn/templateeight/index.action?params.courseId=26ae32dc2dcd4c9cbace10894d9a172b___¶ms.templateType=8¶ms.templateStyleType=0¶ms.template=templateeight¶ms.classId=¶ms.tplRoot=learn',headers=header)
patter=re.compile('limitId.*;')
try:
    limitId=patter.search(res.content.decode()).group().split('"')[1]
except:
    print('\033[31m获取limitId失败,检查Cookie\033[0m')
    exit()

#获得itemId
res = requests.get('https://course.icve.com.cn/learnspace/learn/learn/templateeight/courseware_index.action?params.courseId=26ae32dc2dcd4c9cbace10894d9a172b___',headers=header)
soup = BeautifulSoup(res.content,'lxml')
divs = soup.find_all(id=re.compile("s_point_.*"),itemtype="video")
itemids = {}
for i in divs:
    itemids[i.find(class_="s_pointti").text]=i['id'].strip("s_point_")

#开始刷课
for key in itemids.keys():
    itemid=itemids[key]
    data2={
        'itemId':itemid,
        'videoTotalTime':'00:10:00'
    }
    total = requests.post(url='https://course.icve.com.cn/learnspace/course/plugins/cloud_updateVideoTotalTime.action',headers=header,data=data2)

    #判断视频是否学习完成
    data2={
        'params.courseId':'26ae32dc2dcd4c9cbace10894d9a172b___',
        'params.itemId':itemid
    }
    complete = requests.post(url='https://course.icve.com.cn/learnspace/learn/learnCourseware/getSingleItemCompleteCase.json',headers=header,data=data2)
    if json.loads(complete.content.decode())['result']['completed'] == '1':
        print(key,'视频状态已完成,跳过')
        continue

    start=0
    end=0
    #轮询片段
    while True:
        start=end
        end=start+10
        #单个视频片段状态保存循环
        while True:
            cmd = os.popen('node ./test.js %s %s %s' % (itemid,start,end))
            studyrecord=cmd.read().strip('\n')
            cmd.close()
            data={
                'limitId':limitId,
                'studyRecord':studyrecord
            }
            res2 = requests.post(url='https://course.icve.com.cn/learnspace/course/study/learningTime_saveVideoLearnDetailRecord.action',headers=header,data=data)
            if '保存成功' in res2.content.decode() or '总时长' in res2.content.decode():
                print("\r", end="")
                print(key,"\033[32m学习时长: {}秒 \033[0m".format(end), end="")
                sys.stdout.flush()
                break
            else:
                pass

        if '总时长' in res2.content.decode():
            break
    print(key,'\033[31m学习完成\033[0m')

#刷文档内容

#取出itemid
divs = soup.find_all(id=re.compile("s_point_.*"),itemtype="doc")
itemids = {}
for i in divs:
    itemids[i.find(class_="s_pointti").text]=i['id'].strip("s_point_")

#轮询item
for key in itemids.keys():
    itemid=itemids[key]

    #判断文档是否学习完成
    data2={
        'params.courseId':'26ae32dc2dcd4c9cbace10894d9a172b___',
        'params.itemId':itemid
    }
    complete = requests.post(url='https://course.icve.com.cn/learnspace/learn/learnCourseware/getSingleItemCompleteCase.json',headers=header,data=data2)
    if json.loads(complete.content.decode())['result']['completed'] == '1':
        print(key,'状态已完成,跳过')
        continue

    #保存文档
    doc_data={
        'courseId':'26ae32dc2dcd4c9cbace10894d9a172b',
        'itemId':itemid,
        'recordType':0,
        'studyTime':300
    }
    response = requests.post(url='https://course.icve.com.cn/learnspace/course/study/learningTime_saveCourseItemLearnRecord.action',headers=header,data=doc_data)
    if '成功' in response.content.decode():
        print(key,'完成')
    else:
        print(key,'保存失败')
        set_trace()

test.js:

const CryptoJS = require("crypto-js");

const encrypt = function (e) {
    var f = CryptoJS.enc.Utf8.parse("learnspaceaes123");
    var d = CryptoJS.AES.encrypt(e, f, {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    });
    return d.toString()
};

const decrypt = function (e) {
    var cipherParams = CryptoJS.lib.CipherParams.create({
        ciphertext: CryptoJS.enc.Base64.parse(e)
   });
    var f = CryptoJS.enc.Utf8.parse("learnspaceaes123");
    var res = CryptoJS.AES.decrypt(cipherParams,f,{
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    });
    return res.toString(CryptoJS.enc.Utf8);

}

const timeToSeconds = function (f) {
    var b = f.split(":");
    var d = parseInt(b[0]);
    var a = parseInt(b[1]);
    var c = parseInt(b[2]);
    var e = d * 3600 + a * 60 + c;
    return e
};

const formatStr = function (c, a) {
    var l = "";
    var k = (c + "").length;
    if (k > 0) {
        if (k + 2 > a) {
            return c + ""
        } else {
            var g = a - k - 2;
            var h = 1;
            for (var e = 0; e < g; e++) {
                h = h * 10
            }
            var b = parseInt(Math.random() * h);
            var f = (b + "").length;
            if (f < g) {
                for (var d = f; d < g; d++) {
                    b = b * 10
                }
            }
            if (k >= 10) {
                l += k
            } else {
                l += "0" + k
            } l += c + (b + "")
        }
    } else {
        return c + ""
    }
    return l
};

const getParams=function (p) {
    var q = {
        courseId: p.courseId,
        itemId: p.itemId,
        time1: formatStr(
            (new Date()).getTime(),
            20
        ),
        time2: formatStr(parseInt(p.startTime), 20),
        time3: formatStr(timeToSeconds(p.videoTotalTime), 20),
        time4: formatStr(parseInt(p.endTime), 20),
        videoIndex: p.videoIndex || 0,
        time5: formatStr(p.studyTimeLong, 20),
        terminalType: p.terminalType || 0
    };
    return q
}

var itemids = process.argv[2];
var start = process.argv[3]
var end = process.argv[4]
var p = {
    "interval": true,
    "playComplete": true,
    "courseId": "26ae32dc2dcd4c9cbace10894d9a172b___",
    "itemId": itemids,
    "position": 4,
    "videoTotalTime": "00:10:35",
    "startTime": parseInt(start),
    "endTime": parseInt(end),
    "studyTimeLong": end-start
}
//console.log(p)
console.log(encrypt(JSON.stringify(getParams(p))))

免费评分

参与人数 45吾爱币 +41 热心值 +38 收起 理由
QWQ2333 + 1 + 1 可惜我的已经刷完了
jhy0117 + 1 + 1 热心回复!
xingyu00 + 1 + 1 我很赞同!
l267200155 + 1 + 1 谢谢@Thanks!
hhhh1314 + 1 我很赞同!
学学习系 + 1 + 1 我很赞同!
cyh000 + 1 + 1 我很赞同!
XingQWu + 1 用心讨论,共获提升!
Liona + 1 + 1 谢谢@Thanks!
Fan2115 + 1 + 1 我很赞同!
31803 + 1 + 1 我很赞同!
airipc + 1 我很赞同!
Huibq120 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
xb521314 + 1 + 1 谢谢@Thanks!
arsleeli + 1 + 1 我很赞同!
yunji + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
zhanghuage + 1 我很赞同!
cgiwei999 + 1 我很赞同!
笙若 + 1 + 1 谢谢@Thanks!
wqc5843699 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
sevbots + 1 + 1 我很赞同!
yiban1 + 1 + 1 热心回复!
tantaihong001 + 1 我很赞同!
licw + 1 + 1 很不错
yincheng + 1 + 1 鼓励转贴优秀软件安全工具和文档!
s757129 + 1 + 1 ggnb!
onetake + 1 + 1 我很赞同!
5NYouGuo + 1 + 1 谢谢@Thanks!
exluku + 1 + 1 热心回复!
sasmike + 1 + 1 谢谢@Thanks!
ukpkmkk0000 + 1 热心回复!
zipw + 1 热心回复!
RuinMirror + 1 谢谢@Thanks!
cxzlkjhgfdsa123 + 1 谢谢@Thanks!
tufeige + 1 我很赞同!
wry123 + 1 谢谢@Thanks!
kemuxin + 1 萌新报道!
3084507685 + 1 + 1 我很赞同!
yzjtxwd + 1 热心回复!
CYLmtthhh + 1 + 1 热心回复!
最新的 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
lfm333 + 1 + 1 谢谢@Thanks!
夫子点灯 + 1 热心回复!
yjn866y + 1 + 1 热心回复!
涛之雨 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| pengzhengchang 发表于 2022-11-11 14:37
PLA81 发表于 2022-11-11 13:54
用cookie登录或者账号密码,之后在哪里更改课程?ID

你可以直接在python代码里面搜索courseid,然后替换成你的课程的id。课程id打开学习页面直接在源码中搜索courseid能找到

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
l267200155 + 1 + 1 我很赞同!

查看全部评分

lfm333 发表于 2022-11-11 09:06
cyxnzb 发表于 2022-11-11 00:30
judgecx 发表于 2022-11-11 02:29
fiddle?mac你的是试用版吗?还是买了,还是破解的
123-木头人 发表于 2022-11-11 08:35
感谢分享
zhengxinjun 发表于 2022-11-11 08:40
收藏下来慢慢学习
petal 发表于 2022-11-11 08:53
参观学习下   
FcSp 发表于 2022-11-11 09:14
感谢楼主分享
a155865 发表于 2022-11-11 09:26
参观学习下
最新的 发表于 2022-11-11 09:40
python最后一行报错了,而且我的cookie正确显示 获取limitId失败,检查Cookie
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-23 02:19

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表