Greasy Fork

Greasy Fork is available in English.

开发工具限制绕过

绕过网站对开发工具的限制,具有增强的保护功能

当前为 2024-12-23 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         DevTools Bypass
// @name:vi      Bỏ Qua Chặn DevTools
// @name:zh-CN   开发工具限制绕过
// @name:ru      Разблокировка DevTools
// @namespace    http://greasyfork.icu/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();
})();