ZeroAd: CrazyGames

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

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==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);
    }

})();