DevTools Anti-Detector

Ultimate protection against all DevTools detection

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         DevTools Anti-Detector
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Ultimate protection against all DevTools detection
// @author       Kaypi
// @match        *://*/*
// @license MIT2
// @grant        unsafeWindow
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    const win = unsafeWindow || window;

    // ========== CONFIGURATION ==========
    const CONFIG = {
        blockDebugger: true,
        blockConsoleClear: true,
        blockTimingDetection: true,
        logBlocked: false, // Set true to see blocked actions
        refreshInterval: 50 // How often to re-enforce protections
    };

    const log = CONFIG.logBlocked
        ? (...args) => console.log('%c[Anti-Detector]', 'color: #4CAF50; font-weight: bold;', ...args)
        : () => {};

    // ========== 1. ULTIMATE CONSOLE.CLEAR BLOCK ==========
    (function blockConsoleClear() {
        if (!CONFIG.blockConsoleClear) return;

        const noop = function() {
            log('console.clear() blocked');
            return undefined;
        };

        // Method 1: Direct override
        try {
            win.console.clear = noop;
            Object.defineProperty(win.console, 'clear', {
                value: noop,
                writable: false,
                configurable: false,
                enumerable: true
            });
        } catch(e) {}

        // Method 2: Proxy the entire console object
        try {
            const originalConsole = win.console;
            const consoleProxy = new Proxy(originalConsole, {
                get(target, prop) {
                    if (prop === 'clear') return noop;
                    const value = target[prop];
                    return typeof value === 'function' ? value.bind(target) : value;
                },
                set(target, prop, value) {
                    if (prop === 'clear') return true;
                    target[prop] = value;
                    return true;
                }
            });

            Object.defineProperty(win, 'console', {
                get: () => consoleProxy,
                set: () => true,
                configurable: false
            });
        } catch(e) {}

        // Method 3: Continuously re-enforce (for JSVMP that keeps overwriting)
        const enforceConsoleClear = () => {
            try {
                if (win.console.clear !== noop &&
                    win.console.clear.toString().indexOf('undefined') === -1) {
                    win.console.clear = noop;
                }
            } catch(e) {}
        };

        setInterval(enforceConsoleClear, CONFIG.refreshInterval);
    })();

    // ========== 2. ULTIMATE DEBUGGER BLOCK ==========
    (function blockDebugger() {
        if (!CONFIG.blockDebugger) return;

        // Helper to clean debugger from code
        const cleanDebugger = (code) => {
            if (typeof code !== 'string') return code;
            return code
                .replace(/\bdebugger\b\s*;?/gi, '/* dbg removed */;')
                .replace(/["']debugger["']/gi, '""');
        };

        // Method 1: Override Function constructor
        try {
            const OriginalFunction = win.Function;
            const NewFunction = function(...args) {
                if (args.length > 0) {
                    const lastIndex = args.length - 1;
                    if (typeof args[lastIndex] === 'string') {
                        const original = args[lastIndex];
                        args[lastIndex] = cleanDebugger(original);
                        if (original !== args[lastIndex]) {
                            log('Debugger removed from Function constructor');
                        }
                    }
                }
                return OriginalFunction.apply(this, args);
            };
            NewFunction.prototype = OriginalFunction.prototype;
            NewFunction.prototype.constructor = NewFunction;
            Object.defineProperty(NewFunction, 'name', { value: 'Function' });
            NewFunction.toString = () => 'function Function() { [native code] }';
            win.Function = NewFunction;
        } catch(e) {}

        // Method 2: Override eval
        try {
            const originalEval = win.eval;
            win.eval = function(code) {
                if (typeof code === 'string') {
                    const cleaned = cleanDebugger(code);
                    if (code !== cleaned) log('Debugger removed from eval');
                    code = cleaned;
                }
                return originalEval.call(win, code);
            };
            win.eval.toString = () => 'function eval() { [native code] }';
        } catch(e) {}

        // Method 3: Override setInterval for debugger loops
        try {
            const originalSetInterval = win.setInterval;
            win.setInterval = function(fn, delay, ...args) {
                // Block very fast intervals (debugger loops)
                if (delay !== undefined && delay < 10) {
                    delay = 100;
                }

                if (typeof fn === 'function') {
                    const fnStr = fn.toString();
                    // Block tiny functions that just contain debugger
                    if (fnStr.includes('debugger') && fnStr.length < 100) {
                        log('Blocked debugger setInterval');
                        return originalSetInterval.call(win, () => {}, 999999);
                    }
                }

                if (typeof fn === 'string' && fn.includes('debugger')) {
                    log('Blocked debugger string setInterval');
                    return originalSetInterval.call(win, () => {}, 999999);
                }

                return originalSetInterval.call(win, fn, delay, ...args);
            };
        } catch(e) {}

        // Method 4: Override setTimeout
        try {
            const originalSetTimeout = win.setTimeout;
            win.setTimeout = function(fn, delay, ...args) {
                if (typeof fn === 'function') {
                    const fnStr = fn.toString();
                    if (fnStr.includes('debugger') && fnStr.length < 100) {
                        log('Blocked debugger setTimeout');
                        return 0;
                    }
                }

                if (typeof fn === 'string' && fn.includes('debugger')) {
                    log('Blocked debugger string setTimeout');
                    return 0;
                }

                return originalSetTimeout.call(win, fn, delay, ...args);
            };
        } catch(e) {}

        // Method 5: Nullify debugger via Error.prototype
        try {
            // Some JSVMP uses Error to detect debugger timing
            const OriginalError = win.Error;
            win.Error = function(...args) {
                const err = new OriginalError(...args);
                // Clean stack trace
                if (err.stack) {
                    Object.defineProperty(err, 'stack', {
                        get() {
                            return '';
                        },
                        set() {},
                        configurable: true
                    });
                }
                return err;
            };
            win.Error.prototype = OriginalError.prototype;
            win.Error.captureStackTrace = OriginalError.captureStackTrace;
        } catch(e) {}

    })();

    // ========== 3. WORKER MESSAGE INTERCEPTION ==========
    (function blockWorkerDetection() {
        try {
            const OriginalWorker = win.Worker;

            win.Worker = function(scriptURL, options) {
                const worker = new OriginalWorker(scriptURL, options);

                // Intercept postMessage to worker
                const originalPostMessage = worker.postMessage.bind(worker);
                worker.postMessage = function(message, transfer) {
                    // Block console clear/detection commands
                    if (message && typeof message === 'object') {
                        if (message.type === 'clear' ||
                            message.action === 'clear' ||
                            (message.type && message.type.includes && message.type.includes('clear'))) {
                            log('Blocked Worker console.clear command');
                            return;
                        }
                    }
                    return originalPostMessage(message, transfer);
                };

                // Intercept messages from worker
                const originalAddEventListener = worker.addEventListener.bind(worker);
                worker.addEventListener = function(type, listener, options) {
                    if (type === 'message') {
                        const wrappedListener = function(event) {
                            // Modify timing results to hide debugger
                            if (event.data && event.data.time !== undefined) {
                                if (event.data.time > 100) {
                                    event.data.time = Math.random() * 10;
                                }
                            }
                            return listener.call(this, event);
                        };
                        return originalAddEventListener(type, wrappedListener, options);
                    }
                    return originalAddEventListener(type, listener, options);
                };

                // Also wrap onmessage
                let _onmessage = null;
                Object.defineProperty(worker, 'onmessage', {
                    get: () => _onmessage,
                    set: (fn) => {
                        _onmessage = function(event) {
                            if (event.data && event.data.time !== undefined) {
                                if (event.data.time > 100) {
                                    event.data.time = Math.random() * 10;
                                }
                            }
                            return fn.call(this, event);
                        };
                    }
                });

                return worker;
            };
            win.Worker.prototype = OriginalWorker.prototype;
        } catch(e) {}
    })();

    // ========== 4. TIMING PROTECTION ==========
    (function blockTimingDetection() {
        if (!CONFIG.blockTimingDetection) return;

        try {
            const originalNow = performance.now.bind(performance);
            let lastReal = originalNow();
            let virtual = lastReal;

            performance.now = function() {
                const real = originalNow();
                const delta = real - lastReal;

                // Cap delta to hide debugger pauses
                const maxDelta = 16; // ~60fps
                virtual += Math.min(delta, maxDelta);
                lastReal = real;

                return virtual;
            };
        } catch(e) {}

        try {
            const originalDateNow = Date.now;
            let lastDateNow = originalDateNow();
            let virtualDate = lastDateNow;

            Date.now = function() {
                const real = originalDateNow();
                const delta = real - lastDateNow;

                virtualDate += Math.min(delta, 50);
                lastDateNow = real;

                return virtualDate;
            };
        } catch(e) {}
    })();

    // ========== 5. DATE.TOSTRING PROTECTION ==========
    (function blockDateToString() {
        try {
            const originalToString = Date.prototype.toString;
            let callCount = 0;

            Date.prototype.toString = function() {
                // Don't increment counter - breaks detection
                return originalToString.call(this);
            };

            // Make it look native
            Date.prototype.toString.toString = () => 'function toString() { [native code] }';
        } catch(e) {}
    })();

    // ========== 6. REGEXP.TOSTRING PROTECTION ==========
    (function blockRegExpToString() {
        try {
            const original = RegExp.prototype.toString;
            Object.defineProperty(RegExp.prototype, 'toString', {
                value: original,
                writable: false,
                configurable: false
            });
        } catch(e) {}
    })();

    // ========== 7. WINDOW SIZE PROTECTION ==========
    (function blockWindowSizeDetection() {
        try {
            Object.defineProperty(win, 'outerWidth', {
                get: () => win.innerWidth,
                configurable: true
            });
            Object.defineProperty(win, 'outerHeight', {
                get: () => win.innerHeight + 80,
                configurable: true
            });
        } catch(e) {}
    })();

    // ========== 8. DEVTOOLS DETECTOR LIBRARY BLOCK ==========
    (function blockDetectorLibraries() {
        const fakeDetector = {
            launch: () => {},
            stop: () => {},
            addListener: () => {},
            removeListener: () => {},
            isLaunch: () => false,
            setDetectDelay: () => {},
            isOpen: () => false,
            isEnable: () => false
        };

        const detectorNames = [
            'devtoolsDetector',
            '__DEVTOOLS_DETECTOR__',
            'DevtoolsDetector',
            'devToolsDetector'
        ];

        detectorNames.forEach(name => {
            try {
                Object.defineProperty(win, name, {
                    get: () => fakeDetector,
                    set: () => true,
                    configurable: false
                });
            } catch(e) {}
        });
    })();

    // ========== 9. JSVMP SPECIFIC BYPASS ==========
    (function bypassJSVMP() {
        // Block cbb_jsvmp debugger checks
        try {
            // These are common JSVMP global variables
            const jsvmpVars = ['cbb_jsvmp', 'cshduei', 'changlc', 'offnew', 'cltothis'];

            jsvmpVars.forEach(name => {
                if (win[name] !== undefined) {
                    const original = win[name];
                    if (typeof original === 'function') {
                        win[name] = function(...args) {
                            // Remove debugger-related returns
                            const result = original.apply(this, args);
                            if (result === "-90_cbb") {
                                return undefined;
                            }
                            return result;
                        };
                    }
                }
            });
        } catch(e) {}

        // Monitor for JSVMP initialization
        const observer = new MutationObserver((mutations) => {
            if (win.cbb_jsvmp && !win.cbb_jsvmp._patched) {
                try {
                    const original = win.cbb_jsvmp;
                    win.cbb_jsvmp = function(...args) {
                        const result = original.apply(this, args);
                        if (result === "-90_cbb") return undefined;
                        return result;
                    };
                    win.cbb_jsvmp._patched = true;
                    log('Patched cbb_jsvmp');
                } catch(e) {}
            }
        });

        if (document.body) {
            observer.observe(document.body, { childList: true, subtree: true });
        } else {
            document.addEventListener('DOMContentLoaded', () => {
                observer.observe(document.body, { childList: true, subtree: true });
            });
        }
    })();

    // ========== 10. IFRAME PROTECTION ==========
    (function protectIframes() {
        try {
            const originalContentWindow = Object.getOwnPropertyDescriptor(
                HTMLIFrameElement.prototype, 'contentWindow'
            );

            if (originalContentWindow && originalContentWindow.get) {
                const originalGet = originalContentWindow.get;

                Object.defineProperty(HTMLIFrameElement.prototype, 'contentWindow', {
                    get: function() {
                        const cw = originalGet.call(this);
                        if (cw) {
                            // Apply protections to iframe window
                            try {
                                if (cw.console && cw.console.clear) {
                                    cw.console.clear = () => {};
                                }
                            } catch(e) {} // Cross-origin will fail
                        }
                        return cw;
                    },
                    configurable: true
                });
            }
        } catch(e) {}
    })();

    // ========== 11. BLOB URL PROTECTION ==========
    (function protectBlobURLs() {
        try {
            const originalCreateObjectURL = URL.createObjectURL.bind(URL);

            URL.createObjectURL = function(blob) {
                // Can't easily modify blob content, but we can track it
                const url = originalCreateObjectURL(blob);
                log('Blob URL created:', url);
                return url;
            };
        } catch(e) {}
    })();

    // ========== 12. CONTINUOUS ENFORCEMENT ==========
    (function continuousEnforcement() {
        const enforce = () => {
            // Re-block console.clear
            try {
                const noop = () => undefined;
                if (win.console && win.console.clear &&
                    win.console.clear.toString().indexOf('undefined') === -1) {
                    win.console.clear = noop;
                }
            } catch(e) {}

            // Check for detector libraries
            try {
                if (win.devtoolsDetector && win.devtoolsDetector.isLaunch) {
                    if (win.devtoolsDetector.isLaunch()) {
                        win.devtoolsDetector.stop();
                    }
                }
            } catch(e) {}
        };

        // Run frequently
        setInterval(enforce, CONFIG.refreshInterval);

        // Also run on various events
        ['load', 'DOMContentLoaded', 'readystatechange'].forEach(event => {
            document.addEventListener(event, enforce);
        });
    })();

    // ========== 13. CHROME DEVTOOLS API PROTECTION ==========
    (function blockChromeAPIs() {
        try {
            Object.defineProperty(win, 'devtoolsFormatters', {
                get: () => undefined,
                set: () => true,
                configurable: false
            });
        } catch(e) {}

        try {
            Object.defineProperty(win, 'Firebug', {
                get: () => undefined,
                set: () => true,
                configurable: false
            });
        } catch(e) {}
    })();

    // ========== STARTUP ==========
    console.log(
        '%c[DevTools Anti-Detector v4.0] Ultimate Protection Active\n' +
        '%c✓ console.clear() - BLOCKED\n' +
        '✓ debugger statements - BLOCKED\n' +
        '✓ Worker detection - BLOCKED\n' +
        '✓ Timing detection - BYPASSED\n' +
        '✓ Continuous enforcement - ENABLED',
        'color: #4CAF50; font-size: 14px; font-weight: bold;',
        'color: #8BC34A; font-size: 11px;'
    );

})();