huajiqaq 发表于 2026-3-3 20:53:38

国资e学反调试绕过以及视频加速

本帖最后由 huajiqaq 于 2026-3-3 21:14 编辑

国资e学视频想要加速,通过搜索找到之前有相关帖子 [|记录||分享|成功实现浏览器插件快速播放国资E学视频
](https://blog.csdn.net/xiaoyustudio123/article/details/139694724) ,安装后提示视频播放器异常,这说明网页可能更新了相关检测,以下是本人研究,特此记录。
首先,尝试打开控制台,发现断点到了无限debugger。通过控制台调用回溯,发现这是一个通过构造无限debugger匿名函数,并且检测函数开始时间和结束时间判断是否在控制台下,伪代码大概如下:
```javascript
// 从配置对象中解构参数,包含默认值
const {
startDelayMs: initialDelay = 3000,      // 初始延迟 3秒
thresholdMs: timeThreshold = 100,          // 时间阈值 100ms
confirmCount: requiredConfirmations = 0,   // 需要连续成功的次数
minIntervalMs: minInterval = 500,          // 最小轮询间隔 500ms
maxIntervalMs: maxInterval = 1500,         // 最大轮询间隔 1500ms
onDetected: detectionCallback               // 检测成功后的回调函数
} = config;
// 状态变量
let consecutiveSuccessCount = 0;
let detectionTriggered = false;
// 最终执行函数 - 当检测条件满足时调用
function executeDetection() {
if (!detectionTriggered) {
    detectionTriggered = true;
    if (detectionCallback) {
      detectionCallback();
    } else {
      document.open();
      document.write('页面内容');
      document.close();
    }
}
}
// 主要的检测轮询函数
function pollingCheck() {
if (detectionTriggered) return;
const startTime = Date.now();
// 执行debugger指令,触发调试器中断
(function() {
    const debugFunction = new Function('debugger');
    try {
      debugFunction();
    } catch (error) {}
})();
const executionTime = Date.now() - startTime;
if (executionTime > timeThreshold) {
    consecutiveSuccessCount++;
    if (consecutiveSuccessCount >= requiredConfirmations) {
      executeDetection();
      return;
    }
} else {
    consecutiveSuccessCount = Math.max(0, consecutiveSuccessCount - 1);
}
scheduleNextPolling();
}
// 安排下一次轮询
function scheduleNextPolling() {
const effectiveMinInterval = Math.max(0, minInterval);
const effectiveMaxInterval = Math.max(effectiveMinInterval, maxInterval);
const randomDelay = effectiveMinInterval +
                      Math.random() * (effectiveMaxInterval - effectiveMinInterval);
setTimeout(pollingCheck, randomDelay);
}
// 启动检测
setTimeout(pollingCheck, Math.max(0, initialDelay));
```
删除原始代码的 `_0x491ce9['xWwHJ'](setTimeout, _0x2c52fe, Math['max'](0x0, _0xdb73b9));` 即可。
这里因为只是调试脚本,解决脚本无法加速视频的bug,这里只是本地解决反调试,探究如何绕过视频加速限制,为了方便就本地替换js,通过右键js手动替代js文件,并格式化js文件。
重新加载原网页,发现网页处于无限递归,在控制台源代码处点击暂停按钮,发现执行到了:
```javascript
return _0x31d1f1['toString']()['search'](_0x7da7ff['lAhBM'])['toString']()['constructor'](_0x31d1f1)['search'](_0x7da7ff['lAhBM']);
```
还原大概逻辑为:
```javascript
// 最终还原的代码逻辑
(function() {
    // 控制标志
    let hasExecuted = true;
    // 创建只执行一次的函数包装器
    function createOnceWrapper(thisArg, fn) {
      const wrappedFn = hasExecuted ? function() {
            if (fn) {
                const result = fn.apply(thisArg, arguments);
                fn = null;// 释放
                return result;
            }
      } : function() {};// 空函数
      hasExecuted = false;
      return wrappedFn;
    }
    // 定义反调试函数
    let detector = createOnceWrapper(this, function detect() {
      // 无限递归陷阱
      return detector
            .toString()
            .search(/(((.+)+)+)+$/)// 灾难性正则
            .toString()
            .constructor(detector)   // 重新创建自身
            .search(/(((.+)+)+)+$/); // 再次搜索
    });
    // 立即执行
    detector();// 触发反调试
})();
```
发现是通过构造了陷阱正则表达式达到了无限递归。这里很简单,把正则也就是原始代码的 `_0x7da7ff['lAhBM']` 替换为普通正则即可,比如 `.*`。刷新发现网页正常加载。之后删除之前提到的 `_0x491ce9['xWwHJ'](setTimeout, _0x2c52fe, Math['max'](0x0, _0xdb73b9));`,至此反调试已经成功。
下一步就是视频加速检测的去除。
通过在播放器页面直接搜索"视频播放器运行异常",发现搜索到了一个关键字,很幸运网站没有混淆字符串,直接可以搜索到:
```javascript
'xKbtO': '视频播放器运行异常,强制退出登录',
```
再次向上查找 xKbtO 调用,可以发现最终被 NeTjy 调用:
```javascript
(_0x4f07a5['PnAKD'](_0x179815['value']['_rate'], 0x2) || _0x4f07a5['XwpSO'](_0x179815['value']['_rate'], 0.5)) && _0x4f07a5['Ssaiy'](_0x390d05)['user']['logOut'](_0x4f07a5['SCzUX'])['then'](_0x11af87 => {
    _0x45ae2c['$modal']['msgError'](_0x26ddcb['NeTjy']),
    window['location']['href'] = _0x26ddcb['wfcxW'](window['location']['origin'], _0x26ddcb['zsGnF']);
}
```
还原为伪代码是:
```javascript
// 监听倍速变化事件
player.value.on('ratechange', function(data) {
    // 获取当前倍速
    const currentRate = player.value._rate;
    // 如果倍速大于2.0 或 小于0.5
    if (currentRate > 2.0 || currentRate < 0.5) {
      // 执行登出
      user.logOut().then(() => {
            // 显示错误提示
            $modal.msgError('视频播放器运行异常,强制退出登录');
            // 跳转到首页
            window.location.href = window.location.origin + '/home';
      });
    }
});
```
解决也很简单,直接拦截 ratechange 事件即可。
最终实现油猴脚本代码:
```javascript
// ==UserScript==
// @name         国资e学视频加速
// @namespace    huajiqaq
// @description解决切后台暂停、倍速播放被强制登出问题
// @version      1.0
// @match      https://elearning.tcsasac.com/*
// @grant      none
// @run-at       document-start
// ==/UserScript==
(function() {
    'use strict';
    // 阻止页面可见性检测(切后台不暂停)
    const events = ['visibilitychange', 'pagehide', 'blur', 'focus'];
    events.forEach(event => {
      window.addEventListener(event, e => {
            e.stopImmediatePropagation();
      }, true);
    });
    // 拦截 ratechange 事件监听(不让播放器检测倍速变化)
    const originalAdd = EventTarget.prototype.addEventListener;
    EventTarget.prototype.addEventListener = function(type, listener, options) {
      if (type === 'ratechange') {
            console.log('拦截倍速检测');
            return;
      }
      return originalAdd.call(this, type, listener, options);
    };
    // 设置5倍速
    setInterval(() => {
      const video = document.querySelector('video');
      if (video) {
            video.playbackRate = 5;
            video.muted = true;
            if (video.paused) video.play();
      }
    }, 1000);
})();
```
页: [1]
查看完整版本: 国资e学反调试绕过以及视频加速