绕过开发者工具限制

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

目前为 2024-10-31 提交的版本。查看 最新版本

// ==UserScript==
// @name         DevTools Bypass
// @name:vi      Bỏ Qua Chặn DevTools 
// @name:zh-CN   绕过开发者工具限制
// @namespace    https://greasyfork.org/vi/users/1195312-renji-yuusei
// @version      2.2
// @description  Bypass website restrictions on DevTools and debugging capabilities with enhanced protection and performance
// @description:vi Bỏ qua các hạn chế của trang web về DevTools và khả năng gỡ lỗi với bảo vệ và hiệu suất nâng cao
// @description:zh-CN 绕过网站对开发工具和调试功能的限制,具有增强的保护和性能
// @author       Yuusei
// @match        *://*/*
// @grant        unsafeWindow
// @run-at       document-start
// @license      GPL-3.0-only
// ==/UserScript==

(function () {
	'use strict';

	const config = {
		debugKeywords: /;\s*(?:debugger|debug(?:ger)?|breakpoint)\s*;?/g,
		consoleProps: ['log', 'warn', 'error', 'info', 'debug', 'assert', 'dir', 'dirxml', 'trace', 'group', 'groupCollapsed', 'groupEnd', 'time', 'timeEnd', 'profile', 'profileEnd', 'count', 'table', 'clear'],
		maxLogHistory: 100,
		whitelist: /^(?:example\.com|another-site\.net)$/,
		cutoffs: {
			table: { amount: 5, within: 5000 },
			clear: { amount: 5, within: 5000 },
			redactedLog: { amount: 5, within: 5000 },
			debugger: { amount: 10, within: 10000 },
			debuggerThrow: { amount: 10, within: 10000 },
		},
	};

	// Save original methods
	const originals = {
		console: {},
		Function: window.Function.prototype.constructor,
		createElement: document.createElement.bind(document),
		toString: Function.prototype.toString,
		eval: unsafeWindow.eval,
		functionConstructor: window.Function,
		setInterval: window.setInterval,
		addEventListener: window.addEventListener,
	};

	// Save original console methods safely
	config.consoleProps.forEach(prop => {
		try {
			if (console[prop]) {
				originals.console[prop] = console[prop].bind(console);
			}
		} catch (e) {
			// Ignore if we can't access the property
		}
	});

	const logHistory = [];
	let debugCount = 0;

	// Logging control system with error handling
	const shouldLog = type => {
		try {
			const cutoff = config.cutoffs[type];
			if (!cutoff) return true;
			if (cutoff.tripped) return false;

			cutoff.current = cutoff.current || 0;
			const now = Date.now();
			cutoff.last = cutoff.last || now;

			if (now - cutoff.last > cutoff.within) {
				cutoff.current = 0;
			}

			cutoff.last = now;
			cutoff.current++;

			if (cutoff.current > cutoff.amount) {
				originals.console.warn?.(`Limit reached! Will now ignore ${type}`);
				cutoff.tripped = true;
				return false;
			}

			return true;
		} catch (e) {
			return true; // Default to allowing logs on error
		}
	};

	// Enhanced safe evaluation with better error handling
	const safeEval = code => {
		try {
			const wrapped = `(function() { ${code} })()`;
			return Function(wrapped)();
		} catch (error) {
			originals.console.error?.('Failed to evaluate code:', error);
			return null;
		}
	};

	// Advanced function modification with improved safety
	const modifyFunction = func => {
		if (typeof func !== 'function') return func;

		try {
			const funcStr = func.toString();
			if (config.debugKeywords.test(funcStr)) {
				const modifiedStr = funcStr.replace(config.debugKeywords, ';/* debugger removed */;');
				return safeEval(modifiedStr) || func;
			}
		} catch (e) {
			// If modification fails, return original function
		}
		return func;
	};

	// Enhanced console wrapper with proper prototype handling
	const wrapConsole = () => {
		const wrappedConsole = {};

		config.consoleProps.forEach(prop => {
			try {
				Object.defineProperty(wrappedConsole, prop, {
					configurable: true,
					enumerable: true,
					writable: true,
					value: function (...args) {
						if (!shouldLog(prop)) return;

						// Special cases handling
						if (prop === 'clear' && shouldLog('clear')) {
							originals.console.warn?.('Clear prevented');
							return;
						}

						// Process arguments safely
						const processedArgs = args.map(arg => {
							try {
								if (typeof arg === 'function') return '[Function]';
								if (!arg || typeof arg !== 'object') return arg;

								// Check for potential anti-debug objects
								if (Object.getOwnPropertyDescriptor(arg, 'toString')) {
									return '[Object]';
								}

								return arg;
							} catch (e) {
								return '[Protected]';
							}
						});

						// Apply the original console method if available
						if (originals.console[prop]) {
							originals.console[prop].apply(console, processedArgs);
						}
					},
				});
			} catch (e) {
				// Skip if property cannot be wrapped
			}
		});

		// Safely replace console methods
		try {
			Object.defineProperty(window, 'console', {
				configurable: true,
				enumerable: true,
				get: () => wrappedConsole,
			});
		} catch (e) {
			// Fallback: try to copy methods individually
			config.consoleProps.forEach(prop => {
				try {
					console[prop] = wrappedConsole[prop];
				} catch (_) {}
			});
		}
	};

	// Function constructor protection with improved error handling
	const protectFunctionConstructor = () => {
		try {
			const handler = {
				apply(target, thisArg, args) {
					const modifiedArgs = args.map(arg => (typeof arg === 'string' ? arg.replace(config.debugKeywords, '') : arg));
					return Reflect.apply(target, thisArg, modifiedArgs);
				},
				construct(target, args) {
					const modifiedArgs = args.map(arg => (typeof arg === 'string' ? arg.replace(config.debugKeywords, '') : arg));
					return Reflect.construct(target, modifiedArgs);
				},
			};

			window.Function = new Proxy(window.Function, handler);
		} catch (e) {
			// Fallback protection if Proxy fails
			const originalFunction = window.Function;
			window.Function = function (...args) {
				const modifiedArgs = args.map(arg => (typeof arg === 'string' ? arg.replace(config.debugKeywords, '') : arg));
				return originalFunction.apply(this, modifiedArgs);
			};
			Object.setPrototypeOf(window.Function, originalFunction);
		}
	};

	// Enhanced createElement protection
	const protectCreateElement = () => {
		try {
			document.createElement = new Proxy(originals.createElement, {
				apply(target, thisArg, args) {
					const element = Reflect.apply(target, thisArg, args);
					if (args[0]?.toLowerCase?.() === 'iframe') {
						element.addEventListener('load', () => {
							try {
								const iframeConsole = element.contentWindow.console;
								Object.keys(wrappedConsole).forEach(key => {
									try {
										iframeConsole[key] = wrappedConsole[key];
									} catch (_) {}
								});
							} catch (_) {}
						});
					}
					return element;
				},
			});
		} catch (e) {
			// Fallback if Proxy fails
		}
	};

	// Main protection setup with improved error handling
	const setupProtection = () => {
		try {
			if (config.whitelist.test(window.location.host)) return;

			wrapConsole();
			protectFunctionConstructor();
			protectCreateElement();

			// Protect video playback
			try {
				const originalPlay = HTMLMediaElement.prototype.play;
				Object.defineProperty(HTMLMediaElement.prototype, 'play', {
					configurable: true,
					writable: true,
					value: function (...args) {
						return originalPlay.apply(this, args);
					},
				});
			} catch (_) {}

			// Initialize protection message
			console.log('%cDevTools Bypass is active', 'color: #00ff00; font-weight: bold;');
		} catch (e) {
			// Silent fail for maximum stealth
		}
	};

	// Initialize protection
	setupProtection();
})();