- // ==UserScript==
- // @name DevTools Bypass
- // @name:vi Bỏ Qua Chặn DevTools
- // @name:zh-CN 开发工具限制绕过
- // @name:ru Разблокировка DevTools
- // @namespace https://gf.qytechs.cn/vi/users/1195312-renji-yuusei
- // @version 2024.12.23.2
- // @description Bypass for website restrictions on DevTools with enhanced protection
- // @description:vi Bỏ qua các hạn chế của trang web về DevTools với bảo vệ nâng cao
- // @description:zh-CN 绕过网站对开发工具的限制,具有增强的保护功能
- // @description:ru Разблокировка DevTools с усиленной защитой
- // @author Yuusei
- // @match *://*/*
- // @grant unsafeWindow
- // @run-at document-start
- // @license GPL-3.0-only
- // ==/UserScript==
-
- (() => {
- 'use strict';
-
- // Constants
- const CONSTANTS = {
- PREFIX: '[DevTools Bypass]',
- LOG_LEVELS: {
- INFO: 'info',
- WARN: 'warn',
- ERROR: 'error',
- DEBUG: 'debug'
- },
- TIME_THRESHOLDS: {
- DEBUGGER: 80,
- CACHE: 30000
- }
- };
-
- // Configuration
- const config = {
- debugPatterns: {
- basic: /[;\s]*(?:debugger|debug(?:ger)?|breakpoint|console\.[a-z]+)[\s;]*/gi,
- advanced: /(?:debugger|debug(?:ger)?|breakpoint|devtools?)(?:\s*\{[\s\S]*?\}|\s*\([^)]*\)|\s*;|\s*$)/gi,
- timing: /(?:performance(?:\.timing)?|Date)\.(?:now|getTime)\(\)|new\s+Date(?:\s*\(\s*\))?\s*\.getTime\(\)/gi,
- eval: /(?:eval|Function|setTimeout|setInterval)\s*\(\s*(?:[`'"].*?(?:debugger|debug|breakpoint).*?[`'"]|\{[\s\S]*?(?:debugger|debug|breakpoint)[\s\S]*?\})\s*\)/gi,
- devtools: /(?:isDevTools?|devtools?|debugMode|debug_mode|debugEnabled)\s*[=:]\s*(?:true|1|!0|yes)/gi,
- consoleCheck: /console\.(?:log|warn|error|info|debug|trace|dir|table)\s*\([^)]*\)/gi,
- functionDebug: /function\s*[^(]*\([^)]*\)\s*\{(?:\s|.)*?(?:debugger|debug|breakpoint)(?:\s|.)*?\}/gi,
- sourceMap: /\/\/[#@]\s*source(?:Mapping)?URL\s*=\s*(?:data:|https?:)?\/\/.*?$/gm,
- debugStrings: /(['"`])(?:(?!\1).)*?(?:debug|debugger|breakpoint|devtools?)(?:(?!\1).)*?\1/gi,
- debugComments: /\/\*[\s\S]*?(?:debug|debugger|breakpoint|devtools?)[\s\S]*?\*\/|\/\/.*(?:debug|debugger|breakpoint|devtools?).*$/gim
- },
- consoleProps: ['log', 'warn', 'error', 'info', 'debug', 'trace', 'dir', 'dirxml', 'table', 'profile', 'group', 'groupEnd', 'time', 'timeEnd'],
- cutoffs: {
- debugger: { amount: 30, within: CONSTANTS.TIME_THRESHOLDS.CACHE },
- debuggerThrow: { amount: 30, within: CONSTANTS.TIME_THRESHOLDS.CACHE }
- },
- bypassTriggers: {
- timeThreshold: CONSTANTS.TIME_THRESHOLDS.DEBUGGER,
- stackDepth: 30,
- recursionLimit: 50
- },
- logging: {
- enabled: true,
- prefix: CONSTANTS.PREFIX,
- levels: Object.values(CONSTANTS.LOG_LEVELS),
- detailedErrors: true
- },
- protection: {
- preventDevToolsKeys: true,
- hideStackTraces: true,
- sanitizeErrors: true,
- obfuscateTimers: true,
- preventRightClick: true,
- preventViewSource: true,
- preventCopy: true,
- preventPaste: true,
- preventPrint: true,
- preventSave: true
- }
- };
-
- // Logger class
- class Logger {
- static #instance;
- #lastLog = 0;
- #logCount = 0;
- #logBuffer = [];
-
- constructor() {
- if (Logger.#instance) {
- return Logger.#instance;
- }
- Logger.#instance = this;
- this.#setupBufferFlush();
- }
-
- #setupBufferFlush() {
- setInterval(() => {
- if (this.#logBuffer.length) {
- this.#flushBuffer();
- }
- }, 1000);
- }
-
- #flushBuffer() {
- this.#logBuffer.forEach(({level, args}) => {
- console[level](config.logging.prefix, ...args);
- });
- this.#logBuffer = [];
- }
-
- #shouldLog() {
- const now = Date.now();
- if (now - this.#lastLog > 1000) {
- this.#logCount = 0;
- }
- this.#lastLog = now;
- return ++this.#logCount <= 10;
- }
-
- #log(level, ...args) {
- if (!config.logging.enabled || !this.#shouldLog()) return;
- this.#logBuffer.push({ level, args });
- }
-
- info(...args) { this.#log(CONSTANTS.LOG_LEVELS.INFO, ...args); }
- warn(...args) { this.#log(CONSTANTS.LOG_LEVELS.WARN, ...args); }
- error(...args) { this.#log(CONSTANTS.LOG_LEVELS.ERROR, ...args); }
- debug(...args) { this.#log(CONSTANTS.LOG_LEVELS.DEBUG, ...args); }
- }
-
- // Original functions store
- const OriginalFunctions = {
- defineProperty: Object.defineProperty,
- getOwnPropertyDescriptor: Object.getOwnPropertyDescriptor,
- setTimeout: window.setTimeout,
- setInterval: window.setInterval,
- Date: window.Date,
- now: Date.now,
- performance: window.performance,
- Function: window.Function,
- eval: window.eval,
- console: {},
- toString: Function.prototype.toString,
- preventDefault: Event.prototype.preventDefault,
- getComputedStyle: window.getComputedStyle,
- addEventListener: window.addEventListener,
- removeEventListener: window.removeEventListener,
- fetch: window.fetch,
- XMLHttpRequest: window.XMLHttpRequest,
-
- initConsole() {
- config.consoleProps.forEach(prop => {
- if (console[prop]) {
- this.console[prop] = console[prop].bind(console);
- }
- });
- }
- };
-
- OriginalFunctions.initConsole();
-
- // Debugger detector
- class DebuggerDetector {
- static #detectionCache = new Map();
- static #detectionHistory = [];
-
- static isPresent() {
- try {
- const cacheKey = 'debugger_check';
- const cached = this.#detectionCache.get(cacheKey);
- if (cached && Date.now() - cached.timestamp < 500) {
- return cached.result;
- }
-
- const startTime = OriginalFunctions.now.call(Date);
- new Function('debugger;')();
- const timeDiff = OriginalFunctions.now.call(Date) - startTime;
-
- const result = timeDiff > config.bypassTriggers.timeThreshold;
- this.#detectionCache.set(cacheKey, {
- result,
- timestamp: Date.now()
- });
-
- this.#detectionHistory.push({
- timestamp: Date.now(),
- result,
- timeDiff
- });
-
- // Keep history for 5 minutes
- const fiveMinutesAgo = Date.now() - 300000;
- this.#detectionHistory = this.#detectionHistory.filter(entry => entry.timestamp > fiveMinutesAgo);
-
- return result;
- } catch {
- return false;
- }
- }
-
- static analyzeStack() {
- try {
- const stack = new Error().stack;
- const frames = stack.split('\n');
- const uniqueFrames = new Set(frames);
-
- return {
- depth: frames.length,
- hasDebugKeywords: frames.some(frame =>
- Object.values(config.debugPatterns).some(pattern => pattern.test(frame))
- ),
- isRecursive: uniqueFrames.size < frames.length,
- suspiciousPatterns: this.#detectSuspiciousPatterns(stack),
- stackHash: this.#generateStackHash(stack)
- };
- } catch {
- return {
- depth: 0,
- hasDebugKeywords: false,
- isRecursive: false,
- suspiciousPatterns: [],
- stackHash: ''
- };
- }
- }
-
- static #detectSuspiciousPatterns(stack) {
- const patterns = [
- /eval.*?\(/g,
- /Function.*?\(/g,
- /debugger/g,
- /debug/g,
- /DevTools/g,
- /console\./g,
- /chrome-extension/g
- ];
- return patterns.filter(pattern => pattern.test(stack));
- }
-
- static #generateStackHash(stack) {
- return Array.from(stack).reduce((hash, char) => {
- hash = ((hash << 5) - hash) + char.charCodeAt(0);
- return hash & hash;
- }, 0).toString(36);
- }
-
- static getDetectionStats() {
- const now = Date.now();
- const recentDetections = this.#detectionHistory.filter(entry =>
- entry.timestamp > now - 60000
- );
-
- return {
- total: recentDetections.length,
- positive: recentDetections.filter(entry => entry.result).length,
- averageTime: recentDetections.reduce((acc, curr) =>
- acc + curr.timeDiff, 0) / recentDetections.length || 0
- };
- }
- }
-
- // Helper functions
- const BypassHelpers = {
- disableAntiDebugging: {
- patchTimingChecks() {
- const originalNow = Date.now;
- Date.now = function() {
- return originalNow.call(this) - Math.random() * 100;
- };
- },
-
- patchStackTraces() {
- Error.prepareStackTrace = (_, stack) =>
- stack.filter(frame => !frame.toString().includes('debugger'));
- },
-
- patchDebugChecks() {
- const noop = () => {};
- window.debug = noop;
- window.debugger = noop;
- window.isDebuggerEnabled = false;
- }
- },
-
- debugTools: {
- monitorAPICalls() {
- const originalFetch = window.fetch;
- window.fetch = async (...args) => {
- console.log('[API Call]', ...args);
- return originalFetch.apply(this, args);
- };
- },
-
- monitorDOMEvents() {
- new MutationObserver(mutations => {
- mutations.forEach(mutation => {
- console.log('[DOM Change]', mutation);
- });
- }).observe(document.body, {
- childList: true,
- subtree: true
- });
- }
- }
- };
-
- // Protection class
- class Protection {
- static applyAll() {
- this.#protectTimers();
- this.#protectTiming();
- this.#protectFunction();
- this.#protectStack();
- this.#protectEval();
- this.#protectConsole();
- this.#setupMutationObserver();
- this.#protectDevToolsKeys();
- this.#protectRightClick();
- this.#protectViewSource();
- this.#protectNetwork();
- this.#protectStorage();
- this.#protectClipboard();
- this.#protectPrinting();
- this.#protectWebWorkers();
- this.#enableDebuggingHelpers();
- }
-
- static #protectTimers() {
- const wrapTimer = original => {
- return function(handler, timeout, ...args) {
- if (typeof handler !== 'function') {
- return original.apply(this, arguments);
- }
-
- const wrappedHandler = function() {
- try {
- if (DebuggerDetector.isPresent()) return;
- return handler.apply(this, arguments);
- } catch (e) {
- if (e.message?.includes('debugger')) return;
- throw e;
- }
- };
-
- if (config.protection.obfuscateTimers) {
- timeout = Math.max(1, timeout + (Math.random() * 20 - 10));
- }
-
- return original.call(this, wrappedHandler, timeout, ...args);
- };
- };
-
- window.setTimeout = wrapTimer(OriginalFunctions.setTimeout);
- window.setInterval = wrapTimer(OriginalFunctions.setInterval);
- }
-
- static #protectTiming() {
- const timeOffset = Math.random() * 25;
- const safeNow = () => OriginalFunctions.now.call(Date) + timeOffset;
-
- Object.defineProperty(Date, 'now', {
- value: safeNow,
- configurable: false,
- writable: false
- });
-
- if (window.performance?.now) {
- Object.defineProperty(window.performance, 'now', {
- value: safeNow,
- configurable: false,
- writable: false
- });
- }
- }
-
- static #protectFunction() {
- const handler = {
- apply(target, thisArg, args) {
- if (typeof args[0] === 'string') {
- args[0] = Protection.#cleanCode(args[0]);
- }
- return Reflect.apply(target, thisArg, args);
- },
- construct(target, args) {
- if (typeof args[0] === 'string') {
- args[0] = Protection.#cleanCode(args[0]);
- }
- return Reflect.construct(target, args);
- }
- };
-
- window.Function = new Proxy(OriginalFunctions.Function, handler);
- if (typeof unsafeWindow !== 'undefined') {
- unsafeWindow.Function = window.Function;
- }
- }
-
- static #protectStack() {
- if (!config.protection.hideStackTraces) return;
-
- const errorHandler = {
- get(target, prop) {
- if (prop === 'stack') {
- return Protection.#cleanCode(target.stack);
- }
- return target[prop];
- }
- };
-
- const originalErrorPrototype = Error.prototype;
- const proxyErrorPrototype = Object.create(originalErrorPrototype);
-
- Object.defineProperty(proxyErrorPrototype, 'stack', {
- get() {
- return Protection.#cleanCode(new Error().stack);
- },
- configurable: true
- });
-
- try {
- Error.prototype = proxyErrorPrototype;
- } catch (e) {
- logger.error('Failed to protect stack traces:', e);
- }
- }
-
- static #protectEval() {
- const safeEval = function(code) {
- if (typeof code === 'string') {
- if (DebuggerDetector.isPresent()) return;
- return OriginalFunctions.eval.call(this, Protection.#cleanCode(code));
- }
- return OriginalFunctions.eval.apply(this, arguments);
- };
-
- Object.defineProperty(window, 'eval', {
- value: safeEval,
- configurable: false,
- writable: false
- });
-
- if (typeof unsafeWindow !== 'undefined') {
- unsafeWindow.eval = safeEval;
- }
- }
-
- static #protectConsole() {
- const consoleHandler = {
- get(target, prop) {
- if (!config.consoleProps.includes(prop)) return target[prop];
-
- return function(...args) {
- if (DebuggerDetector.isPresent()) return;
- return OriginalFunctions.console[prop]?.apply(console, args);
- };
- },
- set(target, prop, value) {
- if (config.consoleProps.includes(prop)) return true;
- target[prop] = value;
- return true;
- }
- };
-
- window.console = new Proxy(console, consoleHandler);
- }
-
- static #setupMutationObserver() {
- new MutationObserver(mutations => {
- mutations.forEach(mutation => {
- if (mutation.type === 'childList') {
- mutation.addedNodes.forEach(node => {
- if (node.tagName === 'SCRIPT') {
- const originalContent = node.textContent;
- const cleanedContent = Protection.#cleanCode(originalContent);
- if (originalContent !== cleanedContent) {
- node.textContent = cleanedContent;
- }
- }
- });
- }
- });
- }).observe(document, {
- childList: true,
- subtree: true
- });
- }
-
- static #protectDevToolsKeys() {
- if (!config.protection.preventDevToolsKeys) return;
-
- const handler = e => {
- const { keyCode, ctrlKey, shiftKey, altKey } = e;
- if (
- keyCode === 123 || // F12
- (ctrlKey && shiftKey && keyCode === 73) || // Ctrl+Shift+I
- (ctrlKey && shiftKey && keyCode === 74) || // Ctrl+Shift+J
- (ctrlKey && keyCode === 85) || // Ctrl+U
- (altKey && keyCode === 68) // Alt+D
- ) {
- e.preventDefault();
- e.stopPropagation();
- return false;
- }
- };
-
- window.addEventListener('keydown', handler, true);
- window.addEventListener('keyup', handler, true);
- window.addEventListener('keypress', handler, true);
- }
-
- static #protectRightClick() {
- if (!config.protection.preventRightClick) return;
-
- window.addEventListener('contextmenu', e => {
- e.preventDefault();
- e.stopPropagation();
- return false;
- }, true);
- }
-
- static #protectViewSource() {
- if (!config.protection.preventViewSource) return;
-
- const handler = e => {
- if (
- (e.ctrlKey && (e.key === 'u' || e.key === 's')) || // Ctrl+U, Ctrl+S
- (e.ctrlKey && e.shiftKey && e.key === 'i') || // Ctrl+Shift+I
- (e.ctrlKey && e.shiftKey && e.key === 'j') || // Ctrl+Shift+J
- (e.ctrlKey && e.shiftKey && e.key === 'c') || // Ctrl+Shift+C
- e.key === 'F12'
- ) {
- e.preventDefault();
- e.stopPropagation();
- return false;
- }
- };
-
- window.addEventListener('keydown', handler, true);
- document.addEventListener('keydown', handler, true);
-
- window.addEventListener('beforeunload', e => {
- if (window.location.protocol === 'view-source:') {
- e.preventDefault();
- return false;
- }
- });
- }
-
- static #protectNetwork() {
- window.fetch = async function(...args) {
- if (DebuggerDetector.isPresent()) {
- throw new Error('Network request blocked');
- }
- return OriginalFunctions.fetch.apply(this, args);
- };
-
- window.XMLHttpRequest = function() {
- const xhr = new OriginalFunctions.XMLHttpRequest();
- const originalOpen = xhr.open;
- xhr.open = function(...args) {
- if (DebuggerDetector.isPresent()) {
- throw new Error('Network request blocked');
- }
- return originalOpen.apply(xhr, args);
- };
- return xhr;
- };
- }
-
- static #protectStorage() {
- const storageHandler = {
- get(target, prop) {
- if (DebuggerDetector.isPresent()) return null;
- return target[prop];
- },
- set(target, prop, value) {
- if (DebuggerDetector.isPresent()) return true;
- target[prop] = value;
- return true;
- }
- };
-
- window.localStorage = new Proxy(window.localStorage, storageHandler);
- window.sessionStorage = new Proxy(window.sessionStorage, storageHandler);
- }
-
- static #protectClipboard() {
- if (!config.protection.preventCopy) return;
-
- document.addEventListener('copy', e => {
- e.preventDefault();
- }, true);
-
- document.addEventListener('cut', e => {
- e.preventDefault();
- }, true);
-
- if (config.protection.preventPaste) {
- document.addEventListener('paste', e => {
- e.preventDefault();
- }, true);
- }
- }
-
- static #protectPrinting() {
- if (!config.protection.preventPrint) return;
-
- window.addEventListener('beforeprint', e => {
- e.preventDefault();
- }, true);
-
- window.addEventListener('afterprint', e => {
- e.preventDefault();
- }, true);
- }
-
- static #protectWebWorkers() {
- window.Worker = function(scriptURL, options) {
- console.log('[Worker Created]', scriptURL);
- return new OriginalFunctions.Worker(scriptURL, options);
- };
- }
-
- static #enableDebuggingHelpers() {
- BypassHelpers.disableAntiDebugging.patchTimingChecks();
- BypassHelpers.disableAntiDebugging.patchStackTraces();
- BypassHelpers.debugTools.monitorAPICalls();
- BypassHelpers.debugTools.monitorDOMEvents();
- }
-
- static #cleanCode(code) {
- if (typeof code !== 'string') return code;
-
- let cleanCode = code
- .replace(/\/\/[#@]\s*source(?:Mapping)?URL\s*=.*$/gm, '')
- .replace(/(['"`])(?:(?!\1).)*?(?:debug|debugger|devtools?)(?:(?!\1).)*?\1/gi, match => `'${btoa(match)}'`)
- .replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '')
- .replace(/debugger|debug\s*\(|console\.[a-z]+/gi, '');
-
- Object.values(config.debugPatterns).forEach(pattern => {
- cleanCode = cleanCode.replace(pattern, '');
- });
-
- return cleanCode
- .replace(/function\s*\(/g, 'function /*debug*/(')
- .replace(/return\s+/g, 'return /*debug*/ ');
- }
- }
-
- // Main class
- class DevToolsBypass {
- static init() {
- try {
- Protection.applyAll();
- logger.info('DevTools Bypass initialized successfully');
- } catch (e) {
- logger.error('Failed to initialize DevTools Bypass:', e);
- }
- }
- }
-
- // Initialize
- DevToolsBypass.init();
- })();