// ==UserScript== // @name 网页广告拦截器 // @namespace http://tampermonkey.net/ // @version 6.7.0 // @author DeepSeek&GLM // @description 一个手机端via浏览器适用的强大广告拦截器。注入时机分三档:电脑端浏览器配合脚本猫/Violentmonkey/Tampermonkey(动态模式)多为解析前早注入,仅开「拦截内嵌脚本」即可拦截多数广告链;手机端Firefox/雨见+篡改猴等真扩展为半早注入;Via等套壳/WebView浏览器为加载完成后晚注入。因此某些网页在电脑端仅开「拦截内嵌脚本」即可去广告,手机端套壳浏览器上却大概率失效——此时若拦截日记有记录而广告仍残留,可开启「清空残留容器」尝试隐藏;更建议开启「拦截动态脚本」+「拦截第三方资源」,或直接开启「覆盖层拦截」「苹果设备模拟」。 // @match *://*/* // @license MIT // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_registerMenuCommand // @grant GM_notification // @grant GM_listValues // @grant GM_xmlhttpRequest // @grant GM_setClipboard // @connect * // @run-at document-start // ==/UserScript== (function () { 'use strict'; // ===== 注入时机判档 ===== // 【功能】脚本启动时读取一次 document.readyState, 区分两类宿主: // 早注入档 = document-start 注入(readyState=loading, 主流管理器扩展); // 晚注入档 = 页面加载完成后注入(readyState=interactive/complete, 套壳浏览器)。 // 【机制】晚注入档下解析期已结束: 解析期专用的竞速布置按判档跳过; // 零操作跳转保护以「注入后窗口」替代「加载期」; 存量 DOM 由初始扫描直接接管。 var _rs0 = 'loading'; try { _rs0 = document.readyState || 'loading'; } catch (e) {} var _LATE_REGIME = _rs0 !== 'loading'; var _INIT_AT = Date.now(); var _ZERO_TOUCH_LATE_MS = 10000; // ===== 轻量扩展求值引擎 ===== // 支持计算样式谓词 :matches-css / :matches-css-before / :matches-css-after // (prop: value, 值支持精确/通配符*/正则 /re/, 大小写不敏感), 基底用原生 querySelectorAll 求值; // :has()/:not() 为浏览器原生伪类, 路由层把纯原生的这类规则分流进样式表轨; // :contains()/:has-text()/:upward()/:nth-ancestor()/:xpath() 等扩展伪类不支持, // 含这些伪类的规则按原样跳过(不生效)。 var MiniExtendedCss = (function () { var _PRED_RE = /:matches-css(-before|-after)?\(\s*([a-zA-Z-]+)\s*:\s*([^)]*)\)/g; var _UNSUP_RE = /:(has|contains|has-text|upward|nth-ancestor|xpath|if|if-not|abp-has)\(/; // 宽基底(*)规则 MO 重扫限频窗: 新增节点风暴时星号子树求值(限界候选×计算样式)是 // 扩展引擎最贵的一段, 窗口内的 MO 批次跳过星号扫描, 由补扫定时器对根节点一次兜底 var _STAR_THROTTLE_MS = 500; function splitList(s) { var out = []; var cur = ''; for (var i = 0; i < s.length; i++) { var c = s.charAt(i); if (c === ',') { if (cur.trim()) out.push(cur.trim()); cur = ''; } else cur += c; } if (cur.trim()) out.push(cur.trim()); return out; } // 解析单条扩展选择器: 剥掉 :matches-css* 谓词得原生基底; 返回 null 表示非扩展/不支持 function parseSelector(sel) { var preds = []; var rest = sel.replace(_PRED_RE, function (m, pseudo, prop, val) { preds.push({ pseudo: pseudo ? pseudo.replace(/^-/, '') : null, prop: prop.trim().toLowerCase(), value: val.trim() }); return ''; }); if (!preds.length) return null; if (_UNSUP_RE.test(rest)) return null; var base = rest.trim(); if (!base) base = '*'; return { base: base, preds: preds }; } function cssVal(el, pseudo, prop, memo) { try { var mkey = (pseudo || '') + '|' + prop; var em = null; if (memo) { em = memo.get(el); if (em && em.has(mkey)) return em.get(mkey); } var v; if (pseudo) { if (!_globals.getComputedStyle) return null; v = _globals.getComputedStyle(el, pseudo === 'before' ? '::before' : '::after').getPropertyValue(prop); } else { v = _globals.getComputedStyle ? _globals.getComputedStyle(el).getPropertyValue(prop) : null; } if (memo) { if (!em) { em = new Map(); memo.set(el, em); } em.set(mkey, v); } return v; } catch (e) { return null; } } // 谓词值三态匹配: 精确(无通配符)/通配符(*/跨任意段)/正则(/re/ 包裹, 无 flags), 大小写不敏感; // z-index 纯数字走数值相等快路径; 编译结果缓存在谓词对象上(扫描热路径只编译一次) function buildPredMatcher(pred) { if (pred._m) return pred._m; var val = String(pred.value); var m; if (pred.prop === 'z-index' && /^\d+$/.test(val)) { m = { t: 'zi', n: parseInt(val, 10) }; } else if (val.length > 2 && val.charAt(0) === '/' && val.charAt(val.length - 1) === '/') { try { m = { t: 're', r: new RegExp(val.slice(1, -1), 'i') }; } catch (e) { m = null; } if (!m) m = { t: 'exact', s: val.toLowerCase() }; } else if (val.indexOf('*') !== -1) { var parts = val.split('*'); for (var k = 0; k < parts.length; k++) parts[k] = parts[k].replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); try { m = { t: 're', r: new RegExp('^' + parts.join('.*') + '$', 'i') }; } catch (e2) { m = { t: 'exact', s: val.toLowerCase() }; } } else { m = { t: 'exact', s: val.toLowerCase() }; } pred._m = m; return m; } function predOk(el, pred, memo) { var v = cssVal(el, pred.pseudo, pred.prop, memo); if (v === null || v === undefined) return false; var m = buildPredMatcher(pred); if (m.t === 'zi') { var n = parseInt(v, 10); return !isNaN(n) && n === m.n; } if (m.t === 're') { try { return m.r.test(String(v)); } catch (e) { return false; } } return String(v).toLowerCase() === m.s; } function ruleOk(el, parsed, memo) { for (var i = 0; i < parsed.preds.length; i++) { if (!predOk(el, parsed.preds[i], memo)) return false; } return true; } function MiniExtendedCss(opts) { this._rules = []; this._hidden = []; this._mo = null; try { var sheet = (opts && opts.styleSheet) || ''; var lines = sheet.split(String.fromCharCode(10)); for (var i = 0; i < lines.length; i++) { var line = lines[i].trim(); if (!line) continue; var br = line.indexOf('{'); if (br <= 0) continue; var list = splitList(line.slice(0, br)); for (var j = 0; j < list.length; j++) { var parsed = parseSelector(list[j]); if (parsed) this._rules.push({ parsed: parsed, sel: list[j] }); } } } catch (e) {} this._hasStarRule = false; for (var _ri = 0; _ri < this._rules.length; _ri++) { if (this._rules[_ri].parsed.base === '*') { this._hasStarRule = true; break; } } this._lastStarScanAt = 0; this._starTimer = null; this._churnAt = []; this._churnN = []; this._susp = []; } // 宽基底(*)规则 MO 限频补扫: 限频窗内跳过的星号扫描由这个定时器对根节点一次兜底, // 覆盖窗内累积的全部新增节点; 非星号规则(窄基底)不受限频, 照常即时求值 MiniExtendedCss.prototype._scheduleStarCatchup = function () { var self = this; if (self._starTimer) return; self._starTimer = _setTimeout(function () { self._starTimer = null; try { self._scan(_document.documentElement || _document, null); } catch (e) {} }, _STAR_THROTTLE_MS); }; // 猫鼠熔断: 单条扩展规则在滚动窗内增量隐藏计数, 超阈值即冻结该规则本页的增量求值, // 阈值高于引擎单轮候选上限 —— 单轮扫描永不触发, 持续多轮重建(约>60个/秒)才熔断, // 已隐藏元素保持原状(样式观察器维持), 刷新自动恢复。仅统计变更驱动路径, 初始全量 // 扫描不计 —— 正常页面远达不到阈值, 触发即意味着页面在持续批量重建同类元素 MiniExtendedCss.prototype._noteHide = function (idx, fromMo) { if (!fromMo) return; var now = Date.now(); if (!this._churnAt[idx] || now - this._churnAt[idx] > 10000) { this._churnAt[idx] = now; this._churnN[idx] = 0; } this._churnN[idx]++; if (this._churnN[idx] > 600 && !this._susp[idx]) { this._susp[idx] = true; try { if (typeof LogManager !== 'undefined' && LogManager.add) LogManager.add('elementCssBlock', null, { type: 'CSS_EXT_CHURN_BREAK', detail: '扩展规则短窗隐藏超限(页面在持续批量重建同类元素), 本页暂停其增量求值, 刷新恢复: ' + String((this._rules[idx] && this._rules[idx].sel) || '').slice(0, 120) }); } catch (e) {} } }; MiniExtendedCss.prototype._hide = function (el) { try { if (el.getAttribute && el.getAttribute('data-ab-ext') === '1') return; // 脚本自身 UI 豁免(标记面板宿主已 markSafe): 宽形态规则不得把自家拾取面板当广告藏掉 if (typeof _isSafe === 'function' && _isSafe(el)) return; if (typeof _hasSafeAncestor === 'function' && _hasSafeAncestor(el)) return; if (el.setAttribute) el.setAttribute('data-ab-ext', '1'); el.style.setProperty('display', 'none', 'important'); el.style.setProperty('visibility', 'hidden', 'important'); el.style.setProperty('pointer-events', 'none', 'important'); this._protect(el); this._hidden.push(el); } catch (e) {} }; MiniExtendedCss.prototype._scan = function (root, memo, fromMo) { try { if (!root) return; // 无谓容器标签整棵跳过: 这类节点自身不可能满足扩展谓词(不可见/无计算形态), // 省掉"每新增节点 × 每规则 qSA+computed 求值"里的整段空转 if (root.nodeType === 1 && (root.tagName === 'SCRIPT' || root.tagName === 'STYLE' || root.tagName === 'LINK' || root.tagName === 'META' || root.tagName === 'NOSCRIPT' || root.tagName === 'BR' || root.tagName === 'HR')) return; var self = this; // 全量基底(*)规则的子树候选整批只查一次, 多条 * 规则共享同一集合 —— // 子树查询数与规则数解耦, N 条宽版规则共用一次 qSA var starSub = null; for (var i = 0; i < self._rules.length; i++) { var p = self._rules[i].parsed; if (self._susp && self._susp[i]) continue; try { if (root.matches && root.matches(p.base) && ruleOk(root, p, memo)) { self._noteHide(i, fromMo); if (!self._susp[i]) self._hide(root); } } catch (e) {} if (p.base === '*') { // 宽基底 MO 限频: 限频窗内的 MO 批次跳过星号子树求值, 由补扫定时器兜底 if (fromMo && self._hasStarRule) { var _nowS = Date.now(); if (_nowS - self._lastStarScanAt < _STAR_THROTTLE_MS) { self._scheduleStarCatchup(); continue; } self._lastStarScanAt = _nowS; } // 全量基底(去标签化的形态规则): 命中元素常是新增容器内的子节点, 必须扫子树; // 限界预筛 class/id 持有者(伪元素层样式必须以 class/id 为目标)防超大子树卡段; // 非渲染元素(script/style/link/meta/noscript/br/hr)的伪元素无计算形态, // position 恒不等于 fixed, 候选直接剔除(结果不变, 省去无效求值) if (!starSub) { starSub = []; if (root.querySelectorAll) { try { var _sub = root.querySelectorAll('*[class],[id]'); for (var _sk = 0; _sk < _sub.length && _sk < 500; _sk++) { var _tg = (_sub[_sk].tagName || '').toUpperCase(); if (_tg === 'SCRIPT' || _tg === 'STYLE' || _tg === 'LINK' || _tg === 'META' || _tg === 'NOSCRIPT' || _tg === 'BR' || _tg === 'HR') continue; starSub.push(_sub[_sk]); } } catch (e) {} } } for (var _si2 = 0; _si2 < starSub.length; _si2++) { var _el2 = starSub[_si2]; try { if (_el2.getAttribute && _el2.getAttribute('data-ab-ext') === '1') { if (_el2.style && _el2.style.getPropertyValue('display') !== 'none') self._applyHideStyles(_el2); continue; } if (ruleOk(_el2, p, memo)) { self._noteHide(i, fromMo); if (!self._susp[i]) self._hide(_el2); } } catch (e) {} } continue; } if (p.base.indexOf(' ') !== -1) continue; if (!root.querySelectorAll) continue; var els = root.querySelectorAll(p.base); for (var j = 0; j < els.length; j++) { var el = els[j]; try { if (el.getAttribute && el.getAttribute('data-ab-ext') === '1') { // 已标记元素被页面改回可见(如整串 cssText 重写)时重新隐藏 if (el.style && el.style.getPropertyValue('display') !== 'none') self._applyHideStyles(el); continue; } if (ruleOk(el, p, memo)) { self._noteHide(i, fromMo); if (!self._susp[i]) self._hide(el); } } catch (e) {} } } } catch (e) {} }; // 隐藏样式补写(保护观察者与重隐共用; 不重复入 _hidden/不打标记) MiniExtendedCss.prototype._applyHideStyles = function (el) { el.style.setProperty('display', 'none', 'important'); el.style.setProperty('visibility', 'hidden', 'important'); el.style.setProperty('pointer-events', 'none', 'important'); }; // 每个被隐藏元素挂 style 属性观察: 页面改写内联样式(整串 cssText 重写等)后自动补隐; // 单元素补隐上限 50 次防互改死循环; 元素离树即断开观察 MiniExtendedCss.prototype._protect = function (el) { var self = this; if (!self._protectors) self._protectors = []; if (self._protectors.length > 400) return; var n = 0; var mo = new _MutationObserver(function () { try { if (!el.isConnected) { mo.disconnect(); return; } if (el.style && el.style.getPropertyValue('display') !== 'none') { if (++n > 50) { mo.disconnect(); return; } self._applyHideStyles(el); } } catch (e) {} }); try { mo.observe(el, { attributes: true, attributeFilter: ['style'] }); } catch (e) { return; } self._protectors.push(mo); }; MiniExtendedCss.prototype.apply = function () { var self = this; try { this._scan(_document.documentElement || _document); } catch (e) {} if (this._mo) { try { this._mo.disconnect(); } catch (e) {} } try { this._mo = new MutationObserver(function (muts) { try { // 同批求值记忆: 主规则+变体镜像规则常读同一元素同一属性, computed 只取一次; // 记忆随回调结束丢弃, 不跨回调缓存(页面样式会变) var memo = null; try { memo = new Map(); } catch (e) {} for (var m = 0; m < muts.length; m++) { var nodes = muts[m].addedNodes; for (var n = 0; n < nodes.length; n++) { var node = nodes[n]; if (!node || node.nodeType !== 1) continue; self._scan(node, memo, true); } } } catch (e) {} }); this._mo.observe(_document.documentElement, { childList: true, subtree: true }); } catch (e) {} }; MiniExtendedCss.prototype.dispose = function () { if (this._mo) { try { this._mo.disconnect(); } catch (e) {} this._mo = null; } if (this._starTimer) { try { _clearTimeout(this._starTimer); } catch (e) {} this._starTimer = null; } this._lastStarScanAt = 0; this._churnAt = []; this._churnN = []; this._susp = []; if (this._protectors) { for (var pi = 0; pi < this._protectors.length; pi++) { try { this._protectors[pi].disconnect(); } catch (e2) {} } this._protectors = []; } for (var i = 0; i < this._hidden.length; i++) { try { var el = this._hidden[i]; if (!el || !el.style) continue; if (el.removeAttribute) el.removeAttribute('data-ab-ext'); el.style.removeProperty('display'); el.style.removeProperty('visibility'); el.style.removeProperty('pointer-events'); } catch (e) {} } this._hidden = []; }; // 面板/卡片计数同款查询(只匹配不隐藏) MiniExtendedCss.query = function (selList) { var out = []; try { var seen = null; try { seen = new Set(); } catch (e) {} var items = splitList(String(selList || '')); for (var i = 0; i < items.length; i++) { var parsed = parseSelector(items[i]); if (!parsed) continue; var els = _document.querySelectorAll(parsed.base); for (var j = 0; j < els.length; j++) { if (ruleOk(els[j], parsed)) { if (seen) { if (!seen.has(els[j])) { seen.add(els[j]); out.push(els[j]); } } else out.push(els[j]); } } } } catch (e) {} return out; }; return MiniExtendedCss; })(); // ===== 轻量引擎定义结束 ===== // ======================== 调试辅助 ======================== // 【功能】全脚本统一的异常/调试日志入口 _debugCatch:所有 try/catch 的失败信息都从这里输出。 // 【机制】仅当 设置→高级→调试日志(DEBUG) 开启时才输出到 F12→Console([AB] 前缀),并自动附带调用位置行号; // 自身带防递归保护,catch 块里调用它不会二次抛错。 // 【用户体验】排查问题三步:① 开启 DEBUG → ② 触发问题 → ③ F12 Console 看 [AB] 日志; // 拦截记录看 设置面板→「拦截日志」(每条可点「加白」放行)。 // 轻量扩展求值引擎: MiniExtendedCss 以 var 声明在本 IIFE 作用域内, 直接引用 let _ExtCss = MiniExtendedCss; // 支持 :matches-css/-before/-after 计算样式谓词 const _debugCatch = function(e, ctx) { if (_debugCatch._isRunning) return; _debugCatch._isRunning = true; try { if (typeof currentConfig !== 'undefined' && currentConfig.DEBUG && typeof console !== 'undefined') { // 自动附带调用位置(行号), 无需各调用点手动传入截断上下文串 var _loc = ''; try { var _st = new Error().stack || ''; var _ln = _st.split('\n')[2]; if (_ln) _loc = ' @' + _ln.trim().slice(0, 90); } catch(_e2) {} console.warn('[AB]', ctx || '', _loc, e && e.message ? e.message : e); } } catch(_) { try { console.error('[AB] _debugCatch error:', _ && _.message ? _.message : _); } catch(__) {} } finally { _debugCatch._isRunning = false; } }; // ======================== 初始样式注入 ======================== // 【功能】页面一启动就注入全局隐藏类 ._uh 的样式定义。 // 【机制】覆盖层拦截等 JS 隐藏路径给元素加上 ._uh 类 → visibility:hidden + opacity:0 + pointer-events:none, // 保留原布局尺寸(不引发页面跳动),且不可点击;加白恢复时移除该类即可 // (CSS 样式表轨与扩展引擎的隐藏走内联样式+专属标记, 不经此类)。 // 【注意】此样式独立于任何模块,模块全关也保留;data-hs 属性用于识别脚本自身的样式标签。 (function () { try { var s = document.createElement('style'); s.setAttribute('data-hs', 'true'); s.textContent = '._uh{visibility:hidden!important;opacity:0!important;pointer-events:none!important}'; (document.documentElement || document).appendChild(s); } catch(e) { _debugCatch(e, "初始隐藏样式注入失败"); } })(); // ======================== 默认配置 ======================== // 【功能】定义脚本的全部默认状态:模块开关、高级配置项、CSP 规则模板、内置黑名单关键词、启发式正则、标题黑白名单。 // 【机制】面板里的开关/设置修改后写入 GM 存储(按域名隔离),刷新后生效;「全局重置」恢复本文件默认值。 // 【注意】内置黑名单是广告特征字符串(统计站域名/混淆代码片段),命中即拦,可在「脚本黑名单」面板单独移除; // 启发式黑名单默认关闭(误杀风险较高,需在高级设置手动开启)。 const DEFAULT_MODULE_STATE = { removeInlineScripts: false, removeExternalScripts: false, interceptThirdParty: false, blockDynamicScripts: false, manageCSP: false, overlayIntercept: false, scriptBlacklistMode: true, }; const DEFAULT_CONFIG_STATE = { inlineScriptStrictMode: false, dynamicScriptStrictMode: false, thirdPartyStrictMode: false, thirdPartyStrictMethod: false, funnelStrictMode: false, spoofUAEnabled: false, simplePlatformSpoof: false, residualCleanupEnabled: false, iframeUIFix: false, redirectBlockerEnabled: true, builtinBlacklistEnabled: true, redirectBlockerCompatibilityMode: true, heuristicBlacklistEnabled: false, crossTagPatternThreshold: 3, trackingParamsCleanerEnabled: true, redirectTitleBlacklistEnabled: true, redirectTitleWhitelistEnabled: true, redirectBlockAllEnabled: false, redirectWhitelistBlockMode: false, DEBUG: false, adLinkClickBlock: false, logNoiseReduction: true, overlayStrictMode: false, staticScriptContentCheck: true, }; const DEFAULT_CSP_RULES_TEMPLATE = [ { id: 1, name: '只允许同源外部脚本', rule: "script-src 'self'", enabled: false }, { id: 2, name: '只允许同源外部样式', rule: "style-src 'self'", enabled: false }, { id: 3, name: '只允许同源图片', rule: "img-src 'self'", enabled: false }, { id: 4, name: '只允许同源框架', rule: "frame-src 'self'", enabled: false }, { id: 5, name: '只允许同源媒体', rule: "media-src 'self'", enabled: false }, { id: 6, name: '只允许同源对象与嵌入', rule: "object-src 'self'", enabled: false }, { id: 7, name: '只允许同源网络请求', rule: "connect-src 'self'", enabled: false }, ]; // 内置黑名单关键词:常见广告/统计脚本特征串(如统计站域名、混淆代码片段), // 脚本内容或地址命中任意一条即拦截。 const BUILTIN_BLACKLIST_KEYWORDS = [ 'hm.baidu.com', 'tongji()', 'tj()', 'push.js', 'cnzz', 'histats.com', 'https://hongosi.xn--', '{return void 0!==b[a]?b[a]:a}).join("")}', '${scripts[randomIndex]}', '${scripts[Math.random()', 'https://"+Date.parse(new Date())+', 'https://"+(new Date().getDate())+"', 'https://{randomstr}.', 'new Function(t)()', 'new Function(b)()', 'new Function(c)()', 'new Function(t);', 'new Function(b);', 'new Function(c);', "new Function('d',e)", 'new Function(document[', 'new Function(function(p,a,c,k,e,d)', 'function guanggao(', 'nginx pc', ':8003/', ':8004/', ':8006/', ':8007/', ':8008/', ':8009/', ':8010/', ':8891/', ':8887/', ':21467/', ':690/', ':6681/', ':21233/', '2147483646', 'OJ:5LF_XDRT4', '.insertAdjacentElement("beforebegin",_el)', 'Math.floor(2147483648 * Math.random());', 'Math.floor(Math.random()*url.length)', 'Math.floor(Math.random() * urls.length)', "new Date()['getTime']()", 'newDate=new window', 'Math.floor(((new Date()).getTime()', '&&navigator[', '=navigator;', 'navigator.platform){setTimeout(function', 'disableDebugger', 'blockDeveloperTools', '["Date"]())[\'getTime\']()', '\')', '<\\/\'+\'s\'+\'c\'+\'ri\'+\'pt\'+\'>\')', '(\'#htmlContenthtml\').html', 'D.createElement(\'span\');', 'window.$m(', '{win:false,mac:false,xll:false}', 'parseInt(Math[\'random\'' ]; var _heuristicRegexGroups = null; function getHeuristicRegexGroups() { if (_heuristicRegexGroups !== null) return _heuristicRegexGroups; if (!currentConfig.heuristicBlacklistEnabled) return null; try { const hexGroup = [ '(?:_0x[a-zA-Z0-9]{4,}.*){5,}', 'parseInt\\s*\\(\\s*[\'"\\x60]0x[0-9a-fA-F]{2,}[\'"\\x60]?\\s*\\)\\s*(?:\\||\\^|&)', '(?:\\\\x[0-9a-fA-F]{2}){10,}', '(?:\\\\u[0-9a-fA-F]{4}){10,}', '\\\\x[0-9a-fA-F]{2}(?:\\\\x[0-9a-fA-F]{2}){20,}', '(?:\\^|\\||~)\\s*0x[0-9a-fA-F]{2,}\\s*(?:\\^|\\||~)', 'parseInt\\s*\\([^)]+\\)\\s*\\^\\s*0x[0-9a-fA-F]{2,}', ]; const domGroup = [ "(?:setTimeout|setInterval)\\s*\\(\\s*(?:atob|unescape)\\s*\\(", '\\bwith\\s*\\(\\s*(?:document|window)\\s*\\)\\s*\\{', '(?:window|document)\\s*\\[\\s*[\'"][^\'"]+[\'"]\\s*\\+\\s*[\'"][^\'"]+[\'"]\\s*\\]\\s*\\(', ]; const controlGroup = [ 'blockDeveloperTools|disableDebugger|devtoolschange', 'setTimeout\\s*\\(\\s*[\'"\\x60](?:javascript:|eval\\s*\\(|Function\\s*\\()', 'setInterval\\s*\\(\\s*[\'"\\x60](?:javascript:|eval\\s*\\(|Function\\s*\\()', 'setTimeout\\s*\\(\\s*(?:function|\\(\\)\\s*=>)\\s*\\{[^}]*?location\\.(?:href|replace|assign)', '\\b(?:document|window)\\.(?:oncontextmenu|onkeydown|onkeyup|onselectstart|ondragstart|onmousedown)\\s*=\\s*function', ]; const cipherGroup = [ 'atob\\s*\\([^)]*\\)[^;]{0,100}?(?:eval|Function)\\s*\\(', '(?:eval|Function|document\\.write)\\s*\\([^)]{0,200}?atob\\s*\\(', 'atob\\s*\\(.+?\\.split\\s*\\(\\s*[\'"][\'"]\\s*\\)\\s*\\.map', '\\batob\\s*\\(\\s*[\'"][A-Za-z0-9+/=]{80,}[\'"]\\s*\\)[^;]{0,200}?(?:eval|Function|document\\.write|\\.src\\s*=|\\.href\\s*=)', 'atob\\s*\\(.*?\\).*?atob\\s*\\(', 'unescape\\s*\\(.*?\\)\\s*\\+\\s*unescape', '(?:eval|Function)\\s*\\([^)]{0,200}?unescape\\s*\\(', 'unescape\\s*\\([^)]*\\)[^;]{0,100}?(?:eval|Function)\\s*\\(', '(?:eval|Function)\\s*\\([^)]{0,200}?decodeURIComponent\\s*\\(', 'decodeURIComponent\\s*\\([^)]*\\)[^;]{0,100}?(?:eval|Function)\\s*\\(', '"[\\w\\-~!@#$%^&*()+=\\[\\]{}|\\\\:;\'<>,.?/` ]{60,}"[^;]{0,120}?(?:eval)\\s*\\(', '\\.replace\\s*\\(\\s*\\/\\\\\\\\[a-f0-9]+\\/g\\s*,\\s*[\'"\\x60]\\\\\\\\x[\'"\\x60]\\s*\\).*?(?:eval|Function)\\s*\\(', '(?:\\\\x[0-9a-fA-F]{2}){10,}[^;]{0,100}?(?:eval|Function)\\s*\\(', '(?:\\\\u[0-9a-fA-F]{4}){5,}[^;]{0,100}?(?:eval|Function)\\s*\\(', '(?:var|let|const)\\s+\\w+\\s*=\\s*[\'"][A-Za-z0-9+/=]{300,}[\'"][^;]{0,80}?(?:eval|Function)\\s*\\(', '(?:String\\.fromCharCode|fromCodePoint)\\s*\\([^)]{20,}\\)[^;]{0,100}?(?:eval|Function)\\s*\\(', '\\[\\d{2,3}(?:,\\d{2,3}){5,}\\][^;]{0,50}?(?:eval|Function|String\\.fromCharCode)\\s*\\(', '\\.split\\s*\\(\\s*""\\s*\\)\\s*\\.\\s*map\\s*\\([^)]{0,1000}\\)[^;]{0,1000}?new\\s+Function', 'String\\.fromCharCode\\.apply\\s*\\(null,\\s*\\[', '\\(function\\s*\\([^)]*\\)\\s*\\{[^}]{0,800}?(?:atob[^}]{0,800}?(?:eval|Function)|(?:eval|Function)[^}]{0,800}?atob)\\s*\\(', 'function\\s+\\w+\\s*\\([^)]*\\)\\s*\\{[^}]*?atob[^}]*?(?:eval|Function)\\s*\\(', '(?:toString|split|replace|substring|substr|slice|trim|charAt|charCodeAt|join|reverse){5,}[^;]{0,200}?(?:eval|Function|atob|document\\.write)\\s*\\(', '(?:setTimeout|setInterval)\\s*\\(\\s*(?:function|\\(\\)\\s*=>)\\s*\\{[^}]{0,300}?(?:eval|Function|atob)\\s*\\(', '(?:fetch|XMLHttpRequest)\\s*\\(?[^)]{0,200}?\\)[^;]{0,300}?(?:eval|Function)\\s*\\(', '\\beval\\s*\\(\\s*atob\\s*\\(', '\\beval\\s*\\(\\s*String\\.fromCharCode\\s*\\(', '\\blocation\\s*\\.\\s*href\\s*=\\s*(?:atob|String\\.fromCharCode|decodeURIComponent)', '\\blocation\\s*(?:\\.\\s*href|\\[\\s*[\'"]href[\'"]\\s*\\])\\s*=\\s*[\'"][^\'"]{200,}', 'setTimeout\\s*\\(\\s*[\'"][^\'"]*location\\.href[^\'"]*[\'"]', 'new\\s+Function\\s*\\(\\s*[\'"\\x60][^\'"\\x60]{500,}[\'"\\x60]\\s*\\)', '(?:eval|Function)\\s*\\(\\s*(?:[\\w$]+\\s*\\+\\s*){2,}[\\w$]+\\s*\\)', '(?:eval|Function)\\s*\\(\\s*[\\w$]+\\s*\\.\\s*(?:split|slice|substring|replace|join|reverse)\\s*\\(', '(?:eval|Function)\\s*\\(\\s*\\[\\s*[^\\]]{0,300}?\\]\\s*\\.\\s*join\\s*\\(\\s*[\'"\\x60][\'"\\x60]\\s*\\)\\s*\\)', '\\b(?:atob|decodeURIComponent|unescape)\\s*\\([^)]{30,}\\)\\s*;?\\s*(?:eval|Function)\\s*\\(', 'String\\.fromCharCode\\s*\\(\\s*\\d{1,3}(?:\\s*,\\s*\\d{1,3})+\\s*\\)\\s*\\+', '\\b(?:window|document|self|top)\\s*\\[\\s*[\'"\\x60][^\'"\\x60]{1,10}[\'"\\x60]\\s*\\]\\s*=\\s*(?:atob|String\\.fromCharCode|decodeURIComponent|unescape)', '(?:eval|Function)\\s*\\(\\s*[\'"\\x60][^\'"\\x60]{0,120}[\'"\\x60]\\s*\\+\\s*[\'"\\x60][^\'"\\x60]{0,120}[\'"\\x60]\\s*\\+', '\\b[a-z_][a-zA-Z0-9_]{1,5}\\s*\\(\\s*\\d{5,}(?:\\s*,\\s*\\d+){1,}\\s*\\)', '^[a-zA-Z_$]\\w{2,}\\s*\\(\\s*\\d{4,}(?:\\s*,\\s*\\d+)*\\s*\\)\\s*;?\\s*$', "(?:document\\.write|document\\.writeln)\\s*\\(\\s*unescape\\s*\\(", "window\\.open\\s*\\(\\s*(?:atob|unescape|decodeURIComponent)\\s*\\(", '(?:setTimeout|setInterval)\\s*\\(\\s*(?:atob|unescape)\\s*\\(', ]; const miscGroup = [ 'constructor\\s*\\(\\s*[\'"\\x60]return\\s+this[\'"\\x60]\\s*\\)\\s*\\(', '\\.constructor\\.constructor\\([^\\)]+\\)\\s*\\(', 'try\\s*\\{[^}]{0,200}?(?:eval|Function|atob|document\\.write)\\s*\\([^)]{0,200}\\}\\s*catch\\s*\\(\\s*[a-zA-Z_]+\\s*\\)\\s*\\{\\s*\\}', 'try\\s*\\{[^}]{0,150}\\}\\s*catch\\s*\\(\\s*\\w+\\s*\\)\\s*\\{\\s*return\\s+(?:_0x|this|constructor)', '\\.style\\.position\\s*=\\s*[\'"]fixed[\'"][\\s\\S]{0,50}?\\.style\\.zIndex\\s*=\\s*[\'"]?[1-9]\\d{4,}', '_0x[0-9a-f]+\\s*=\\s*function\\s*\\(\\s*_0x[0-9a-f]+\\s*,\\s*_0x[0-9a-f]+\\s*\\)', '_0x[0-9a-f]+\\s*=\\s*function\\s*\\(\\s*_0x[0-9a-f]+\\s*,\\s*_0x[0-9a-f]+\\s*,\\s*_0x[0-9a-f]+\\s*\\)', '(?:Object\\.keys|Object\\.values)\\s*\\(\\s*_0x[0-9a-f]+\\s*\\)\\.map\\s*\\(', '_0x[0-9a-f]+\\s*\\.forEach\\s*\\(\\s*(?:_0x[0-9a-f]+|function)\\s*\\(', '(?:const|let|var)\\s*\\{[^}]{5,}\\}\\s*=\\s*_0x[0-9a-f]+\\s*\\(', '!function\\s*\\(\\s*\\)\\s*\\{[^}]{0,200}return\\s+_0x[0-9a-f]+\\s*\\(', 'JSON\\.parse\\s*\\(\\s*_0x[0-9a-f]+\\s*\\(', '(?:window|document|navigator)\\s*\\[\\s*[\'"][^\'"]{2,10}[\'"]\\s*\\+\\s*[\'"][^\'"]{2,10}[\'"]\\s*\\]\\s*\\(', 'function\\s+[a-z]\\d[a-z0-9]{6,}', '\\[\\s*[\'"][^\'"]{1,10}[\'"]\\s*\\+\\s*[\'"][^\'"]{1,10}[\'"]\\s*\\+\\s*[\'"][^\'"]{1,10}[\'"]\\s*\\]', 'arguments\\s*\\[\\s*\\d+\\s*\\]\\s*\\(\\s*\\d+\\s*\\)', 'try\\s*\\{\\s*[a-zA-Z_]\\w*?\\d{1,4}\\s*\\([^)]*\\)\\s*;?\\s*\\}\\s*catch\\s*\\(\\s*\\w+\\s*\\)\\s*\\{\\s*\\}?\\s*;?\\s*try\\s*\\{\\s*[a-zA-Z_]\\w*?\\d{1,4}\\s*\\([^)]*\\)\\s*;?\\s*\\}\\s*catch\\s*\\(\\s*\\w+\\s*\\)\\s*\\{\\s*\\}?\\s*;?\\s*try\\s*\\{\\s*[a-zA-Z_]\\w*?\\d{1,4}\\s*\\([^)]*\\)\\s*;?\\s*\\}\\s*catch\\s*\\(\\s*\\w+\\s*\\)\\s*\\{\\s*\\}?\\s*', 'document\\.cookie[^;]{0,200}?(?:new\\s+)?Image\\s*[=(]', '_0x[0-9a-f]+\\s*\\(\\s*_0x[0-9a-f]+\\s*\\)[^;]{0,50}?(?:eval|Function|atob|JSON\\.parse)\\s*\\(', "\\[\\s*['\\\"]push['\\\"]\\s*\\]\\s*\\(\\s*[^)\\[]{0,40}\\[\\s*['\\\"]shift['\\\"]\\s*\\]", ]; const adkitGroup = [ 'writeln\\s*\\(\\s*[\'"]