ZeroAd: CrazyGames

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 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);
    }

})();