Greasy Fork is available in English.
阻止网页通过 Function/eval/debugger 等常见方式来无限断点反调试
// ==UserScript==
// @name Anti Anti-Debugger Enhanced v1.3
// @namespace https://example.com/
// @version 1.3.0
// @description 阻止网页通过 Function/eval/debugger 等常见方式来无限断点反调试
// @author IsKongKongYa
// @match *://*/*
// @run-at document-start
// @inject-into page
// @grant unsafeWindow
// @license MIT
// ==/UserScript==
(function () {
'use strict';
// ==================================================================
// 用户可配置项(按需开关)
// ==================================================================
const CONFIG = {
DEBUG_LOG: false, // 控制台调试日志
AGGRESSIVE_IMPORT_SCRIPTS: true, // Worker 内 importScripts 使用 XHR+eval 激进拦截
BLOCK_CONSOLE_CLEAR: true, // 阻止 console.clear
PATCH_INNER_HTML: true, // 拦截 innerHTML 中的反调试代码
PATCH_REQUEST_ANIMATION_FRAME: true, // 拦截 requestAnimationFrame 中的可疑回调
EXPOSE_DEBUG_API: true, // 暴露 __ANTI_DEBUGGER__ 调试 API
};
const win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;
const doc = win.document;
function log(...args) {
if (CONFIG.DEBUG_LOG) console.log('[Anti-Debugger v3.1]', ...args);
}
const NativeStore = {
Function: win.Function,
eval: win.eval,
Blob: win.Blob,
Worker: win.Worker,
URL_createObjectURL: win.URL && win.URL.createObjectURL,
URL_revokeObjectURL: win.URL && win.URL.revokeObjectURL,
FnToString: Function.prototype.toString,
setTimeout: win.setTimeout,
setInterval: win.setInterval,
appendChild: Element.prototype.appendChild,
insertBefore: Element.prototype.insertBefore,
replaceChild: Element.prototype.replaceChild,
createElement: Document.prototype.createElement,
write: Document.prototype.write,
writeln: Document.prototype.writeln,
};
// ==================================================================
// 可序列化纯函数(通过 fn.toString() 注入 Worker,禁止引用闭包变量)
// ==================================================================
// [FIX #1] 循环折叠 + 同类引号 + 混合引号("a"+'b')支持
function tryFoldSimpleConcat(code) {
if (typeof code !== 'string') return code;
var dqRe = /"((?:[^"\\]|\\.)*)"\s*\+\s*"((?:[^"\\]|\\.)*)"/g;
var sqRe = /'((?:[^'\\]|\\.)*)'\s*\+\s*'((?:[^'\\]|\\.)*)'/g;
var btRe = /`((?:[^`\\]|\\.)*)`\s*\+\s*`((?:[^`\\]|\\.)*)`/g;
var mxRe = /(?:"((?:[^"\\]|\\.)*)"|'((?:[^'\\]|\\.)*)')\s*\+\s*(?:"((?:[^"\\]|\\.)*)"|'((?:[^'\\]|\\.)*)')/g;
var out = code;
var prev;
var rounds = 0;
do {
prev = out;
// 同类引号折叠(保留原始引号风格)
dqRe.lastIndex = 0;
out = out.replace(dqRe, function (_, a, b) { return '"' + a + b + '"'; });
sqRe.lastIndex = 0;
out = out.replace(sqRe, function (_, a, b) { return "'" + a + b + "'"; });
btRe.lastIndex = 0;
out = out.replace(btRe, function (_, a, b) { return '`' + a + b + '`'; });
// 混合引号折叠(输出双引号,跳过含双引号内容防语法错误)
mxRe.lastIndex = 0;
out = out.replace(mxRe, function (m, dq1, sq1, dq2, sq2) {
// 两侧引号类型相同 → 跳过(已被同类正则处理)
var leftIsDouble = dq1 != null;
var rightIsDouble = dq2 != null;
if (leftIsDouble === rightIsDouble) return m;
var a = leftIsDouble ? dq1 : (sq1 || '');
var b = rightIsDouble ? dq2 : (sq2 || '');
if (a.indexOf('"') >= 0 || b.indexOf('"') >= 0) return m;
return '"' + a + b + '"';
});
} while (out !== prev && ++rounds < 5);
return out;
}
// [FIX #2 prep] 改用 atob(非 win.atob)以便序列化到 Worker
function tryDecodeBase64Literal(code) {
if (typeof code !== 'string') return code;
return code.replace(
/\batob\s*\(\s*(['"`])([A-Za-z0-9+/=]{8,})\1\s*\)/g,
function (m, q, b64) {
try { return JSON.stringify(atob(b64)); }
catch (e) { return m; }
}
);
}
// [FIX #2] 只解码可见 ASCII 范围(0x20-0x7E),避免展开控制字符破坏代码
function tryDecodeEscapes(code) {
if (typeof code !== 'string') return code;
return code
.replace(/\\x([2-7][0-9a-fA-F])/g, function (m, h) {
var c = parseInt(h, 16);
return (c >= 0x20 && c <= 0x7e) ? String.fromCharCode(c) : m;
})
.replace(/\\u00([2-7][0-9a-fA-F])/g, function (m, h) {
var c = parseInt(h, 16);
return (c >= 0x20 && c <= 0x7e) ? String.fromCharCode(c) : m;
});
}
function normalizeCode(code) {
if (typeof code !== 'string') return code;
var out = code;
out = tryFoldSimpleConcat(out);
out = tryDecodeBase64Literal(out);
out = tryDecodeEscapes(out);
return out;
}
function stripDebugger(code) {
if (typeof code !== 'string') return code;
var out = normalizeCode(code);
out = out.replace(/\bdebugger\b\s*;?/g, '');
out = out.replace(/;\s*;/g, ';');
out = out.replace(/Function\s*\(\s*(['"`])\s*debugger\s*;?\s*\1\s*\)/g, 'Function("")');
out = out.replace(/new\s+Function\s*\(\s*(['"`])\s*debugger\s*;?\s*\1\s*\)/g, 'new Function("")');
out = out.replace(/eval\s*\(\s*(['"`])\s*debugger\s*;?\s*\1\s*\)/g, 'eval("")');
return out;
}
// ==================================================================
// [FIX #4] looksSuspicious 评分制,降低误报率
// ==================================================================
function looksSuspicious(code) {
if (typeof code !== 'string') return false;
var normalized = normalizeCode(code);
// 直接命中
if (/\bdebugger\b/.test(normalized)) return true;
// 高可疑:Function/eval 参数直接包含 debugger
if (/Function\s*\(\s*['"`][^)]{0,500}debugger[^)]{0,500}['"`]\s*\)/.test(normalized)) return true;
if (/eval\s*\(\s*['"`][^)]{0,500}debugger[^)]{0,500}['"`]\s*\)/.test(normalized)) return true;
// 评分制:至少命中 2 项才标记
var score = 0;
if (/new\s+Function\s*\(/.test(normalized)) score++;
if (/\.constructor\s*\(\s*['"`]/.test(normalized)) score++;
if (/\beval\s*\(\s*atob\s*\(/.test(normalized)) score++;
if (/\batob\s*\([\s\S]*(?:debugger|Function|eval)/.test(code)) score++;
if (/setInterval\s*\(\s*['"`]/.test(normalized)) score++;
if (/setTimeout\s*\(\s*['"`]/.test(normalized)) score++;
return score >= 2;
}
// ==================================================================
// 工具函数
// ==================================================================
function safeToString(name) {
return function () {
return 'function ' + name + '() { [native code] }';
};
}
function patchFunctionLike(targetObj, key, wrapperFactory) {
var original = targetObj[key];
if (typeof original !== 'function') return;
var wrapped = wrapperFactory(original);
try {
Object.defineProperty(wrapped, 'toString', {
configurable: true,
value: safeToString(key)
});
} catch (e) {}
try {
Object.defineProperty(targetObj, key, {
configurable: true,
writable: true,
value: wrapped
});
log('patched', key);
} catch (e) {
log('patch failed:', key, e);
}
}
function patchCodeStringArg(args, indexList) {
var newArgs = Array.from(args);
for (var i = 0; i < indexList.length; i++) {
if (typeof newArgs[indexList[i]] === 'string') {
newArgs[indexList[i]] = stripDebugger(newArgs[indexList[i]]);
}
}
return newArgs;
}
// ==================================================================
// 主线程基础补丁
// ==================================================================
patchFunctionLike(win, 'eval', function (original) {
return new Proxy(original, {
apply: function (target, thisArg, args) {
return Reflect.apply(target, thisArg, patchCodeStringArg(args, [0]));
}
});
});
(function patchFunctionConstructor() {
var RawFunction = NativeStore.Function;
function SafeFunction() {
var patchedArgs = Array.from(arguments).map(function (arg) {
return typeof arg === 'string' ? stripDebugger(arg) : arg;
});
return RawFunction.apply(this, patchedArgs);
}
SafeFunction.prototype = RawFunction.prototype;
var FunctionProxy = new Proxy(SafeFunction, {
apply: function (target, thisArg, args) {
var patchedArgs = args.map(function (arg) {
return typeof arg === 'string' ? stripDebugger(arg) : arg;
});
return Reflect.apply(RawFunction, thisArg, patchedArgs);
},
construct: function (target, args, newTarget) {
var patchedArgs = args.map(function (arg) {
return typeof arg === 'string' ? stripDebugger(arg) : arg;
});
return Reflect.construct(RawFunction, patchedArgs, newTarget || RawFunction);
}
});
try {
Object.defineProperty(FunctionProxy, 'toString', {
configurable: true,
value: safeToString('Function')
});
} catch (e) {}
try {
Object.defineProperty(win, 'Function', {
configurable: true, writable: true, value: FunctionProxy
});
} catch (e) {}
try {
Object.defineProperty(RawFunction.prototype, 'constructor', {
configurable: true, writable: true, value: FunctionProxy
});
} catch (e) {}
})();
['setTimeout', 'setInterval'].forEach(function (name) {
patchFunctionLike(win, name, function (original) {
return new Proxy(original, {
apply: function (target, thisArg, args) {
return Reflect.apply(target, thisArg, patchCodeStringArg(args, [0]));
}
});
});
});
if (CONFIG.PATCH_REQUEST_ANIMATION_FRAME) {
patchFunctionLike(win, 'requestAnimationFrame', function (original) {
return new Proxy(original, {
apply: function (target, thisArg, args) {
var cb = args[0];
if (typeof cb === 'function') {
try {
var src = NativeStore.FnToString.call(cb);
if (looksSuspicious(src)) {
args[0] = function () {};
}
} catch (e) {}
}
return Reflect.apply(target, thisArg, args);
}
});
});
}
// 注意:MutationObserver 触发时脚本可能已开始执行,修改 textContent 无法阻止已启动的执行。
// 但对通过 innerHTML 批量插入的后续 script 节点仍有拦截价值。
function patchScriptNode(node) {
if (!node || node.nodeType !== 1 || node.tagName !== 'SCRIPT') return node;
try {
if (typeof node.textContent === 'string' && node.textContent) {
node.textContent = stripDebugger(node.textContent);
}
} catch (e) {}
try {
if (node.src && typeof node.src === 'string' && node.src.startsWith('javascript:')) {
node.src = stripDebugger(node.src);
}
} catch (e) {}
return node;
}
['appendChild', 'insertBefore', 'replaceChild'].forEach(function (name) {
patchFunctionLike(Element.prototype, name, function (original) {
return new Proxy(original, {
apply: function (target, thisArg, args) {
if (args[0]) patchScriptNode(args[0]);
return Reflect.apply(target, thisArg, args);
}
});
});
});
patchFunctionLike(Document.prototype, 'createElement', function (original) {
return new Proxy(original, {
apply: function (target, thisArg, args) {
var node = Reflect.apply(target, thisArg, args);
try {
if (String(args[0]).toLowerCase() === 'script') {
// 注意:此处用实例属性劫持 text/textContent,会脱离 DOM 原型链行为。
// 可能与 React/Vue 等框架操作 script 节点时产生细微不一致。
var _text = '';
var _textContent = '';
Object.defineProperty(node, 'text', {
configurable: true,
get: function () { return _text; },
set: function (v) { _text = typeof v === 'string' ? stripDebugger(v) : v; }
});
Object.defineProperty(node, 'textContent', {
configurable: true,
get: function () { return _textContent; },
set: function (v) { _textContent = typeof v === 'string' ? stripDebugger(v) : v; }
});
}
} catch (e) {}
return node;
}
});
});
['write', 'writeln'].forEach(function (name) {
patchFunctionLike(Document.prototype, name, function (original) {
return new Proxy(original, {
apply: function (target, thisArg, args) {
var newArgs = args.map(function (arg) {
return typeof arg === 'string' ? stripDebugger(arg) : arg;
});
return Reflect.apply(target, thisArg, newArgs);
}
});
});
});
if (CONFIG.PATCH_INNER_HTML) {
try {
var rawInnerHTMLDescriptor = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
if (rawInnerHTMLDescriptor && rawInnerHTMLDescriptor.set) {
var rawSetter = rawInnerHTMLDescriptor.set;
var rawGetter = rawInnerHTMLDescriptor.get;
Object.defineProperty(Element.prototype, 'innerHTML', {
configurable: true,
get: function () { return rawGetter.call(this); },
set: function (v) {
if (typeof v === 'string' && looksSuspicious(v)) {
v = v.replace(
/(<script[^>]*>)([\s\S]*?)(<\/script>)/gi,
function (m, open, body, close) {
return open + stripDebugger(body) + close;
}
);
}
return rawSetter.call(this, v);
}
});
}
} catch (e) {}
}
// ==================================================================
// Blob / URL / Worker 主链增强
// ==================================================================
var blobToMeta = new WeakMap();
var urlToMeta = new Map();
var wrappedWorkerUrlSet = new Set();
function detectJsMime(type) {
return /javascript|ecmascript|json|text\/plain|application\/octet-stream/i.test(type || '');
}
// [FIX #6] Worker bootstrap 使用 fn.toString() 序列化,消除代码重复
// workerPatchBody 是一个永远不在主线程调用的函数,仅取 toString() 注入到 Worker
// 它假定 stripDebugger 和 __config 变量已在 Worker 作用域中定义
function workerPatchBody() {
/* eslint-disable no-undef */
var __strip = stripDebugger;
function __patchCodeArgs(args, idxs) {
var out = Array.prototype.slice.call(args);
for (var i = 0; i < idxs.length; i++) {
if (typeof out[idxs[i]] === 'string') out[idxs[i]] = __strip(out[idxs[i]]);
}
return out;
}
try {
var __rawEval = self.eval;
self.eval = new Proxy(__rawEval, {
apply: function (target, thisArg, args) {
return Reflect.apply(target, thisArg, __patchCodeArgs(args, [0]));
}
});
} catch (e) {}
try {
var __RawFunction = self.Function;
function __SafeFunction() {
var a = Array.prototype.slice.call(arguments).map(function (x) {
return typeof x === 'string' ? __strip(x) : x;
});
return __RawFunction.apply(this, a);
}
__SafeFunction.prototype = __RawFunction.prototype;
var __FP = new Proxy(__SafeFunction, {
apply: function (target, thisArg, args) {
args = args.map(function (x) { return typeof x === 'string' ? __strip(x) : x; });
return Reflect.apply(__RawFunction, thisArg, args);
},
construct: function (target, args, newTarget) {
args = args.map(function (x) { return typeof x === 'string' ? __strip(x) : x; });
return Reflect.construct(__RawFunction, args, newTarget || __RawFunction);
}
});
self.Function = __FP;
__RawFunction.prototype.constructor = __FP;
} catch (e) {}
// [FIX #3] importScripts 激进拦截:XHR 同步读取 + __strip + eval
// Worker 中同步 XHR 不受主线程限制,比主线程可靠得多
try {
var __rawImportScripts = self.importScripts;
if (__config.AGGRESSIVE_IMPORT_SCRIPTS) {
self.importScripts = function () {
var urls = Array.prototype.slice.call(arguments);
for (var i = 0; i < urls.length; i++) {
try {
var xhr = new XMLHttpRequest();
xhr.open('GET', urls[i], false);
xhr.send();
if (xhr.status >= 200 && xhr.status < 300) {
var code = __strip(xhr.responseText || '');
(0, eval)(code);
continue;
}
} catch (e) {}
// XHR 失败(跨域等)回退原生 importScripts
__rawImportScripts.call(self, urls[i]);
}
};
}
// 非激进模式不做任何处理,保持原生 importScripts
} catch (e) {}
try {
var __rawSetTimeout = self.setTimeout;
self.setTimeout = new Proxy(__rawSetTimeout, {
apply: function (target, thisArg, args) {
return Reflect.apply(target, thisArg, __patchCodeArgs(args, [0]));
}
});
} catch (e) {}
try {
var __rawSetInterval = self.setInterval;
self.setInterval = new Proxy(__rawSetInterval, {
apply: function (target, thisArg, args) {
return Reflect.apply(target, thisArg, __patchCodeArgs(args, [0]));
}
});
} catch (e) {}
/* eslint-enable no-undef */
}
function buildWorkerBootstrap(userCode) {
// 序列化纯函数到 Worker
var serializableFns = [
tryFoldSimpleConcat,
tryDecodeBase64Literal,
tryDecodeEscapes,
normalizeCode,
stripDebugger
];
var parts = [];
parts.push('(function(){');
parts.push('"use strict";');
parts.push('var __config = ' + JSON.stringify({
AGGRESSIVE_IMPORT_SCRIPTS: CONFIG.AGGRESSIVE_IMPORT_SCRIPTS
}) + ';');
for (var i = 0; i < serializableFns.length; i++) {
parts.push(serializableFns[i].toString() + ';');
}
// 提取 workerPatchBody 的函数体(去掉外层 function 声明)
var patchSrc = workerPatchBody.toString();
var bodyMatch = patchSrc.match(/^[^{]*\{([\s\S]*)\}\s*$/);
parts.push(bodyMatch ? bodyMatch[1] : patchSrc);
parts.push('})();');
return parts.join('\n') + '\n\n' + userCode;
}
function makeWrappedWorkerUrlFromCode(code, mimeType) {
var cleanUserCode = stripDebugger(code);
var wrappedCode = buildWorkerBootstrap(cleanUserCode);
var blob = new NativeStore.Blob([wrappedCode], {
type: mimeType || 'application/javascript'
});
var url = NativeStore.URL_createObjectURL.call(win.URL, blob);
wrappedWorkerUrlSet.add(url);
return url;
}
// [FIX #7] SafeBlob 去除双重清理:只对各 part 清理一次,不再 join 后再清理
if (typeof NativeStore.Blob === 'function') {
var RawBlob = NativeStore.Blob;
function SafeBlob(parts, options) {
var originalCode = null;
var cleanedCode = null;
var type = options && options.type ? options.type : '';
try {
if (Array.isArray(parts)) {
var rawTextParts = [];
var cleanTextParts = [];
var sanitizedParts = parts.map(function (part) {
if (typeof part === 'string') {
rawTextParts.push(part);
var cleaned = stripDebugger(part);
cleanTextParts.push(cleaned);
return cleaned;
}
return part;
});
var joinedRaw = rawTextParts.join('\n');
if (joinedRaw) {
originalCode = joinedRaw;
cleanedCode = cleanTextParts.join('\n');
parts = sanitizedParts;
}
}
} catch (e) {
log('SafeBlob sanitize failed:', e);
}
var blob = new RawBlob(parts, options);
try {
if (originalCode !== null && (looksSuspicious(originalCode) || detectJsMime(type))) {
blobToMeta.set(blob, {
originalCode: originalCode,
cleanCode: cleanedCode,
type: type
});
}
} catch (e) {}
return blob;
}
SafeBlob.prototype = RawBlob.prototype;
try {
Object.defineProperty(SafeBlob, 'toString', {
configurable: true, value: safeToString('Blob')
});
} catch (e) {}
try {
Object.defineProperty(win, 'Blob', {
configurable: true, writable: true, value: SafeBlob
});
} catch (e) {}
}
if (win.URL && typeof NativeStore.URL_createObjectURL === 'function') {
patchFunctionLike(win.URL, 'createObjectURL', function (original) {
return new Proxy(original, {
apply: function (target, thisArg, args) {
var blob = args[0];
var url = Reflect.apply(target, thisArg, args);
try {
var meta = blobToMeta.get(blob);
if (meta) {
urlToMeta.set(url, meta);
// 防止长时间运行页面内存泄漏
if (urlToMeta.size > 1000) {
var oldest = urlToMeta.keys().next().value;
urlToMeta.delete(oldest);
}
log('tracked blob url', url);
}
} catch (e) {}
return url;
}
});
});
}
if (win.URL && typeof NativeStore.URL_revokeObjectURL === 'function') {
patchFunctionLike(win.URL, 'revokeObjectURL', function (original) {
return new Proxy(original, {
apply: function (target, thisArg, args) {
var url = args[0];
try {
if (typeof url === 'string') {
urlToMeta.delete(url);
wrappedWorkerUrlSet.delete(url);
}
} catch (e) {}
return Reflect.apply(target, thisArg, args);
}
});
});
}
function tryReadSameOriginScript(url) {
try {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.send();
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 0) {
return xhr.responseText || '';
}
} catch (e) {}
return null;
}
if (typeof NativeStore.Worker === 'function') {
patchFunctionLike(win, 'Worker', function (original) {
return new Proxy(original, {
construct: function (target, args, newTarget) {
var url = args[0];
try {
if (typeof url === 'string' && url.startsWith('javascript:')) {
args[0] = stripDebugger(url);
return Reflect.construct(target, args, newTarget);
}
// 1) blob: 且来自已追踪的 createObjectURL
if (typeof url === 'string' && url.startsWith('blob:')) {
var meta = urlToMeta.get(url);
if (meta && meta.cleanCode != null) {
args[0] = makeWrappedWorkerUrlFromCode(meta.cleanCode, meta.type);
log('worker wrapped from tracked blob url');
return Reflect.construct(target, args, newTarget);
}
// 2) 兜底:尽量读回 blob: 内容
var blobCode = tryReadSameOriginScript(url);
if (typeof blobCode === 'string' && blobCode) {
args[0] = makeWrappedWorkerUrlFromCode(blobCode, 'application/javascript');
log('worker wrapped from fallback-read blob url');
return Reflect.construct(target, args, newTarget);
}
}
// [FIX #5] 3) 普通同源 js 文件,附加日志说明跨域失败情况
if (typeof url === 'string' && /^(https?:|\/|\.\/|\.\.\/)/.test(url)) {
var srcCode = tryReadSameOriginScript(url);
if (typeof srcCode === 'string' && srcCode) {
args[0] = makeWrappedWorkerUrlFromCode(srcCode, 'application/javascript');
log('worker wrapped from same-origin script');
return Reflect.construct(target, args, newTarget);
}
// 跨域或读取失败:直接放行,不阻塞不报错
log('worker script not interceptable (likely cross-origin):', url);
}
} catch (e) {
log('Worker wrap failed:', e);
}
return Reflect.construct(target, args, newTarget);
}
});
});
}
// ==================================================================
// MutationObserver
// ==================================================================
try {
var mo = new MutationObserver(function (mutations) {
for (var i = 0; i < mutations.length; i++) {
var addedNodes = mutations[i].addedNodes;
for (var j = 0; j < addedNodes.length; j++) {
try {
patchScriptNode(addedNodes[j]);
if (addedNodes[j] && addedNodes[j].querySelectorAll) {
var scripts = addedNodes[j].querySelectorAll('script');
for (var k = 0; k < scripts.length; k++) patchScriptNode(scripts[k]);
}
} catch (e) {}
}
}
});
var startObserve = function () {
try {
mo.observe(doc.documentElement || doc, { childList: true, subtree: true });
} catch (e) {}
};
if (doc.documentElement) startObserve();
else doc.addEventListener('DOMContentLoaded', startObserve, { once: true });
} catch (e) {}
// [FIX #8] console.clear:修复未使用的 rawClear,增加 CONFIG 开关
if (CONFIG.BLOCK_CONSOLE_CLEAR) {
try {
var rawClear = console.clear;
console.clear = function () {
log('console.clear blocked');
// 如需恢复原始行为,取消下面注释:
// rawClear.apply(console, arguments);
};
try { console.clear.toString = safeToString('clear'); } catch (e) {}
} catch (e) {}
}
// 调试 API
if (CONFIG.EXPOSE_DEBUG_API) {
try {
win.__ANTI_DEBUGGER__ = {
version: '1.3.0',
config: CONFIG,
stripDebugger: stripDebugger,
looksSuspicious: looksSuspicious,
dumpTrackedBlobUrls: function () {
return Array.from(urlToMeta.keys());
},
dumpWrappedWorkerUrls: function () {
return Array.from(wrappedWorkerUrlSet);
},
test: function () {
console.log('Anti-Debugger v1.3 active');
return true;
}
};
} catch (e) {}
}
log('Anti Anti-Debugger Enhanced v1.3 loaded');
})();