// ==UserScript== // @name 浏览器功能包 // @namespace http://tampermonkey.net/ // @version 0.2 // @description 修改浏览器的一些配置,使脚本可以作弊 // @author Tenfond // @match *://*/* // @grant none // @license AGPL-3.0 // @run-at document-start // @downloadURL none // ==/UserScript== (function () { // event 可信任事件 (function () { function tamper(event) { return { "isTrusted": true, get altitudeAngle() { return event["altitudeAngle"]; }, get azimuthAngle() { return event["azimuthAngle"]; }, "getCoalescedEvents": function getCoalescedEvents() { return event["getCoalescedEvents"].apply(event, arguments); }, "getPredictedEvents": function getPredictedEvents() { return event["getPredictedEvents"].apply(event, arguments); }, get height() { return event["height"]; }, get isPrimary() { return event["isPrimary"]; }, get pointerId() { return event["pointerId"]; }, get pointerType() { return event["pointerType"]; }, get pressure() { return event["pressure"]; }, get tangentialPressure() { return event["tangentialPressure"]; }, get tiltX() { return event["tiltX"]; }, get tiltY() { return event["tiltY"]; }, get twist() { return event["twist"]; }, get width() { return event["width"]; }, "constructor": event["constructor"], "__proto__": event["__proto__"], get altKey() { return event["altKey"]; }, get bubbles() { return event["bubbles"]; }, get button() { return event["button"]; }, get buttons() { return event["buttons"]; }, get cancelBubble() { return event["cancelBubble"]; }, get cancelable() { return event["cancelable"]; }, get clientX() { return event["clientX"]; }, get clientY() { return event["clientY"]; }, get composed() { return event["composed"]; }, get ctrlKey() { return event["ctrlKey"]; }, get currentTarget() { return event["currentTarget"]; }, get defaultPrevented() { return event["defaultPrevented"]; }, get detail() { return event["detail"]; }, get eventPhase() { return event["eventPhase"]; }, get fromElement() { return event["fromElement"]; }, get layerX() { return event["layerX"]; }, get layerY() { return event["layerY"]; }, get metaKey() { return event["metaKey"]; }, get movementX() { return event["movementX"]; }, get movementY() { return event["movementY"]; }, get offsetX() { return event["offsetX"]; }, get offsetY() { return event["offsetY"]; }, get pageX() { return event["pageX"]; }, get pageY() { return event["pageY"]; }, get path() { return event["path"]; }, get relatedTarget() { return event["relatedTarget"]; }, get returnValue() { return event["returnValue"]; }, get screenX() { return event["screenX"]; }, get screenY() { return event["screenY"]; }, get shiftKey() { return event["shiftKey"]; }, get sourceCapabilities() { return event["sourceCapabilities"] }, get srcElement() { return event["srcElement"]; }, get target() { return event["target"]; }, get timeStamp() { return event["timeStamp"]; }, get toElement() { return event["toElement"]; }, get type() { return event["type"]; }, get view() { return event["view"]; }, get which() { return event["which"]; }, get x() { return event["x"]; }, get y() { return event["y"]; }, "composedPath": function composedPath() { return event["composedPath"].apply(event, arguments); }, "preventDefault": function preventDefault() { return event["preventDefault"].apply(event, arguments); }, "stopImmediatePropagation": function stopImmediatePropagation() { return event["stopImmediatePropagation"].apply(event, arguments); }, "stopPropagation": function stopPropagation() { return event["stopPropagation"].apply(event, arguments); } }; } try { const addEventListener = EventTarget.prototype.addEventListener; Object.defineProperty(EventTarget.prototype, "addEventListener", { value: function (type, callback, options = false) { return addEventListener.apply(this, [type, type === "click" ? function () { if (arguments.length > 0 && arguments[0].constructor.name === "PointerEvent") arguments[0] = tamper(arguments[0]); return callback.apply(this, arguments); } : callback, options]); }, writable: false, enumerable: true, configurable: false }); } catch (e) { console.error(e.message); } })(); // 定义 location.hashCode 获取 href的hash值 (function () { try { Object.defineProperty(location, "hashCode", { enumerable: true, configurable: false, get: function () { let code = 0; for (const v of location.href) { code += (code << 7) + v.charCodeAt(0); } // 返回值在 JavaScript 中的取值范围 [-2147483648,4294967294] return code; } }); } catch (e) { console.error(e.message); } let hashCode = location.hashCode, onchange = null; try { Object.defineProperty(location, "onchange", { enumerable: true, configurable: false, get: function () { return onchange; }, set: function (handler) { if (typeof handler === "function" || Boolean(handler) === false) { onchange = handler; } else { console.error("Uncaught (in onchange) TypeError: " + handler + " is not a function.") } } }); setInterval(function () { if (hashCode !== location.hashCode) { hashCode = location.hashCode; if (typeof onchange === "function") onchange(); } }, 500); } catch (e) { console.error(e.message); } })(); window.searchToJSON = function searchToJSON(search) { if (search) { return JSON.parse("{\"" + decodeURIComponent(search.substring(1) .replace(new RegExp("\"", "g"), '\\"') .replace(new RegExp("&", "g"), '","') .replace(new RegExp("=", "g"), '":"')) + "\"}"); } else { return null; } } window.hrefToLocation = function hrefToLocation(href) { let location = {href: href}, c = 0, start = 0, port, search; for (let i = 0; i < href.length; i++) { if (href[i] === "/") { if (++c === 1) { location.protocol = href.substring(start, i); } else if (c === 3) { location.host = href.substring(start, i); location.origin = href.substring(0, i); if (port) { location.port = href.substring(port, i); } else { location.hostname = location.host; location.port = ""; } } if (c <= 3) { start = i + 1; } } else if (href[i] === ":" && c === 2) { location.hostname = href.substring(start + 1, i); port = i + 1; } else if (href[i] === "?" && !search) { location.pathname = href.substring(start - 1, i); search = i; } else if (href[i] === "#" && !location.hash) { location.hash = href.substring(i); if (search) { location.search = href.substring(search, i); } else { location.search = ""; location.pathname = href.substring(start - 1, i); } break; } } if (typeof location.host === "undefined") { if (c < 2) { location.host = location.hostname = location.port = location.origin = ""; } else if (c === 2) { location.host = href.substring(start); location.origin = href; if (typeof location.hostname === "undefined") { location.hostname = location.host; location.port = ""; } else { location.port = href.substring(port); } } location.pathname = location.hash = ""; } else if (typeof location.pathname === "undefined") { location.pathname = href.substring(start - 1); location.search = location.hash = ""; } else if (typeof location.search === "undefined") { if (search) { location.search = href.substring(search); } else { location.search = ""; } location.hash = ""; } else if (typeof location.hash === "undefined") { location.hash = ""; } return location; } window.xmlHttpRequest = function xmlHttpRequest(handler = {}) { function xhrToArgs(xhr) { if (xhr.constructor.name === "XMLHttpRequest") return { // "onabort": xhr["onabort"], // "onerror": xhr["onerror"], // "onload": xhr["onload"], // "onloadend": xhr["onloadend"], // "onloadstart": xhr["onloadstart"], // "onprogress": xhr["onprogress"], // "onreadystatechange": xhr["onreadystatechange"], // "ontimeout": xhr["ontimeout"], "abort": function () { return xhr["abort"](); }, "finalUrl": xhr["responseURL"], "responseHeaders": (function () { const headers = {}; xhr["getAllResponseHeaders"]().split("\r\n").forEach(function (header) { header = header.split(": "); headers[header[0]] = header[1]; }); return headers; })(), "getResponseHeader": function (name) { return xhr["getResponseHeader"](name); }, "overrideMimeType": function (mime) { return xhr["overrideMimeType"](mime); }, "responseType": xhr["responseType"], "response": xhr["response"], "responseText": (function () { try { return xhr["responseText"]; } catch (e) { console.error(e.message); return e; } })(), "responseXML": (function () { try { return xhr["responseXML"]; } catch (e) { console.error(e.message); return e; } })(), "readyState": xhr["readyState"], "status": xhr["status"], "statusText": xhr["statusText"], "timeout": xhr["timeout"], // "upload": xhr["upload"], // "withCredentials": xhr["withCredentials"] }; else return xhr.constructor.name; } if (typeof handler === "string") handler = {url: handler}; const request = new XMLHttpRequest(); if (handler.onreadystatechange) request.onreadystatechange = function (event) { return handler.onreadystatechange(xhrToArgs(request), event); }; request.open(handler.method ? handler.method.toUpperCase() : "GET", handler.url ? handler.url : location.href, handler.async ? handler.async : true, handler.user ? handler.user : null, handler.password ? handler.password : null); if (handler.headers) for (let header in handler.headers) request.setRequestHeader(header, handler.headers[header]); if (handler.onabort) request.onabort = function (event) { return handler.onabort(xhrToArgs(request), event); }; if (handler.onerror) request.onerror = function (event) { return handler.onerror(xhrToArgs(request), event); }; if (handler.onload) request.onload = function (event) { return handler.onload(xhrToArgs(request), event); }; if (handler.onloadend) request.onloadend = function (event) { return handler.onloadend(xhrToArgs(request), event); }; if (handler.onloadstart) request.onloadstart = function (event) { return handler.onloadstart(xhrToArgs(request), event); }; if (handler.onprogress) request.onprogress = function (event) { return handler.onprogress(xhrToArgs(request), event); }; if (handler.ontimeout) request.ontimeout = function (event) { return handler.ontimeout(xhrToArgs(request), event); }; if (handler.responseType) request.responseType = handler.responseType; if (handler.overrideMimeType) request.setRequestHeader("Content-Type", handler.overrideMimeType); if (handler.data) { request.send(JSON.stringify(handler.data)); } else { request.send(); } return request; } window.ready = function ready(handler, readyState = "interactive") { // "loading": 表示文档还在加载中,即处于“正在加载”状态。 // "interactive": 文档已经结束了“正在加载”状态,DOM 元素可以被访问。但是像图像,样式表和框架等资源依然还在加载。 // "complete": 页面所有内容都已被完全加载。 let intervalId = setInterval(function (states = ["loading", "interactive", "complete"]) { if (states.indexOf(document.readyState.toLowerCase()) >= states.indexOf(readyState.toLowerCase())) { clearInterval(intervalId); if (typeof handler === "function") { handler(); } else { console.error("Uncaught (in ready) TypeError: " + handler + " is not a function."); } } }); } /** 梅森旋转算法中用到的变量如下所示: w:长度 生成的随机数的二进制长度 n:寄存器长度 参与旋转的随机数个数(旋转的深度) m:周期参数,用作第三阶段的偏移量 旋转算法参与旋转的中间项 r:低位掩码/低位要提取的位数 内存界限值 2 的 r 次方 - 1 x⃗ (u)kx→k(u) 和 x⃗ (l)k+1x→k+1(l) 的切分位置 a:旋转矩阵的参数 旋转算法异或基数 矩阵 AA 的最后一行 f:初始化梅森旋转链所需参数 旋转链异或值膨化量 u,s,t,l: 整数参数,移位运算的移动距离 d,b,c: 比特遮罩 s,t:TGFSR的位移量 b,c:TGFSR的掩码 u,d,l:额外梅森旋转所需的掩码和位移量 MT19937-32的参数列表如下: (w, n, m, r) = (32, 624, 397, 31) a = 9908B0DF(16) f = 1812433253 (u, d) = (11, FFFFFFFF16) (s, b) = (7, 9D2C568016) (t, c) = (15, EFC6000016) l = 18 */ window.MT = (function () { // 新方案定义私有变量。修复部分浏览器不支持 # 定义private私有变量 const $n = Symbol(), $m = Symbol(), $r = Symbol(), $a = Symbol(), $u = Symbol(), $d = Symbol(), $s = Symbol(), $b = Symbol(), $t = Symbol(), $c = Symbol(), $l = Symbol(), $index = Symbol(), $LinkedList = Symbol(); // 旋转算法处理旋转链 function generate(MT) { for (let i = 0n; i < MT[$n]; i++) { const lower_mask = -(1n << MT[$r]); const upper_mask = ~lower_mask; const y = (MT[$LinkedList][i] & upper_mask) + (MT[$LinkedList][(i + 1n) % MT[$n]] & lower_mask); let yA = y >> 1n; if ((y % 2n) !== 0n) { yA = yA ^ MT[$a]; } MT[$LinkedList][i] = MT[$LinkedList][(i + MT[$m]) % MT[$n]] ^ yA; } } class MT { constructor( seed = Date.now(), w = 32, n = 624, m = 397, r = 31, a = 0x9908B0DF, f = 1812433253, u = 11, d = 0xFFFFFFFF, s = 7, b = 0x9D2C5680, t = 15, c = 0xEFC60000, l = 18) { w = BigInt(w); this[$n] = BigInt(n); this[$m] = BigInt(m); this[$r] = BigInt(r); this[$a] = BigInt(a); f = BigInt(f); this[$u] = BigInt(u); this[$d] = BigInt(d); this[$s] = BigInt(s); this[$b] = BigInt(b); this[$t] = BigInt(t); this[$c] = BigInt(c); this[$l] = BigInt(l); this[$index] = 0n; this[$LinkedList] = [BigInt(seed)]; // 对数组其他元素进行初始化 for (let i = 1n; i < this[$n]; i++) { this[$LinkedList][i] = (f * (this[$LinkedList][i - 1n] ^ (this[$LinkedList][i - 1n] >> (w - 2n))) + i & (1n << w) - 1n); } } // 获取随机数 next() { if (this[$index] === 0n) generate(this); let y = this[$LinkedList][this[$index]]; y = (y ^ ((y >> this[$u]) & this[$d])); y = (y ^ ((y << this[$s]) & this[$b])); y = (y ^ ((y << this[$t]) & this[$c])); y = (y ^ (y >> this[$l])); this[$index] = (this[$index] + 1n) % this[$n]; if (y <= 9007199254740992n) y = parseInt(y.toString()); return y; } } return MT; })(); // 未经许可禁止抄袭算法,可以私用。 window.Key = (function () { // 定义private私有变量 const $pwd = Symbol(); // 自定义加密算法,以防数据包被破解。 class Key { // _pwd; // 火狐v68版本貌似不支持这种方式声明变量。 constructor(pwd = "Tenfond") { // num,密码偏移量 // key,排列长度偏移量 // charCode,防止内存频繁运动,定义在外部 let key = 7n; if (typeof pwd === "string") { for (let i = 0; i < pwd.length; i++) { key = key * 31n + BigInt(pwd[i].charCodeAt(0)); } pwd = key; key = key & 0xFFFFFFFFFFFFn; } else if ((typeof pwd).match(new RegExp("(number|'bigint')"))) { // 如果密码是数值型就使用此方法作为 密码偏移量 和 排列长度偏移量 pwd = BigInt(Math.round(pwd)); key = (key * 31n + pwd) & 0xFFFFFFFFFFFFn; } else { // 如果类型不匹配就直接提出错误 console.error("Unsupported type '" + (typeof pwd) + "'. It only supports 'string' 'number' 'bigint'."); } // 让排列长度偏移量取第一个数字。加上密码转换成字符字符串的方式 this[$pwd] = (pwd >= 0n ? pwd % 8n + 2n : -(pwd % 8n) + 2n).toString() + key.toString(36); } encrypt(string) { if (typeof string === "string" && string.length > 0) { // subStart 排列长度的起始位置。subLength 排列长度。 let subStart = string.length, subLength = parseInt(this[$pwd][0]), // encryptPool 加密池,即去除的排列长度存放在这里。result 加密后的结果。 encryptPool = [], result = ""; // stringKey 加密种子。 const MTSeed = new MT(subStart + parseInt(this[$pwd].substring(1), 36)); // 获取加密池。 while (subStart > subLength) { subStart -= subLength; encryptPool.push(string.substring(subStart, subStart + subLength)); } encryptPool.push(string.substring(0, subStart)); // 对加密池进行加密,并将加密的字符的结果放入 result 中。 for (let i = 0, j; i < subLength; i++) { for (j = 0; j < encryptPool.length; j++) { const char = encryptPool[j][i]; if (char) { let key = (char.charCodeAt(0) + MTSeed.next()) % 0x100000000; key = [Math.floor(key / 0x10000), key % 0x10000]; result += i * j % 2 === 0 ? String.fromCharCode(key[0]) + String.fromCharCode(key[1]) : String.fromCharCode(key[1]) + String.fromCharCode(key[0]); } else { break; } } } // 返回加密结果 return result; } else { // 如果加密字符串不存在就返回string return string; } } /* 假设有7个字符 加密前 - 排列 ( 1 ) ( 2 3 4 ) ( 5 6 7 ) 加密中 - 排列 ︵ ︵ ︵ 5 2 1 6 3 ︶ 7 4 ︶ ︶ 加密后 - 排列 ( 5 2 1 ) ( 6 3 ) ( 7 4 ) 解密中 - 排列 ︵ ︵ ︵ 5 6 7 2 3 4 1 ︶ ︶ ︶ 解密后 - 排列 1 2 3 4 5 6 7 */ decrypt(string) { if (typeof string === "string" && string.length > 0) { // subStart 排列长度的起始位置。desubLength 反向取加密池的长度。 let subStart = 0, desubLength = Math.ceil(string.length / 2 / parseInt(this[$pwd][0])), // decryptPool 解密池。result 解密后的结果。 decryptPool = [], result = ""; // stringKey 加密种子。 const MTSeed = new MT(string.length / 2 + parseInt(this[$pwd].substring(1), 36)); (function (MT, desubLength) { //NullCount 加密池中没有空位的池数 const NullCount = string.length / 2 % parseInt(MT[$pwd][0]); // 获取解密池 while (string.length / 2 - subStart > desubLength) { decryptPool.push(string.substring(subStart * 2, (subStart + desubLength) * 2)); subStart += desubLength; if (decryptPool.length === NullCount) desubLength--; } decryptPool.push(string.substring(subStart * 2)); })(this, desubLength); // 对解密池进行解密 并将解密结果 加入到 result(结果) 中 string = []; for (let i = 0, j; i < decryptPool.length; i++) { for (j = 0; j < desubLength; j++) { const char = i * j % 2 === 0 ? decryptPool[i][j * 2] + decryptPool[i][j * 2 + 1] : decryptPool[i][j * 2 + 1] + decryptPool[i][j * 2]; if (char) { if (typeof string[j] === "undefined") string[j] = []; string[j][i] = String.fromCharCode((char.charCodeAt(0) * 65536 + char.charCodeAt(1) + 0x100000000 - MTSeed.next()) % 65536); } } } for (let i = string.length - 1; i >= 0; i--) { result += string[i].join(""); } // 返回解密结果 return result; } else { // 如果解密字符串不存在就返回string return string; } } // encrypt 既可以用作加密 也可以用作解密,decrypt 既可以用作解密 也可以用作加密。 } return Key; })(); })();