DevTools Bypass

Bypass for website restrictions on DevTools with improved protection

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name         DevTools Bypass
// @name:vi      Bỏ Qua Chặn DevTools
// @name:zh-CN   开发工具限制绕过
// @namespace    https://greasyfork.org/vi/users/1195312-renji-yuusei
// @version      3.0
// @description  Bypass for website restrictions on DevTools with improved protection
// @description:vi Bỏ qua các hạn chế của trang web về DevTools với bảo vệ được cải tiến
// @description:zh-CN 绕过网站对开发工具的限制,具有增强的保护功能
// @author       Yuusei
// @match        *://*/*
// @grant        unsafeWindow
// @run-at       document-start
// @license      GPL-3.0-only
// ==/UserScript==

(function() {
    'use strict';

    // Add initialization logging
    console.log('[DevTools Bypass] Script initialized at:', new Date().toISOString());

    const config = {
        debugPatterns: {
            basic: /;\s*(?:debugger|debug(?:ger)?|breakpoint)\s*;?/g,
            advanced: /(?:debugger|debug(?:ger)?|breakpoint)[\s;]*(?:\{[\s\S]*?\})?/g,
            timing: /performance\.now\(\)|Date\.now\(\)/g,
            eval: /eval\(.*?debugger.*?\)/g
        },
        consoleProps: ['log', 'warn', 'error', 'info', 'debug', 'trace'],
        cutoffs: {
            debugger: { amount: 50, within: 60000 },
            debuggerThrow: { amount: 50, within: 60000 }
        },
        bypassTriggers: {
            timeThreshold: 100,
            stackDepth: 50,
            recursionLimit: 100
        },
        logging: {
            enabled: false,
            prefix: '[DevTools Bypass]',
            levels: ['info', 'warn', 'error']
        }
    };

    // Enhanced logging utility
    const logger = {
        info: (...args) => {
            if (config.logging.enabled) {
                console.log(config.logging.prefix, '(INFO)', ...args);
            }
        },
        warn: (...args) => {
            if (config.logging.enabled) {
                console.warn(config.logging.prefix, '(WARN)', ...args);
            }
        },
        error: (...args) => {
            if (config.logging.enabled) {
                console.error(config.logging.prefix, '(ERROR)', ...args);
            }
        }
    };

    const originals = {
        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
    };

    config.consoleProps.forEach(prop => {
        if (console[prop]) {
            originals.console[prop] = console[prop].bind(console);
        }
    });

    const isDebuggerPresent = () => {
        try {
            const startTime = originals.now.call(Date);
            const testFunc = new Function('debugger;')();
            const timeDiff = originals.now.call(Date) - startTime;
            if (timeDiff > config.bypassTriggers.timeThreshold) {
                logger.warn('Debugger detected! Time difference:', timeDiff, 'ms');
                return true;
            }
            return false;
        } catch (e) {
            logger.error('Error in debugger detection:', e);
            return false;
        }
    };

    const analyzeStack = () => {
        try {
            const stack = new Error().stack;
            const frames = stack.split('\n');
            const analysis = {
                depth: frames.length,
                hasDebugKeywords: frames.some(frame => 
                    Object.values(config.debugPatterns).some(pattern => 
                        pattern.test(frame)
                    )
                ),
                isRecursive: new Set(frames).size < frames.length
            };

            if (analysis.hasDebugKeywords || analysis.isRecursive) {
                logger.warn('Suspicious stack detected:', analysis);
            }

            return analysis;
        } catch (e) {
            logger.error('Error analyzing stack:', e);
            return { depth: 0, hasDebugKeywords: false, isRecursive: false };
        }
    };

    const enhancedAntiDebugger = () => {
        try {
            let protectionCount = 0;

            const createSafeTimer = (original) => {
                return function(handler, timeout, ...args) {
                    if (typeof handler === 'function') {
                        const wrappedHandler = function() {
                            try {
                                return handler.apply(this, arguments);
                            } catch (e) {
                                if (e.message?.includes('debugger')) {
                                    logger.info('Caught and bypassed debugger in timer');
                                    return undefined;
                                }
                                throw e;
                            }
                        };
                        return original.call(this, wrappedHandler, timeout, ...args);
                    }
                    return original.apply(this, arguments);
                };
            };

            const protectTiming = () => {
                const timeOffset = Math.random() * 10;
                const safeNow = function() {
                    return originals.now.call(Date) + timeOffset;
                };

                try {
                    Object.defineProperty(Date, 'now', {
                        value: safeNow,
                        configurable: true,
                        writable: true
                    });

                    if (window.performance && window.performance.now) {
                        Object.defineProperty(window.performance, 'now', {
                            value: safeNow,
                            configurable: true,
                            writable: true
                        });
                    }
                    protectionCount++;
                    logger.info('Timing protection applied with offset:', timeOffset);
                } catch (e) {
                    logger.error('Failed to protect timing:', e);
                }
            };

            const protectFunction = () => {
                const handler = {
                    apply(target, thisArg, args) {
                        const code = args[0];
                        if (typeof code === 'string') {
                            let cleanCode = code;
                            let detectedPatterns = [];
                            Object.entries(config.debugPatterns).forEach(([key, pattern]) => {
                                if (pattern.test(code)) {
                                    detectedPatterns.push(key);
                                }
                                cleanCode = cleanCode.replace(pattern, '');
                            });
                            
                            if (detectedPatterns.length > 0) {
                                logger.warn('Cleaned debug patterns from Function:', detectedPatterns);
                            }
                            
                            args[0] = cleanCode;
                        }
                        return Reflect.apply(target, thisArg, args);
                    },
                    construct(target, args) {
                        const code = args[0];
                        if (typeof code === 'string') {
                            let cleanCode = code;
                            Object.values(config.debugPatterns).forEach(pattern => {
                                cleanCode = cleanCode.replace(pattern, '');
                            });
                            args[0] = cleanCode;
                        }
                        return Reflect.construct(target, args);
                    }
                };

                window.Function = new Proxy(originals.Function, handler);
                if (typeof unsafeWindow !== 'undefined') {
                    unsafeWindow.Function = window.Function;
                }
                protectionCount++;
                logger.info('Function protection applied');
            };

            const protectStack = () => {
                try {
                    const errorHandler = {
                        get(target, prop) {
                            if (prop === 'stack') {
                                const stack = target.stack;
                                const cleanedStack = stack.split('\n')
                                    .filter(line => !Object.values(config.debugPatterns)
                                        .some(pattern => pattern.test(line)))
                                    .join('\n');
                                
                                if (cleanedStack.length !== stack.length) {
                                    logger.info('Cleaned suspicious stack trace');
                                }
                                
                                return cleanedStack;
                            }
                            return target[prop];
                        }
                    };

                    const errorProtoHandler = {
                        get(target, prop) {
                            if (prop === 'stack') {
                                const error = new Error();
                                return new Proxy(error, errorHandler).stack;
                            }
                            return Reflect.get(target, prop);
                        }
                    };

                    Error.prototype = new Proxy(Error.prototype, errorProtoHandler);
                    protectionCount++;
                    logger.info('Stack protection applied');
                } catch (e) {
                    logger.error('Failed to protect stack:', e);
                }
            };

            const protectEval = () => {
                const safeEval = function(code) {
                    if (typeof code === 'string') {
                        let cleanCode = code;
                        let detectedPatterns = [];
                        Object.entries(config.debugPatterns).forEach(([key, pattern]) => {
                            if (pattern.test(code)) {
                                detectedPatterns.push(key);
                            }
                            cleanCode = cleanCode.replace(pattern, '');
                        });
                        
                        if (detectedPatterns.length > 0) {
                            logger.warn('Cleaned debug patterns from eval:', detectedPatterns);
                        }
                        
                        return originals.eval.call(this, cleanCode);
                    }
                    return originals.eval.apply(this, arguments);
                };

                try {
                    Object.defineProperty(window, 'eval', {
                        value: safeEval,
                        configurable: true,
                        writable: true
                    });
                    if (typeof unsafeWindow !== 'undefined') {
                        unsafeWindow.eval = safeEval;
                    }
                    protectionCount++;
                    logger.info('Eval protection applied');
                } catch (e) {
                    logger.error('Failed to protect eval:', e);
                }
            };

            const protectConsole = () => {
                const handler = {
                    get(target, prop) {
                        if (config.consoleProps.includes(prop)) {
                            return function(...args) {
                                if (!isDebuggerPresent()) {
                                    return originals.console[prop]?.apply(console, args);
                                }
                                logger.warn('Console method blocked due to debugger presence:', prop);
                                return undefined;
                            };
                        }
                        return target[prop];
                    },
                    set(target, prop, value) {
                        if (config.consoleProps.includes(prop)) {
                            logger.warn('Attempted to modify console method:', prop);
                            return true;
                        }
                        target[prop] = value;
                        return true;
                    }
                };

                window.console = new Proxy(console, handler);
                protectionCount++;
                logger.info('Console protection applied');
            };

            // Apply all protections
            window.setTimeout = createSafeTimer(originals.setTimeout);
            window.setInterval = createSafeTimer(originals.setInterval);
            protectTiming();
            protectFunction();
            protectStack();
            protectEval();
            protectConsole();

            // Enhanced MutationObserver with logging
            const observer = new MutationObserver((mutations) => {
                for (const mutation of mutations) {
                    if (mutation.type === 'childList') {
                        mutation.addedNodes.forEach((node) => {
                            if (node.tagName === 'SCRIPT') {
                                const content = node.textContent;
                                let detectedPatterns = [];
                                
                                Object.entries(config.debugPatterns).forEach(([key, pattern]) => {
                                    if (pattern.test(content)) {
                                        detectedPatterns.push(key);
                                    }
                                });

                                if (detectedPatterns.length > 0) {
                                    logger.warn('Cleaned debug patterns from dynamic script:', detectedPatterns);
                                    node.textContent = content.replace(
                                        new RegExp(Object.values(config.debugPatterns)
                                            .map(p => p.source).join('|'), 'g'),
                                        ''
                                    );
                                }
                            }
                        });
                    }
                }
            });

            observer.observe(document, {
                childList: true,
                subtree: true
            });

            logger.info('All protections applied successfully. Total protections:', protectionCount);

        } catch (e) {
            logger.error('Critical error in enhancedAntiDebugger:', e);
        }
    };

    const init = () => {
        try {
            logger.info('Initializing DevTools bypass...');
            enhancedAntiDebugger();
            logger.info('DevTools bypass initialized successfully');
        } catch (e) {
            logger.error('Failed to initialize DevTools bypass:', e);
        }
    };

    // Add status check function
    window._checkDevToolsBypassStatus = () => {
        try {
            const status = {
                initialized: true,
                debuggerPresent: isDebuggerPresent(),
                stackAnalysis: analyzeStack(),
                timestamp: new Date().toISOString()
            };
            logger.info('Status check:', status);
            return status;
        } catch (e) {
            logger.error('Error checking status:', e);
            return { error: e.message };
        }
    };

    init();
})();