ZeroAd: CrazyGames

Ad bypass with deep hooks, stateful ad simulation & race condition handling

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         ZeroAd: CrazyGames
// @namespace    https://greasyfork.org/users/YOUR_USER_ID
// @version      4.1.0
// @description  Ad bypass with deep hooks, stateful ad simulation & race condition handling
// @author       ZeroAd Team
// @match        *://*.crazygames.com/*
// @match        *://crazygames.com/*
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Prevent double execution
    if (window.__zeroAdInstalled) return;
    window.__zeroAdInstalled = true;

    // ═══════════════════════════════════════════════════════════════
    // CONFIGURATION
    // ═══════════════════════════════════════════════════════════════
    const CONFIG = {
        DEBUG: true,
        REWARD_DELAY_MS: 10,
        MAX_HOOK_ATTEMPTS: 100,
        HOOK_RETRY_INTERVAL_MS: 200,
        MUTATION_OBSERVER_ENABLED: true,
        AD_PLAYING_DURATION_MS: 5   // how long isAdPlaying stays true (ms)
    };

    const log = (...args) => CONFIG.DEBUG && console.log('[ZeroAd]', ...args);
    const warn = (...args) => CONFIG.DEBUG && console.warn('[ZeroAd]', ...args);

    const hookState = {
        crazyGamesSDK: false,
        constructSDK: false,
        crazygamesAds: false,
        interceptedCalls: 0
    };

    // ═══════════════════════════════════════════════════════════════
    // FAKE AD MODULE (stateful isAdPlaying)
    // ═══════════════════════════════════════════════════════════════
    function createFakeAdModule() {
        let _adPlaying = false;
        let _playingTimer = null;

        // Dispatch common reward events
        function dispatchRewardEvents() {
            const events = [
                'rewardedComplete', 'rewardGranted', 'adComplete',
                'crazy_ad_finished', 'adReward', 'adFinished'
            ];
            events.forEach(ev => {
                try { window.dispatchEvent(new CustomEvent(ev)); } catch (e) {}
            });
        }

        const module = {
            get isAdPlaying() {
                log(`isAdPlaying checked → ${_adPlaying}`);
                return _adPlaying;
            },
            get requestInProgress() {
                log('requestInProgress checked → false');
                return false;
            },
            get hasAdblock() {
                log('hasAdblock checked → false');
                return false;
            },

            async prefetchAd(type) {
                hookState.interceptedCalls++;
                log(`✓ INTERCEPTED: prefetchAd("${type}")`);
                return Promise.resolve();
            },

            async requestAd(type, callbacks = {}) {
                hookState.interceptedCalls++;
                log(`✓ INTERCEPTED: requestAd("${type}")`);

                // Set ad playing state
                _adPlaying = true;
                if (_playingTimer) clearTimeout(_playingTimer);
                _playingTimer = setTimeout(() => { _adPlaying = false; }, CONFIG.AD_PLAYING_DURATION_MS);

                // adStarted callback
                if (typeof callbacks.adStarted === 'function') {
                    try {
                        callbacks.adStarted();
                        log('  → adStarted() called');
                    } catch(e) {
                        warn('adStarted error:', e);
                    }
                }

                // Resolve after reward delay
                return new Promise(resolve => {
                    setTimeout(() => {
                        _adPlaying = false;
                        if (_playingTimer) {
                            clearTimeout(_playingTimer);
                            _playingTimer = null;
                        }

                        if (typeof callbacks.adFinished === 'function') {
                            try {
                                callbacks.adFinished();
                                log('  → adFinished() called');
                            } catch(e) {
                                warn('adFinished error:', e);
                            }
                        }

                        dispatchRewardEvents();
                        log(`  → ✅ Reward granted for "${type}"`);
                        resolve();
                    }, CONFIG.REWARD_DELAY_MS);
                });
            },

            async hasAdblockEnabled() {
                hookState.interceptedCalls++;
                log('✓ INTERCEPTED: hasAdblockEnabled() → false');
                return false;
            },

            addAdblockPopupListener() { log('addAdblockPopupListener (stub)'); },
            removeAdblockPopupListener() { log('removeAdblockPopupListener (stub)'); }
        };

        return module;
    }

    // ═══════════════════════════════════════════════════════════════
    // HOOK: CrazyGames.SDK.ad
    // ═══════════════════════════════════════════════════════════════
    function hookCrazyGamesSDK() {
        if (hookState.crazyGamesSDK) return true;

        try {
            if (window.CrazyGames?.SDK) {
                const fakeAd = createFakeAdModule();
                Object.defineProperty(window.CrazyGames.SDK, 'ad', {
                    configurable: true,
                    enumerable: true,
                    get: () => {
                        log('SDK.ad accessed (getter)');
                        return fakeAd;
                    }
                });
                hookState.crazyGamesSDK = true;
                log('✓✓ CrazyGames.SDK.ad HOOKED (existing)');
                return true;
            }

            let _crazyGames = window.CrazyGames;
            Object.defineProperty(window, 'CrazyGames', {
                configurable: true,
                enumerable: true,
                get() { return _crazyGames; },
                set(newValue) {
                    log('CrazyGames object assigned');
                    _crazyGames = newValue;
                    if (newValue?.SDK && !hookState.crazyGamesSDK) {
                        const fakeAd = createFakeAdModule();
                        Object.defineProperty(newValue.SDK, 'ad', {
                            configurable: true,
                            enumerable: true,
                            get: () => fakeAd
                        });
                        hookState.crazyGamesSDK = true;
                        log('✓✓ CrazyGames.SDK.ad HOOKED (deferred)');
                    }
                }
            });
            log('✓ CrazyGames trap installed');
            return false;
        } catch (error) {
            warn('Failed to hook CrazyGames.SDK:', error);
            return false;
        }
    }

    // ═══════════════════════════════════════════════════════════════
    // HOOK: ConstructCrazySDK.ad
    // ═══════════════════════════════════════════════════════════════
    function hookConstructSDK() {
        if (hookState.constructSDK) return true;

        try {
            if (window.ConstructCrazySDK) {
                const fakeAd = createFakeAdModule();
                Object.defineProperty(window.ConstructCrazySDK, 'ad', {
                    configurable: true,
                    enumerable: true,
                    get: () => fakeAd
                });
                hookState.constructSDK = true;
                log('✓✓ ConstructCrazySDK.ad HOOKED (existing)');
                return true;
            }

            let _construct = window.ConstructCrazySDK;
            Object.defineProperty(window, 'ConstructCrazySDK', {
                configurable: true,
                enumerable: true,
                get() { return _construct; },
                set(newValue) {
                    log('ConstructCrazySDK object assigned');
                    _construct = newValue;
                    if (newValue && !hookState.constructSDK) {
                        const fakeAd = createFakeAdModule();
                        Object.defineProperty(newValue, 'ad', {
                            configurable: true,
                            enumerable: true,
                            get: () => fakeAd
                        });
                        hookState.constructSDK = true;
                        log('✓✓ ConstructCrazySDK.ad HOOKED (deferred)');
                    }
                }
            });
            log('✓ ConstructCrazySDK trap installed');
            return false;
        } catch (error) {
            warn('Failed to hook ConstructCrazySDK:', error);
            return false;
        }
    }

    // ═══════════════════════════════════════════════════════════════
    // HOOK: CrazygamesAds (Proxy with improved adblock matching)
    // ═══════════════════════════════════════════════════════════════
    function hookCrazygamesAds() {
        if (hookState.crazygamesAds) return true;

        const AD_METHODS = [
            'requestAd', 'requestAds', 'showAd', 'showRewardedAd',
            'displayAd', 'displayRewardedAd', 'displayMidrollAd',
            'requestRewardedAd', 'showRewardedVideo', 'requestRewardedVideo',
            'showInterstitial', 'requestOnly', 'render', 'preloadAd'
        ];

        function isAdMethod(prop) {
            return AD_METHODS.includes(prop);
        }

        function isAdblockMethod(prop) {
            // case-insensitive match for variations
            const lower = prop.toLowerCase();
            return lower === 'hasadblock' || lower === 'hasadblockenabled' || lower === 'isadblockactive';
        }

        function createAdsProxy(target) {
            if (!target || target.__zaProxied) return target;

            const handler = {
                get(obj, prop) {
                    const original = obj[prop];

                    if (isAdMethod(prop) && typeof original === 'function') {
                        return function(...args) {
                            hookState.interceptedCalls++;
                            log(`✓ INTERCEPTED: CrazygamesAds.${prop}()`);

                            let onStarted = null;
                            let onFinished = null;

                            for (const arg of args) {
                                if (arg && typeof arg === 'object') {
                                    onStarted = arg.adStarted || arg.onAdStarted || arg.onStart;
                                    onFinished = arg.adFinished || arg.onAdFinished || arg.onComplete || arg.onReward;
                                }
                            }

                            if (typeof onStarted === 'function') {
                                try { onStarted(); } catch(e) { warn('onStarted error:', e); }
                            }

                            if (prop === 'requestOnly' || prop === 'preloadAd') {
                                return Promise.resolve({ success: true });
                            }

                            return new Promise(resolve => {
                                setTimeout(() => {
                                    if (typeof onFinished === 'function') {
                                        try { onFinished(); } catch(e) { warn('onFinished error:', e); }
                                    }
                                    // Dispatch events
                                    const events = [
                                        'rewardedComplete', 'adComplete', 'crazy_ad_finished'
                                    ];
                                    events.forEach(ev => {
                                        try { window.dispatchEvent(new CustomEvent(ev)); } catch(e) {}
                                    });
                                    resolve({ success: true, completed: true });
                                }, CONFIG.REWARD_DELAY_MS);
                            });
                        };
                    }

                    if (isAdblockMethod(prop) && typeof original === 'function') {
                        return async () => {
                            log(`✓ INTERCEPTED: CrazygamesAds.${prop}() → false`);
                            return false;
                        };
                    }

                    return original;
                }
            };

            const proxied = new Proxy(target, handler);
            proxied.__zaProxied = true;
            return proxied;
        }

        try {
            if (window.CrazygamesAds) {
                window.CrazygamesAds = createAdsProxy(window.CrazygamesAds);
                hookState.crazygamesAds = true;
                log('✓✓ CrazygamesAds HOOKED (existing)');
                return true;
            }

            let _ads = window.CrazygamesAds;
            Object.defineProperty(window, 'CrazygamesAds', {
                configurable: true,
                enumerable: true,
                get() { return _ads; },
                set(newValue) {
                    log('CrazygamesAds object assigned');
                    _ads = newValue ? createAdsProxy(newValue) : newValue;
                    if (_ads && !hookState.crazygamesAds) {
                        hookState.crazygamesAds = true;
                        log('✓✓ CrazygamesAds HOOKED (deferred)');
                    }
                }
            });
            log('✓ CrazygamesAds trap installed');
            return false;
        } catch (error) {
            warn('Failed to hook CrazygamesAds:', error);
            return false;
        }
    }

    // ═══════════════════════════════════════════════════════════════
    // ORCHESTRATION & RETRY LOGIC
    // ═══════════════════════════════════════════════════════════════
    let hookAttempts = 0;
    let retryTimer = null;
    let observer = null;

    function allHooksInstalled() {
        return hookState.crazyGamesSDK && hookState.constructSDK && hookState.crazygamesAds;
    }

    function attemptHooks() {
        hookAttempts++;
        hookCrazyGamesSDK();
        hookConstructSDK();
        hookCrazygamesAds();

        if (allHooksInstalled()) {
            log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
            log('✅ ALL HOOKS INSTALLED SUCCESSFULLY');
            log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
            cleanup();
            return true;
        }

        if (hookAttempts >= CONFIG.MAX_HOOK_ATTEMPTS) {
            warn('⚠️  Hook installation incomplete after max attempts');
            warn('Hooked:', hookState);
            cleanup();
            return false;
        }

        return false;
    }

    function cleanup() {
        if (retryTimer) {
            clearInterval(retryTimer);
            retryTimer = null;
        }
        if (observer) {
            observer.disconnect();
            observer = null;
            log('✓ MutationObserver disconnected');
        }
    }

    // ═══════════════════════════════════════════════════════════════
    // MUTATION OBSERVER: Watch for SDK script injection
    // ═══════════════════════════════════════════════════════════════
    function setupMutationObserver() {
        if (!CONFIG.MUTATION_OBSERVER_ENABLED) return;

        observer = new MutationObserver((mutations) => {
            for (const mutation of mutations) {
                for (const node of mutation.addedNodes) {
                    if (node.tagName === 'SCRIPT') {
                        const src = node.src || '';
                        if (src.includes('crazygames') || src.includes('sdk')) {
                            log(`Script detected: ${src.substring(0, 80)}...`);
                            node.addEventListener('load', () => {
                                log('SDK script loaded, re-attempting hooks');
                                setTimeout(attemptHooks, 50);
                            });
                        }
                    }
                }
            }
        });

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

        log('✓ MutationObserver watching for SDK scripts');
    }

    // ═══════════════════════════════════════════════════════════════
    // INITIALIZATION
    // ═══════════════════════════════════════════════════════════════
    function initialize() {
        log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
        log('ZeroAd v4.1.0 - Fixed & Enhanced');
        log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');

        attemptHooks();
        setupMutationObserver();

        retryTimer = setInterval(() => {
            if (!allHooksInstalled() && hookAttempts < CONFIG.MAX_HOOK_ATTEMPTS) {
                attemptHooks();
                log(`Hook attempt ${hookAttempts}/${CONFIG.MAX_HOOK_ATTEMPTS}`);
            } else {
                cleanup();
            }
        }, CONFIG.HOOK_RETRY_INTERVAL_MS);

        setTimeout(() => {
            log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
            log('Status Report:');
            log('  Hooks installed:', hookState);
            log('  Intercepted calls:', hookState.interceptedCalls);
            log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
        }, 5000);
    }

    // Run immediately
    initialize();

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', attemptHooks);
    }

})();