什么叫只有Web端没有被邀请参加派对? 这不公平! 学习通有许多考试只允许手机参加,而本文通过 UA 伪装、参数构造与 JSBridge Hook 实现了在电脑浏览器上参加这类考试。
免责声明 :本文仅供技术学习交流,请遵守学校相关规定,不要做违规的事情! (那就是要做啊我看)
感谢与补充(2026年5月更新)
本文最初写于 2025年12月14日。感谢 mrgeda 的修正建议与补充内容!以下补充方案已在 2026年5月 的学习通版本中验证有效。
补充一:APP版本检测绕过 问题说明 :原方案在当前版本会触发”APP版本过低”弹窗,阻断考试入口。直接修改页面中的 <script> 内容不会稳定生效,推测与后续脚本覆盖或动态事件绑定有关。
解决方案 :在考试入口页、点击”开始考试”前,于浏览器控制台执行以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 (function ( ) { window .confirmEnterPop = function ( ) { preEnter (); }; const startBtn = $("#start" ); startBtn.off ('tap' ); startBtn.off ('click' ); startBtn.on ('tap' , preEnter); startBtn.on ('click' , preEnter); console .log ("confirmEnterPop 已绕过" ); })();
原理 :通过覆盖 confirmEnterPop 函数并重新绑定按钮事件,绕过客户端版本检测逻辑,直接调用 preEnter() 进入考试流程。
补充二:防粘贴与切屏监控绕过
执行时机更正 :防粘贴与切屏监控脚本需要在进入正式答题页面、题目和输入框已经渲染出来之后 再执行。学习通会在题目组件初始化完成后动态绑定限制逻辑,如果过早注入,后续 SPA 初始化或题目切换很可能会把前面改掉的事件与 Hook 覆盖掉。
问题说明 :进入考试后,系统在答题环节设置了以下限制:
防粘贴机制 :简答题的 UEditor 富文本编辑器在 beforePaste 事件中强行清空剪贴板数据
切屏与F12监控 :页面绑定了 CLIENT_WEB_LIFECYCLE 和 DOM 焦点事件,切换窗口或打开控制台会触发日志上报甚至强制收卷
反调试死循环 :部分页面打开控制台时被 debugger; 语句卡死
解决方案 :进入正式答题页面并看到输入框后,在控制台执行以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 if (window .editors && window .editors .length > 0 ) { window .editors .forEach (function (e ) { var ue = e.ueditor ; if (ue) { if (ue._listeners && ue._listeners ['beforepaste' ]) ue._listeners ['beforepaste' ] = []; ue.options .pasteplain = false ; ue.options .disablePasteImage = false ; } }); } window .exitCountAndExitTip = window .switchScreenLog = window .switchScreenSuspendedWindowLog = window .screenMonitorLog = window .screenMonitorStopLog = window .clientSnapShotLog = window .snapshotMonitorLog = function ( ) {};if (window .jsBridge && typeof window .jsBridge .unbind === 'function' ) { window .jsBridge .unbind ('CLIENT_WEB_LIFECYCLE' ); window .jsBridge .unbind ('CLIENT_SCREEN_MONITOR' ); } Object .defineProperty (document , 'hidden' , { value : false , writable : false });Object .defineProperty (document , 'visibilityState' , { value : 'visible' , writable : false });var blockVisibility = function (e ) { e.stopImmediatePropagation (); };['visibilitychange' , 'blur' ].forEach (evt => { window .addEventListener (evt, blockVisibility, true ); document .addEventListener (evt, blockVisibility, true ); }); window .onblur = document .onblur = document .body .onblur = null ;console .log ("粘贴限制与切屏监控已全部解除!" );
原理 :
粘贴解禁 :清空编辑器底层 beforepaste 事件数组,剥夺其修改剪贴板数据的能力
事件劫持 :重定义 visibilityState 属性,利用 stopImmediatePropagation() 在捕获阶段拦截切屏事件
上报阻断 :重写所有异常记录函数,切断 JSBridge 层面的状态轮询
实验原理简析 学习通的仅手机端限制主要依赖以下机制:
层级
检测方式
绕过方法
HTTP层
User-Agent 判断
UA伪装插件
前端路由
URL参数校验
手动构造URL
JS层
设备特征检测
Chrome设备模拟
Native层
JSBridge通信
Hook模拟APP响应
安全层
签名验证
构造签名响应
我们发现:服务端未严格验证签名来源,仅依赖前端+JSBridge限制
技术细节(逆向分析) JSBridge 通信机制 学习通 APP 使用 JSBridge 实现网页与原生 APP 的通信:
1 2 3 4 5 网页 → jsBridge.postNotification('CLIENT_FORM_SIGN', data) → iframe.src = 'jsbridge://PostNotificationWithId-1' → APP拦截并处理 → APP 调用 jsBridge.trigger('CLIENT_FORM_SIGN', response) → 网页收到回调,继续执行
在电脑浏览器中,如果我们只通过修改UA与构造URL来访问考试jsbridge:// 将协议无人处理,导致流程中断。
关键 JSBridge 事件
事件名
用途
CLIENT_DEVICE_ID
获取设备唯一标识
CLIENT_FORM_SIGN
表单签名验证
CLIENT_CHECK_URL_TYPE
URL类型检查
CLIENT_EVERISK_INFO_CHECK
风险检查
签名回调格式 CLIENT_FORM_SIGN 回调期望的响应格式:
1 2 3 4 5 6 7 8 9 { success : true , result : 0 , typeFlag : '{"type":"startExam","funckey":"startExam_xxx"}' , cxcid : '设备ID' , cxtime : '时间戳' , paramToken : '参数签名' , signToken : '签名Token' }
测试环境
时间:2025年12月(原方案)/ 2026年5月(补充脚本,感谢 mrgeda 验证)
浏览器:Edge / Chrome
学习通版本:6.7.1(原方案)/ 最新版(补充脚本)
准备工作 安装浏览器插件 安装 User-Agent Switcher and Manager (Chrome/Edge/Firefox 均可)
获取学习通手机端 UA 在手机学习通内置浏览器中访问:
1 https://www.whatismybrowser.com/detect/what-is-my-user-agent
复制显示的 User-Agent 字符串,格式类似:
1 2 Mozilla/5.0 (iPhone; CPU iPhone OS 26_1like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 ... com.ssreader.ChaoXingStudy/ChaoXingStudy_3_6.7.1_ios_phone_...
提示 :UA 必须包含 ChaoXingStudy 关键字,普通手机浏览器 UA 无效
学习通访问外部链接的小技巧:在笔记里直接写一个链接,点开访问
操作步骤 第一步:提取课程参数
电脑登录学习通,进入目标课程页面
F12 打开开发者工具 → Elements 面板
Ctrl+F 搜索 courseId、classId 等参数
也可以在 URL 中找到:
第二步:获取考试ID
启用 UA 伪装 (设置为手机端 UA)
构造并访问以下链接(填写自己的参数):
1 https://mooc1.xuexi365.com/exam-ans/exam/test?courseId=【courseId】&classId=【classId】&ut=s&cpi=【cpi】&enc=【enc】&openc=【openc】
F12 → Ctrl+F 搜索 TestRelationInfo
找到类似内容:
1 TestRelationInfo = {"7707727" :{"limitTime" :"60" ,"expiredAutoSubmit" :"1" }};
记录其中的数字 ID(如 7707727),这就是 taskrefId
提示 :enc 参数有时效性,过期需重新获取
第三步:进入考试页面
构造最终链接:
1 https://mooc1-api.chaoxing.com/exam-ans/exam/phone/task-exam?taskrefId=【taskrefId】&courseId=【courseId】&classId=【classId】&ut=s&cpi=【cpi】
确保 UA 伪装已启用
访问链接
F12 打开开发者工具 → 点击左上角 设备模拟图标 (或 Ctrl+Shift+M)
第四步:注入入口页 Hook 代码(JSBridge / APP版本检测) 在点击”开始考试”前,先在入口页 Console 中执行以下代码。这里保留的是反调试、验证码回调、JSBridge 与 APP 版本检测绕过;防粘贴与切屏监控脚本不要在这里提前执行,等进入题目页面后再执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 (function ( ) { var _Function = Function ; Function = function ( ) { var args = Array .from (arguments ); var body = args[args.length - 1 ]; if (typeof body === 'string' && body.includes ('debugger' )) { args[args.length - 1 ] = body.replace (/debugger/g , '' ); } return _Function.apply (this , args); }; Function .prototype = _Function.prototype ; var _setInterval = setInterval ; setInterval = function (fn, time ) { if (typeof fn === 'function' && fn.toString ().includes ('debugger' )) { return null ; } return _setInterval.apply (this , arguments ); }; })(); window .cx_captcha_function = function (data ) { console .log ('[验证码回调]' , data); if (data.result === true && data.extraData ) { var extra = JSON .parse (data.extraData ); console .log ('验证码通过,validate:' , extra.validate ); window ._captchaValidate = extra.validate ; } }; (function ( ) { var fakeDeviceId = 'IMEI_' + Math .random ().toString (36 ).substr (2 , 16 ).toUpperCase (); var originalPost = jsBridge.postNotification .bind (jsBridge); jsBridge.postNotification = function (name, userInfo ) { console .log ('[发送]' , name, userInfo); setTimeout (function ( ) { var response = {success : true , result : 0 }; if (name === 'CLIENT_FORM_SIGN' ) { var typeFlag = '' ; try { typeFlag = userInfo.typeFlag ; } catch (e) {} response = { success : true , result : 0 , typeFlag : typeFlag, cxcid : fakeDeviceId, cxtime : String (Date .now ()), paramToken : 'pt_' + Date .now (), signToken : 'st_' + Date .now (), checkCount : '0' , extraInfo : {code : '' } }; } else if (name === 'CLIENT_DEVICE_ID' ) { response = {deviceId : fakeDeviceId, imei : fakeDeviceId, success : true }; } else if (name === 'CLIENT_CHECK_URL_TYPE' ) { response = {success : true , result : 0 , type : 0 }; } console .log ('[响应]' , name, response); jsBridge.trigger (name, response); }, 100 ); }; jsBridge.setDevice ('ios' ); })(); window .confirmEnterPop = function ( ) { preEnter (); }; const startBtn = $("#start" );startBtn.off ('tap' ); startBtn.off ('click' ); startBtn.on ('tap' , preEnter); startBtn.on ('click' , preEnter); console .log ('入口页 Hook 已注入(含 mrgeda 补充的 APP 版本绕过),可以点击开始考试了' );
第五步:开始考试
按 Ctrl+F8 禁用所有断点(学习通网页检测到F12打开会强制debugger)
点击”开始考试”按钮
完成验证码验证
成功进入考试!
第六步:进入题目后解除防粘贴与切屏监控 进入正式答题页面,看到具体题目和输入框之后,再执行上文”补充二:防粘贴与切屏监控绕过”中的脚本。不要在开始考试按钮页提前执行这一段,因为学习通会在题目渲染完成后重新绑定 UEditor、焦点监听和生命周期监控。
如果考试使用的是单题切换模式 ,每切换一次题目都可能重新渲染 DOM 与事件监听,因此需要在切题后重新执行一次防粘贴与切屏监控脚本。
参数速查表
步骤
链接模板
获取 taskrefId
https://mooc1.xuexi365.com/exam-ans/exam/test?courseId=&classId=&ut=s&cpi=&enc=&openc=
进入考试
https://mooc1-api.chaoxing.com/exam-ans/exam/phone/task-exam?taskrefId=&courseId=&classId=&ut=s&cpi=
注意事项
enc 参数有时效性 ,过期需重新获取
UA 必须是学习通 APP 的 ,普通手机浏览器 UA 无效
考试过程中不要关闭 UA 伪装和设备模拟
入口页 Hook 代码需要在每次刷新页面后重新执行
防粘贴与切屏监控脚本需要在进入题目并看到输入框后执行 ;单题切换模式下,每次切题后也可能需要重新执行
参考资料