// ==UserScript==
// @name Anti Anti-debugger
// @name:vi Chống Anti-debugger
// @name:zh-CN 反反调试
// @namespace https://greasyfork.org/vi/users/1195312-renji-yuusei
// @version 1.0
// @description Stops most anti-debugging implementations by JavaScript obfuscators and stops the console logs from being automatically cleared.
// @description:vi Ngăn chặn hầu hết các triển khai anti-debugging bằng JavaScript obfuscators và ngăn chặn việc xóa nhật ký console tự động.
// @description:zh-CN 阻止大多数 JavaScript 混淆器实现的反调试,并阻止控制台日志被自动清除。
// @author Yuusei
// @match *://*/*
// @grant unsafeWindow
// @grant GM_setValue
// @grant GM_getValue
// @run-at document-start
// @license GPL-3.0-only
// ==/UserScript==
(function() {
'use strict';
const config = {
excludedDomains: ['vidstream.pro', 'mcloud.to'],
debugKeywords: ['debugger', 'debug', 'debugging', 'breakpoint'],
consoleProps: ['log', 'warn', 'error', 'info', 'debug', 'assert', 'dir', 'dirxml', 'trace', 'group', 'groupCollapsed', 'groupEnd', 'time', 'timeEnd', 'profile', 'profileEnd', 'count'],
enabled: true, // Can be toggled at runtime
};
// Load user settings
const loadSettings = () => {
config.enabled = GM_getValue('antiAntiDebuggerEnabled', true);
config.excludedDomains = GM_getValue('excludedDomains', config.excludedDomains);
};
loadSettings();
const isExcludedDomain = () => config.excludedDomains.some(domain =>
new RegExp(`(^|\.)${domain.replace(/\./g, '\\.')}$`, 'i').test(location.hostname)
);
if (isExcludedDomain()) return;
const safeEval = (code, context = {}) => {
const safeContext = { ...context, console: { log: () => {} } };
const safeCode = `
'use strict';
const alert = () => {};
const confirm = () => {};
const prompt = () => {};
${Object.keys(safeContext).map(key => `const ${key} = this.${key};`).join('\n')}
return (${code});
`;
try {
return new Function(safeCode).call(safeContext);
} catch (error) {
console.warn('Failed to evaluate code:', error);
return null;
}
};
const modifyFunction = (func) => {
if (typeof func !== 'function') return func;
let funcStr = func.toString();
if (config.debugKeywords.some(keyword => funcStr.includes(keyword))) {
funcStr = funcStr.replace(new RegExp(`\\b(${config.debugKeywords.join('|')})\\b`, 'g'), '/* removed */');
return safeEval(funcStr) || func;
}
return func;
};
const wrapConsole = () => {
const originalConsole = { ...console };
const consoleProxy = new Proxy(console, {
get: (target, prop) => {
if (config.consoleProps.includes(prop) && typeof target[prop] === 'function') {
return new Proxy(target[prop], {
apply: (targetFunc, thisArg, args) => {
if (!config.enabled) return Reflect.apply(targetFunc, thisArg, args);
args = args.map(modifyFunction);
return Reflect.apply(targetFunc, thisArg, args);
}
});
}
return Reflect.get(target, prop);
},
set: () => false // Prevent overwriting console properties
});
Object.defineProperty(unsafeWindow, 'console', {
get: () => consoleProxy,
set: () => false,
configurable: false
});
};
const antiAntiDebugger = () => {
const proxyHandler = {
apply: (target, thisArg, args) => {
if (!config.enabled) return Reflect.apply(target, thisArg, args);
args = args.map(modifyFunction);
return Reflect.apply(target, thisArg, args);
},
construct: (target, args) => {
if (!config.enabled) return Reflect.construct(target, args);
args = args.map(modifyFunction);
return Reflect.construct(target, args);
}
};
Function.prototype.constructor = new Proxy(Function.prototype.constructor, proxyHandler);
// Protect eval and Function constructor
unsafeWindow.eval = new Proxy(unsafeWindow.eval, proxyHandler);
unsafeWindow.Function = new Proxy(unsafeWindow.Function, proxyHandler);
};
const preventDebugging = () => {
const noop = () => {};
const protectedProps = [...config.debugKeywords, 'pause', 'alert', 'confirm', 'prompt'];
protectedProps.forEach(prop => {
Object.defineProperty(unsafeWindow, prop, {
get: () => config.enabled ? noop : unsafeWindow[prop],
set: () => {},
configurable: false
});
});
// Override common debugging-related Date methods
const originalDate = unsafeWindow.Date;
unsafeWindow.Date = new Proxy(originalDate, {
construct: (target, args) => {
const date = new target(...args);
date.getTime = new Proxy(date.getTime, {
apply: (target, thisArg, args) => {
if (config.enabled && new Error().stack.includes('debugger')) {
return 0; // Return a fake timestamp
}
return Reflect.apply(target, thisArg, args);
}
});
return date;
}
});
};
const setupToggleShortcut = () => {
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.shiftKey && e.key === 'D') {
config.enabled = !config.enabled;
GM_setValue('antiAntiDebuggerEnabled', config.enabled);
console.log(`Anti Anti-debugger ${config.enabled ? 'enabled' : 'disabled'}`);
}
});
};
wrapConsole();
antiAntiDebugger();
preventDebugging();
setupToggleShortcut();
console.log('Anti Anti-debugger is active');
})();