DevTools Bypass

Bypass website anti-DevTools restrictions and enable full developer access

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

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

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

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

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

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         DevTools Bypass
// @name:vi      Bỏ Qua Chặn DevTools
// @name:zh-CN   开发工具限制绕过
// @name:en      DevTools Bypass
// @namespace    https://greasyfork.org/vi/users/1195312-renji-yuusei
// @version      4.0.0
// @description  Bypass website anti-DevTools restrictions and enable full developer access
// @description:vi Vô hiệu hóa các biện pháp chặn DevTools của website và cho phép truy cập đầy đủ
// @description:zh-CN 绕过网站的反开发者工具限制,启用完整的开发者访问权限
// @description:en Bypass website anti-DevTools restrictions and enable full developer access
// @author       Yuusei
// @match        *://*/*
// @grant        unsafeWindow
// @run-at       document-start
// @license      GPL-3.0-only
// ==/UserScript==

(() => {
  "use strict";

  // Configuration
  const CONFIG = {
    // Enhanced regex to detect and neutralize anti-DevTools code
    antiDevToolsRegex: new RegExp(
      [
        // Debugger statements - remove completely
        /(?:^|[;\s{(,])\s*debugger\s*(?:[;\s}),]|$)/.source,

        // Function constructor with debugger
        /(?:new\s+)?Function\s*\(\s*['"`][^'"`]*debugger[^'"`]*['"`]\s*\)/
          .source,

        // Timer-based debugger injections
        /(?:setTimeout|setInterval)\s*\(\s*(?:function[^{]*\{[^}]*debugger[^}]*\}|['"`][^'"`]*debugger[^'"`]*['"`])\s*[,)]/
          .source,

        // eval with debugger
        /eval\s*\(\s*['"`][^'"`]*debugger[^'"`]*['"`]\s*\)/.source,

        // Console detection tricks
        /console\s*\[\s*['"`](?:log|warn|error|info|debug|clear|table|dir|group|time)['"`]\s*\]\s*\.\s*toString/
          .source,
        /console\.(?:log|warn|error|info|debug|trace|clear|table|dir|group|time)\s*\.\s*toString\s*\(\s*\)/
          .source,

        // DevTools size detection
        /(?:window\.(?:outer|inner)(?:Width|Height)|screen\.(?:width|height))\s*[-+*\/]\s*(?:window\.(?:outer|inner)(?:Width|Height)|screen\.(?:width|height))\s*[<>=!]+\s*\d+/
          .source,

        // Performance timing detection
        /(?:performance\.now|Date\.now)\s*\(\s*\)\s*[-+]\s*(?:performance\.now|Date\.now)\s*\(\s*\)\s*[><=!]+\s*\d+/
          .source,

        // Known anti-DevTools libraries
        /(?:FuckDevTools|devtools-detector|disable-devtool|console-ban|anti-debug|devtools-detect|fuck-debugger)/
          .source,

        // DevTools event listeners
        /(?:addEventListener|on)\s*\(\s*['"`](?:keydown|keyup|keypress|contextmenu|selectstart|copy|cut|paste|dragstart)['"`][^)]*(?:F12|preventDefault|stopPropagation)/
          .source,

        // Console override attempts
        /console\s*=\s*(?:\{\}|null|undefined|false)/.source,
        /window\.console\s*=/.source,

        // DevTools detection via exceptions
        /try\s*\{[^}]*(?:debugger|console)[^}]*\}\s*catch/.source,

        // Stack trace analysis for DevTools detection
        /(?:Error|TypeError|ReferenceError)\(\)\.stack\.(?:split|match|replace|indexOf|includes|search)/
          .source,

        // Arguments.callee detection (used in some anti-debug)
        /arguments\.callee/.source,

        // toString override for detection
        /toString\s*=\s*function[^{]*\{[^}]*(?:devtools|debug|console)/.source,
      ].join("|"),
      "gim"
    ),

    protection: {
      neutralizeDebugger: true,
      enableDevToolsKeys: true,
      enableRightClick: true,
      enableTextSelection: true,
      enableCopyPaste: true,
      preventAntiDebugTimers: true,
      restoreConsole: true,
      preventKeyBlocking: true,
    },

    logging: {
      enabled: true,
      prefix: "[DevTools Bypass]",
      verbose: false,
    },
  };

  // Logger
  class Logger {
    static #logHistory = new Map();
    static #maxLogsPerType = 5;

    static #canLog(type, message) {
      const key = `${type}:${message}`;
      const count = this.#logHistory.get(key) || 0;
      if (count >= this.#maxLogsPerType) return false;

      this.#logHistory.set(key, count + 1);
      return true;
    }

    static info(message, ...args) {
      if (CONFIG.logging.enabled && this.#canLog("info", message)) {
        console.info(CONFIG.logging.prefix, message, ...args);
      }
    }

    static warn(message, ...args) {
      if (CONFIG.logging.enabled && this.#canLog("warn", message)) {
        console.warn(CONFIG.logging.prefix, message, ...args);
      }
    }

    static debug(message, ...args) {
      if (
        CONFIG.logging.enabled &&
        CONFIG.logging.verbose &&
        this.#canLog("debug", message)
      ) {
        console.debug(CONFIG.logging.prefix, message, ...args);
      }
    }
  }

  // Store original functions before they get overridden
  const ORIGINAL = {
    // Core functions
    Function: window.Function,
    eval: window.eval,
    setTimeout: window.setTimeout,
    setInterval: window.setInterval,
    clearTimeout: window.clearTimeout,
    clearInterval: window.clearInterval,

    // Timing
    Date: window.Date,
    now: Date.now,
    performance: window.performance?.now?.bind(window.performance),

    // DOM
    addEventListener: window.addEventListener,
    removeEventListener: window.removeEventListener,
    createElement: document.createElement,

    // Object methods
    defineProperty: Object.defineProperty,
    getOwnPropertyDescriptor: Object.getOwnPropertyDescriptor,
    keys: Object.keys,

    // Console (store before potential override)
    console: {},
  };

  // Backup console methods
  [
    "log",
    "warn",
    "error",
    "info",
    "debug",
    "trace",
    "dir",
    "table",
    "group",
    "groupEnd",
    "clear",
    "time",
    "timeEnd",
  ].forEach((method) => {
    if (console[method]) {
      ORIGINAL.console[method] = console[method].bind(console);
    }
  });

  // Code Neutralizer - Cleans anti-DevTools code
  class CodeNeutralizer {
    static neutralize(code) {
      if (typeof code !== "string" || !code.trim()) {
        return code;
      }

      try {
        let neutralized = code;

        // Replace anti-DevTools patterns
        neutralized = neutralized.replace(
          CONFIG.antiDevToolsRegex,
          (match, ...args) => {
            const replacement = this.#getReplacement(match);
            Logger.debug(
              "Neutralized anti-DevTools code:",
              match.substring(0, 100)
            );
            return replacement;
          }
        );

        // Handle encoded debugger statements
        neutralized = neutralized.replace(
          /\\u0064\\u0065\\u0062\\u0075\\u0067\\u0067\\u0065\\u0072/g,
          ""
        );
        neutralized = neutralized.replace(
          /\u0064\u0065\u0062\u0075\u0067\u0067\u0065\u0072/g,
          ""
        );

        // Remove obfuscated debugger
        neutralized = neutralized.replace(/['"`]debugger['"`]/g, '""');
        neutralized = neutralized.replace(/\bdebugger\b/g, "");

        // Neutralize console blocking
        neutralized = neutralized.replace(
          /console\s*=\s*(?:\{\}|null|undefined|false)/g,
          "console = console"
        );
        neutralized = neutralized.replace(/window\.console\s*=\s*[^;]+/g, "");

        return neutralized;
      } catch (e) {
        Logger.warn("Code neutralization failed:", e.message);
        return code;
      }
    }

    static #getReplacement(match) {
      if (match.includes("debugger")) {
        return "/* debugger statement removed */";
      }
      if (match.includes("console")) {
        return "/* console detection removed */";
      }
      if (match.includes("addEventListener") || match.includes("keydown")) {
        return "/* key blocking removed */";
      }
      if (match.includes("performance") || match.includes("Date.now")) {
        return "/* timing detection removed */";
      }
      return "/* anti-DevTools code removed */";
    }
  }

  // DevTools Protection Bypass
  class DevToolsProtectionBypass {
    static apply() {
      this.#neutralizeFunctionConstructor();
      this.#neutralizeEval();
      this.#neutralizeTimers();
      this.#preventKeyBlocking();
      this.#restoreRightClick();
      this.#restoreTextSelection();
      this.#restoreConsole();
      this.#preventTimingDetection();
      this.#neutralizeDebuggerTricks();
      this.#patchMutationObserver();
      this.#restoreClipboard();
      this.#preventErrorOverrides();
    }

    // Neutralize Function constructor to prevent debugger injection
    static #neutralizeFunctionConstructor() {
      const handler = {
        construct(target, args) {
          if (args[0] && typeof args[0] === "string") {
            args[0] = CodeNeutralizer.neutralize(args[0]);
          }
          return Reflect.construct(target, args);
        },
        apply(target, thisArg, args) {
          if (args[0] && typeof args[0] === "string") {
            args[0] = CodeNeutralizer.neutralize(args[0]);
          }
          return Reflect.apply(target, thisArg, args);
        },
      };

      try {
        window.Function = new Proxy(ORIGINAL.Function, handler);
        if (typeof unsafeWindow !== "undefined") {
          unsafeWindow.Function = window.Function;
        }
        Logger.info("Function constructor protected");
      } catch (e) {
        Logger.warn("Function protection failed:", e.message);
      }
    }

    // Neutralize eval to prevent debugger injection
    static #neutralizeEval() {
      const safeEval = function (code) {
        if (typeof code === "string") {
          code = CodeNeutralizer.neutralize(code);
        }
        return ORIGINAL.eval.call(this, code);
      };

      try {
        Object.defineProperty(window, "eval", {
          value: safeEval,
          writable: false,
          configurable: false,
        });

        if (typeof unsafeWindow !== "undefined") {
          unsafeWindow.eval = safeEval;
        }
        Logger.info("eval function protected");
      } catch (e) {
        Logger.warn("eval protection failed:", e.message);
      }
    }

    // Neutralize timers that might inject debugger
    static #neutralizeTimers() {
      const wrapTimer = (original, name) => {
        return function (handler, delay, ...args) {
          if (typeof handler === "string") {
            handler = CodeNeutralizer.neutralize(handler);
          }
          return original.call(this, handler, delay, ...args);
        };
      };

      window.setTimeout = wrapTimer(ORIGINAL.setTimeout, "setTimeout");
      window.setInterval = wrapTimer(ORIGINAL.setInterval, "setInterval");

      Logger.info("Timer functions protected");
    }

    // Prevent key blocking (F12, Ctrl+Shift+I, etc.)
    static #preventKeyBlocking() {
      const events = ["keydown", "keypress", "keyup"];

      events.forEach((eventType) => {
        // Override addEventListener to prevent key blocking
        const originalAddListener = ORIGINAL.addEventListener;
        document.addEventListener = function (type, listener, options) {
          if (type === eventType && typeof listener === "function") {
            const originalListener = listener;
            listener = function (event) {
              const key = event.key?.toLowerCase();
              const code = event.code?.toLowerCase();

              // Allow DevTools keys
              const isDevToolsKey =
                key === "f12" ||
                (event.ctrlKey &&
                  event.shiftKey &&
                  ["i", "j", "c"].includes(key)) ||
                (event.ctrlKey && key === "u");

              if (isDevToolsKey) {
                Logger.debug("Allowing DevTools key:", key);
                return; // Don't call the original listener
              }

              return originalListener.call(this, event);
            };
          }
          return originalAddListener.call(this, type, listener, options);
        };

        // Also handle window events
        window.addEventListener = document.addEventListener;
      });

      // Block existing key event listeners by overriding preventDefault
      const originalPreventDefault = Event.prototype.preventDefault;
      Event.prototype.preventDefault = function () {
        const key = this.key?.toLowerCase();
        const isDevToolsKey =
          key === "f12" ||
          (this.ctrlKey && this.shiftKey && ["i", "j", "c"].includes(key)) ||
          (this.ctrlKey && key === "u");

        if (
          isDevToolsKey &&
          (this.type === "keydown" ||
            this.type === "keypress" ||
            this.type === "keyup")
        ) {
          Logger.debug("Prevented preventDefault on DevTools key:", key);
          return; // Don't prevent default for DevTools keys
        }

        return originalPreventDefault.call(this);
      };

      Logger.info("Key blocking prevention enabled");
    }

    // Restore right-click context menu
    static #restoreRightClick() {
      // Override contextmenu event blocking
      const originalAddListener = document.addEventListener;
      document.addEventListener = function (type, listener, options) {
        if (type === "contextmenu") {
          // Replace with a dummy function that doesn't block
          listener = function (e) {
            Logger.debug("Context menu allowed");
            return true;
          };
        }
        return originalAddListener.call(this, type, listener, options);
      };

      // Also handle oncontextmenu attribute
      const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
          if (
            mutation.type === "attributes" &&
            mutation.attributeName === "oncontextmenu"
          ) {
            mutation.target.removeAttribute("oncontextmenu");
            Logger.debug("Removed oncontextmenu attribute");
          }
        });
      });

      observer.observe(document.documentElement, {
        attributes: true,
        subtree: true,
        attributeFilter: ["oncontextmenu"],
      });

      Logger.info("Right-click restored");
    }

    // Restore text selection
    static #restoreTextSelection() {
      // Override selectstart event blocking
      const originalAddListener = document.addEventListener;
      const blockedEvents = ["selectstart", "dragstart", "copy", "cut"];

      document.addEventListener = function (type, listener, options) {
        if (blockedEvents.includes(type)) {
          listener = function (e) {
            Logger.debug("Selection/copy event allowed:", type);
            return true;
          };
        }
        return originalAddListener.call(this, type, listener, options);
      };

      // Remove CSS that prevents text selection
      const style = document.createElement("style");
      style.textContent = `
                *, *::before, *::after {
                    -webkit-user-select: text !important;
                    -moz-user-select: text !important;
                    -ms-user-select: text !important;
                    user-select: text !important;
                }
            `;
      document.head.appendChild(style);

      Logger.info("Text selection restored");
    }

    // Restore console if it was overridden
    static #restoreConsole() {
      try {
        // Check if console was disabled/overridden
        if (!window.console || typeof window.console.log !== "function") {
          window.console = ORIGINAL.console;
          Logger.info("Console restored");
        }

        // Ensure console methods are working
        Object.keys(ORIGINAL.console).forEach((method) => {
          if (!console[method] || typeof console[method] !== "function") {
            console[method] = ORIGINAL.console[method];
          }
        });

        // Prevent future console overrides
        Object.defineProperty(window, "console", {
          value: window.console,
          writable: false,
          configurable: false,
        });
      } catch (e) {
        Logger.warn("Console restoration failed:", e.message);
      }
    }

    // Prevent timing-based DevTools detection
    static #preventTimingDetection() {
      // Add small random delays to timing functions to break detection
      const addNoise = () => Math.random() * 2;

      try {
        Object.defineProperty(Date, "now", {
          value: () => ORIGINAL.now() + addNoise(),
          writable: false,
          configurable: false,
        });

        if (window.performance?.now) {
          Object.defineProperty(window.performance, "now", {
            value: () => ORIGINAL.performance() + addNoise(),
            writable: false,
            configurable: false,
          });
        }

        Logger.info("Timing detection prevented");
      } catch (e) {
        Logger.warn("Timing protection failed:", e.message);
      }
    }

    // Neutralize debugger tricks
    static #neutralizeDebuggerTricks() {
      // Override toString methods that might be used for detection
      const safeToString = function () {
        return this.name
          ? `function ${this.name}() { [native code] }`
          : "function() { [native code] }";
      };

      try {
        // Protect critical functions from toString inspection
        window.Function.prototype.toString = safeToString;
        window.eval.toString = () => "function eval() { [native code] }";

        Logger.info("Debugger tricks neutralized");
      } catch (e) {
        Logger.warn("Debugger trick neutralization failed:", e.message);
      }
    }

    // Monitor and clean injected scripts
    static #patchMutationObserver() {
      if (!window.MutationObserver) return;

      try {
        new MutationObserver((mutations) => {
          mutations.forEach((mutation) => {
            mutation.addedNodes.forEach((node) => {
              if (node.nodeType === Node.ELEMENT_NODE) {
                // Clean script content
                if (node.tagName === "SCRIPT" && node.textContent) {
                  const originalContent = node.textContent;
                  const cleanedContent =
                    CodeNeutralizer.neutralize(originalContent);

                  if (originalContent !== cleanedContent) {
                    node.textContent = cleanedContent;
                    Logger.debug("Cleaned injected script");
                  }
                }

                // Clean event attributes
                if (node.attributes) {
                  Array.from(node.attributes).forEach((attr) => {
                    if (
                      attr.name.startsWith("on") ||
                      attr.name === "oncontextmenu"
                    ) {
                      const cleaned = CodeNeutralizer.neutralize(attr.value);
                      if (
                        cleaned !== attr.value ||
                        attr.name === "oncontextmenu"
                      ) {
                        node.removeAttribute(attr.name);
                        Logger.debug(
                          "Removed/cleaned event attribute:",
                          attr.name
                        );
                      }
                    }
                  });
                }
              }
            });
          });
        }).observe(document.documentElement, {
          childList: true,
          subtree: true,
          attributes: true,
          attributeFilter: [
            "onload",
            "onerror",
            "onclick",
            "oncontextmenu",
            "onkeydown",
            "onkeyup",
          ],
        });

        Logger.info("DOM monitoring active");
      } catch (e) {
        Logger.warn("DOM monitoring failed:", e.message);
      }
    }

    // Restore clipboard functionality
    static #restoreClipboard() {
      const clipboardEvents = ["copy", "cut", "paste"];

      clipboardEvents.forEach((eventType) => {
        document.addEventListener(
          eventType,
          (e) => {
            // Ensure clipboard events are not blocked
            e.stopImmediatePropagation();
          },
          true
        );
      });

      Logger.info("Clipboard functionality restored");
    }

    // Prevent error handling overrides that might block DevTools
    static #preventErrorOverrides() {
      const originalErrorHandler = window.onerror;

      window.addEventListener(
        "error",
        (e) => {
          // Don't let websites block error reporting
          e.stopImmediatePropagation();
        },
        true
      );

      // Prevent overriding of error handlers
      Object.defineProperty(window, "onerror", {
        set: function (handler) {
          Logger.debug("Prevented error handler override");
        },
        get: function () {
          return originalErrorHandler;
        },
      });

      Logger.info("Error override prevention active");
    }
  }

  // Main bypass controller
  class DevToolsBypass {
    static init() {
      try {
        Logger.info("Starting DevTools protection bypass...");

        // Apply all bypasses
        DevToolsProtectionBypass.apply();

        // Clean existing page content
        this.#cleanExistingContent();

        Logger.info("DevTools bypass activated successfully");

        // Show success indicator
        this.#showSuccessIndicator();
      } catch (e) {
        Logger.warn("Bypass initialization failed:", e.message);
      }
    }

    static #cleanExistingContent() {
      try {
        // Clean all existing script tags
        const scripts = document.querySelectorAll("script");
        scripts.forEach((script) => {
          if (script.textContent) {
            const cleaned = CodeNeutralizer.neutralize(script.textContent);
            if (cleaned !== script.textContent) {
              script.textContent = cleaned;
              Logger.debug("Cleaned existing script");
            }
          }
        });

        // Remove problematic event attributes
        const elementsWithEvents = document.querySelectorAll(
          "[oncontextmenu], [onkeydown], [onkeyup], [onselectstart], [ondragstart]"
        );
        elementsWithEvents.forEach((element) => {
          [
            "oncontextmenu",
            "onkeydown",
            "onkeyup",
            "onselectstart",
            "ondragstart",
          ].forEach((attr) => {
            if (element.hasAttribute(attr)) {
              element.removeAttribute(attr);
              Logger.debug("Removed event attribute:", attr);
            }
          });
        });
      } catch (e) {
        Logger.warn("Content cleaning failed:", e.message);
      }
    }

    static #showSuccessIndicator() {
      if (!CONFIG.logging.enabled) return;

      // Create a temporary success indicator
      const indicator = document.createElement("div");
      indicator.style.cssText = `
                position: fixed;
                top: 20px;
                right: 20px;
                background: #4CAF50;
                color: white;
                padding: 10px 20px;
                border-radius: 5px;
                z-index: 999999;
                font-family: Arial, sans-serif;
                font-size: 14px;
                box-shadow: 0 2px 10px rgba(0,0,0,0.3);
            `;
      indicator.textContent = "✓ DevTools Bypass Active";

      document.body?.appendChild(indicator);

      // Remove after 3 seconds
      setTimeout(() => {
        indicator.remove();
      }, 3000);
    }
  }

  // Initialize immediately and on various events
  DevToolsBypass.init();

  // Also initialize when DOM is ready (fallback)
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", DevToolsBypass.init);
  }

  // Initialize on window load (another fallback)
  window.addEventListener("load", DevToolsBypass.init);
})();