Greasy Fork

Greasy Fork is available in English.

开发工具限制绕过

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

当前为 2024-11-10 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴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   开发工具限制绕过
// @namespace    http://greasyfork.icu/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();
})();