Bỏ Qua Chặn DevTools Nâng Cao

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

Tính đến 31-10-2024. Xem phiên bản mới nhất.

// ==UserScript==
// @name         DevTools Bypass
// @name:vi      Bỏ Qua Chặn DevTools Nâng Cao
// @name:zh-CN   增强型开发工具限制绕过
// @namespace    https://greasyfork.org/vi/users/1195312-renji-yuusei
// @version      2.1
// @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();
})();