ZeroAd: Poki

Instant, zero-delay Poki SDK bypass with bulletproof hook

2026-08-21 기준 버전입니다. 최신 버전을 확인하세요.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

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

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         ZeroAd: Poki
// @namespace    https://greasyfork.org/en/users/1483567-vujohn123
// @version      4.0.4
// @description  Instant, zero-delay Poki SDK bypass with bulletproof hook
// @author       ZeroAd Team
// @match        *://*.poki.com/*
// @match        *://poki.com/*
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    if (window.__zaPokiLoaded) return;
    window.__zaPokiLoaded = true;

    const CONFIG = { DEBUG: true };  // Set false to disable logs
    const METRICS = {
        hooksInstalled: 0,
        interceptedCalls: 0,
        failedHooks: 0,
        rewardsGranted: 0
    };

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

    // --- Hook functions (same as before) ---
    function safeDispatchEvent(target, eventName) {
        try { target.dispatchEvent(new CustomEvent(eventName, { bubbles: true })); } catch (e) {}
    }
    function safeCallback(fn, ...args) {
        if (typeof fn === 'function') {
            try { fn(...args); } catch (e) { warn('Callback error:', e); }
        }
    }

    function hookPokiSDK(sdk) {
        if (!sdk || sdk.__zaHooked) return false;
        log('Hooking PokiSDK...');

        try {
            sdk.__zaHooked = true;

            // commercialBreak
            if (typeof sdk.commercialBreak === 'function') {
                sdk.commercialBreak = function(...args) {
                    log('🚫 commercialBreak skipped');
                    METRICS.interceptedCalls++;
                    if (args.length && typeof args[0] === 'function') try { args[0](); } catch(e) {}
                    return Promise.resolve();
                };
                log('✅ commercialBreak hooked');
            }

            // rewardedBreak
            if (typeof sdk.rewardedBreak === 'function') {
                sdk.rewardedBreak = function(callbacks) {
                    log('🎁 rewardedBreak → instant reward');
                    METRICS.interceptedCalls++;
                    let onStart = null, onReward = null, onError = null;
                    if (typeof callbacks === 'function') {
                        onReward = callbacks;
                    } else if (callbacks && typeof callbacks === 'object') {
                        onStart = callbacks.onStart || callbacks.start;
                        onReward = callbacks.adFinished || callbacks.onComplete || callbacks.onReward || callbacks.complete;
                        onError = callbacks.onError || callbacks.error;
                    }
                    safeCallback(onStart);
                    safeCallback(onReward);
                    safeCallback(onError, null);
                    METRICS.rewardsGranted++;
                    safeDispatchEvent(window, 'rewardedComplete');
                    safeDispatchEvent(window, 'rewardGranted');
                    safeDispatchEvent(window, 'adComplete');
                    log('✅ Reward granted instantly');
                    return Promise.resolve(true);
                };
                log('✅ rewardedBreak hooked');
            }

            // display ads
            if (typeof sdk.hoistDisplayAd === 'function') {
                sdk.hoistDisplayAd = () => { METRICS.interceptedCalls++; return false; };
            }
            if (typeof sdk.destroyDisplayAd === 'function') {
                sdk.destroyDisplayAd = () => { METRICS.interceptedCalls++; };
            }
            if (typeof sdk.displayAd === 'function') {
                sdk.displayAd = (e, t, o, i) => {
                    METRICS.interceptedCalls++;
                    if (i) safeCallback(i, true);
                    if (o) safeCallback(o);
                    return false;
                };
            }
            if (typeof sdk.destroyAd === 'function') {
                sdk.destroyAd = () => { METRICS.interceptedCalls++; };
            }

            // playground/platform breaks
            ['playgroundCommercialBreak', 'platformCommercialBreak'].forEach(m => {
                if (typeof sdk[m] === 'function') {
                    sdk[m] = () => { log(m + ' skipped'); METRICS.interceptedCalls++; return Promise.resolve(); };
                }
            });

            // monetization internals
            if (sdk.__monetization) {
                if (typeof sdk.__monetization.requestAd === 'function') sdk.__monetization.requestAd = () => Promise.resolve();
                if (typeof sdk.__monetization.displayAd === 'function') sdk.__monetization.displayAd = () => false;
                if (typeof sdk.__monetization.init === 'function') sdk.__monetization.init = () => Promise.resolve();
            }

            // no-op tracking
            ['happyTime','gameLoading','gameplayStart','gameplayStop','captureError','sendEvent','track','setDebug','measure','gameLoadingFinished','gameLoadingProgress','gameInteractive','logError','muteAd','roundEnd','roundStart','sendHighscore','setLogging','setPlayerAge','enableEventTracking','openExternalLink'].forEach(m => {
                if (typeof sdk[m] === 'function') {
                    sdk[m] = (...args) => {
                        if (m === 'gameplayStart' || m === 'gameplayStop') log(m + ' tracked (no-op)');
                        else log(m + ' no-op');
                    };
                }
            });

            METRICS.hooksInstalled++;
            log('✅ PokiSDK hooked successfully!');
            return true;
        } catch (e) {
            error('Hook failed:', e);
            METRICS.failedHooks++;
            return false;
        }
    }

    // --- BULLETPROOF TRAP: non-configurable property descriptor ---
    function installBulletproofTrap() {
        let _pokiSDK = window.PokiSDK;

        // If the SDK already exists, hook it and use it as the stored value.
        if (_pokiSDK && !_pokiSDK.__zaHooked) {
            hookPokiSDK(_pokiSDK);
        }

        // Define a non-configurable property that can't be overwritten.
        Object.defineProperty(window, 'PokiSDK', {
            configurable: false,   // Prevents any redefinition
            enumerable: true,
            get: function() {
                log('PokiSDK GET');
                return _pokiSDK;
            },
            set: function(newValue) {
                log('PokiSDK SET (new SDK)');
                _pokiSDK = newValue;
                if (newValue && !newValue.__zaHooked) {
                    hookPokiSDK(newValue);
                }
            }
        });

        log('✅ Bulletproof trap installed (non-configurable)');
    }

    // --- Fallback observers (just in case) ---
    function setupObserver() {
        const observer = new MutationObserver(mutations => {
            for (const mutation of mutations) {
                for (const node of mutation.addedNodes) {
                    if (node.tagName === 'SCRIPT') {
                        const src = (node.src || '').toLowerCase();
                        if (src.includes('poki') && (src.includes('sdk') || src.includes('hoist') || src.includes('playground') || src.includes('v2'))) {
                            log('SDK script detected:', src.substring(0, 80));
                            if (node.readyState === 'complete' || node.readyState === 'loaded') {
                                setTimeout(() => {
                                    if (window.PokiSDK && !window.PokiSDK.__zaHooked) {
                                        hookPokiSDK(window.PokiSDK);
                                    }
                                }, 0);
                            } else {
                                node.addEventListener('load', () => {
                                    setTimeout(() => {
                                        if (window.PokiSDK && !window.PokiSDK.__zaHooked) {
                                            hookPokiSDK(window.PokiSDK);
                                        }
                                    }, 0);
                                });
                            }
                        }
                    }
                }
            }
        });
        if (document.documentElement) {
            observer.observe(document.documentElement, { childList: true, subtree: true });
        }
        log('✅ MutationObserver active');
    }

    function startRetry() {
        let attempts = 0;
        const maxAttempts = 100;
        const interval = setInterval(() => {
            attempts++;
            if (window.PokiSDK && !window.PokiSDK.__zaHooked) {
                log('Retry attempt ' + attempts + ' - hooking SDK');
                hookPokiSDK(window.PokiSDK);
            }
            if (attempts >= maxAttempts || (window.PokiSDK && window.PokiSDK.__zaHooked)) {
                clearInterval(interval);
                if (window.PokiSDK && window.PokiSDK.__zaHooked) {
                    log('✅ SDK hooked via retry');
                } else {
                    warn('⚠️ SDK not found after retries');
                }
            }
        }, 50);
    }

    // --- Global reference cleanup (scans for cached SDK references) ---
    function scanAndReplaceCachedReferences() {
        // This is a sledgehammer approach: look at all properties of `window`
        // and if any of them point to the original SDK object, replace them with our hooked version.
        // We only do this once, after the SDK is known to be hooked.
        setTimeout(() => {
            if (!window.PokiSDK || !window.PokiSDK.__zaHooked) return;
            const hooked = window.PokiSDK;
            // We need a way to detect the original object. We'll check if a property has the same methods as the hooked one, but it's tricky.
            // Instead, we can look for properties that are objects and have a `rewardedBreak` function that is not our hooked one.
            for (let key in window) {
                try {
                    const val = window[key];
                    if (val && typeof val === 'object' && val !== hooked && typeof val.rewardedBreak === 'function' && val !== window.PokiSDK) {
                        // Check if it's the original by seeing if its `rewardedBreak` is the same as the original?
                        // We can't easily compare, but we can check if it has `__zaHooked` flag – if not, it's likely the original.
                        if (!val.__zaHooked) {
                            log('Found cached reference: window.' + key + ' – replacing with hooked version');
                            try {
                                window[key] = hooked;
                            } catch(e) {}
                        }
                    }
                } catch(e) {}
            }
        }, 1000);
    }

    // --- Initialization ---
    function initialize() {
        log('🚀 ZeroAd: Poki SDK v4.0.4 – Bulletproof');
        installBulletproofTrap();
        setupObserver();
        startRetry();
        scanAndReplaceCachedReferences();

        window._zaMetrics = window._zaMetrics || {};
        window._zaMetrics.poki = METRICS;

        setTimeout(() => {
            log('📊 Status:', {
                hookState: !!(window.PokiSDK && window.PokiSDK.__zaHooked),
                metrics: METRICS
            });
        }, 5000);
    }

    initialize();

    // Additional safety: on DOMContentLoaded, re-scan and hook if not yet.
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => {
            if (window.PokiSDK && !window.PokiSDK.__zaHooked) {
                hookPokiSDK(window.PokiSDK);
            }
            scanAndReplaceCachedReferences();
        });
    }
})();