文章目录
0x0 前言0x1 1.0版本 -- 解除限制我方进攻
0x2 2.0版本 - 自动翻译与解析听力我方进攻ITEST方防御
0x3 3.0版本 -- 解除切屏限制与添加翻译助手反制防御我方进攻ITEST防御
0x4 4.0版本 - 全随机与ajax拦截反制防御我方进攻ITEST防御
0x5 5.0版本 - 只读属性的胜利反制防御我方进攻
0x6 后记
0x0 前言
脚本已经失效, 此博客只为记录我的开发历程, 方便大家学习油猴脚本开发 学校的英语考试选择在ITEST平台上进行, 并让我们进行了一次模拟考试, 进入考试后发现无法选中切屏等操作, 不如就写个脚本解除这些限制吧, 马上我同学魔改其他人的脚本加入了翻译等功能, 我就想着不如我也写着试一试吧, 随后就开始了我与ITEST的拉锯战 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200625021256477.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNDM2MTc2,size_16,color_FFFFFF,t_70)
0x1 1.0版本 – 解除限制
我方进攻
解除限制非常简单, 首先注意到所有的.itest-ques均被挂上了false, document document.body也被限制了, 直接解除这些限制即可
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200625011817264.png)
function hackClass(className) {
for (const i of document.getElementsByClassName(className)) {
hackItem(i);
}
}
/**
* 现在会被检测
*/
function hackItem(item) {
item.onpaste = () => true;
item.oncontextmenu = () => true;
item.onselectstart = () => true;
item.ondragstart = () => true;
item.oncopy = () => true;
item.onbeforecopy = () => true;
item.style = '';
}
hackClass('itest-ques');
hackClass('itest-direction');
hackItem(document.body);
0x2 2.0版本 - 自动翻译与解析听力
我方进攻
注意到所有的听力材料都是以json的形式写在了dom里, 只需要遍历这些dom, 就可以将听力的地址提取出来 ITEST开发人员太懒了
翻译题目很简单, 只需要遍历每个题目的节点, 在每个题目上加上按钮, 传入百度翻译即可返回结果, 这里贴上部分代码
/**
* 调用翻译api
* @param context_list
* @param from
* @param to
* @returns {Promise}
*/
async function translateAPI(context_list, from, to) {
const trans_salt = (new Date).getTime();
const {appid, key} = getBaiduAPIKey()
const trans_str = appid + context_list + trans_salt + key;
const trans_sign = md5(trans_str);
for (let i=0; i
q: context_list,
from,
to,
appid: appid,
salt: trans_salt,
sign: trans_sign
})
if (data.error_code) {
const errmsg = {
"52001": "请求超时",
"52002": "系统错误",
"52003": "未授权用户",
"54003": "访问频率受限",
"54004": "账户余额不足",
"58002": "服务当前已关闭",
"90107": "认证未通过或未生效"
}
if (parseInt(data.error_code) !== 54003) {
alert(`错误代码${data.error_code} 信息:${errmsg[data.error_code.toString()]}`)
throw new Error(`错误代码${data.error_code} 信息:${errmsg[data.error_code.toString()]}`)
} else {
await delay(1000);
}
}
return data.trans_result;
}
alert("请求过于频繁")
throw new Error("请求过于频繁");
}
/**
* 单选题注入
*/
function singleSelect() {
$('.row').each(function () {
if ($(this).find('.option').length !== 0) {
$(this).prepend(`翻译`)
}
})
$('.sk-tr-s').on('click', function () {
if ($(this).is('.sk-btn-p')) {
$(this).parent().find('span').each(function () {
$(this).remove();
})
const $this = $(this).parent();
const selectOption = [];
$this.children('.option').each(function () {
selectOption.push($(this).find('label'))
})
const p = selectOption.map(value => value.text().replace('\n', '')).join('\n');
translateAPI(p, 'en', 'zh').then(value => {
for (let i = 0; i value[i].dst}`)
}
$(this).removeClass('sk-btn-p').addClass('sk-btn-g').html('清空');
})
} else {
$(this).removeClass('sk-btn-g').addClass('sk-btn-p').html('翻译');
$(this).parent().find('span').each(function () {
$(this).remove();
})
}
})
}
ITEST方防御
因为不少学校的ITEST平台是定制的, 域名未知, 我不得不匹配所有域名, 为了判断一个平台是否为ITEST, 我才用了判断标题的方法
/**
* 判断是否为Itest平台, 为了防止部分学校定制
* @returns {boolean}
*/
function isItest() {
return document.title.indexOf("iTEST") !== -1 && document.getElementById('all-content') !== null;
}
收到失效的报告后, 我进入平台检查, 发现了下面令我瞠目结舌的场面: 他们把ITEST的T与E替换成了希腊字母Εε和Ττ, 肉眼看不出任何问题, 但是程序不认了, 要不是有拼写检查, 我还真看不出来ITEST和ITΕSΤ不一样, 你看得出来吗?
0x3 3.0版本 – 解除切屏限制与添加翻译助手
反制防御
因为ITEST被改, 不能判断ITEST, 我将条件删为仅判断节点
function isItest() {
return document.getElementById('all-content') !== null;
}
我方进攻
在逻辑里发现切屏代码, 是通过window.onblur与 window.onfocus检测切屏, 很简单, 我只要把这两个函数置空即可 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200625013406385.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNDM2MTc2,size_16,color_FFFFFF,t_70)
setInterval(function () {
window.onblur = () => {};
window.onfocus = () => {};
}, 5 * 1000)
为了方便查单词, 我添加了翻译助手, 大概就是添加了个节点, 点击会直接调用百度翻译进行翻译, 大致源码, 红框内为铺垫 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200625013633302.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNDM2MTc2,size_16,color_FFFFFF,t_70)
ITEST防御
还记得前面那个翻译助手吗? 就那里出现了大问题, ITEST直接检测了翻译助手的悬浮窗, 如何出现问题直接判定为作弊, 并通过ajax传输出去! 至此, 我不得不修改源码 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200625014026354.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNDM2MTc2,size_16,color_FFFFFF,t_70)
0x4 4.0版本 - 全随机与ajax拦截
反制防御
为了防止脚本被固定节点检测出, 我决定对脚本进行重构, 对所有的class进行随机化处理, 核心代码如下
/**
* 生成随机字符串
* @param len 长度
* @returns {string}
*/
function getRandomString(len = 10) {
const str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const maxPos = str.length;
let pwd = '';
for (let i = 0; i
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
}
const RANDOM_CLASS = { // 对所有的随机化处理
BTN: getRandomString(getRandomInt(3, 10)),
BTN_P: getRandomString(getRandomInt(3, 10)),
BTN_G: getRandomString(getRandomInt(3, 10)),
TRANSLATE_TEXT: getRandomString(getRandomInt(3, 10)),
}
/**
* 文章翻译
*/
function article() {
const ART = getRandomString(getRandomInt(5, 10));
$('.con-left>.article').each(function () {
$(this).prepend(` |