BlockAdBlock Publicidad Ingeniería inversa antibloqueo

Si usa bloqueadores de anuncios, puede encontrar BlockAdBlock . Este script detecta su bloqueador y no lo permite en el sitio hasta que lo desactive. Pero me preguntaba cómo funciona. ¿Cómo detecta los bloqueadores los anti-bloqueadores? ¿Y cómo reaccionan los bloqueadores a esto y cómo bloquean los anti-bloqueadores?

Historia de la ingeniería inversa.


Lo primero que hice fue mirar su sitio . BlockAdBlock ofrece un configurador con configuraciones: el intervalo de espera y cómo se verá la advertencia, generando diferentes versiones del script.

Esto me hizo pensar en versiones. ¿Qué pasaría si no pudiera ver una versión, y todas a la vez? Así que lo hice. Regresé en el tiempo usando la máquina Wayback . Después de eso, descargué todas las versiones de BlockAdBlock y las procesé.

Lista de todas las versiones de BlockAdBlock, con sha1sum


6d5eafab2ca816ccd049ad8f796358c0a7a43cf3 20151007203811.js
065b4aa813b219abbce76ad20a3216b3481b11bb 20151113115955.js
d5dec97a775b2e563f3e4359e4f8f1c3645ba0e5 20160121132336.js
8add06cbb79bc25114bd7a2083067ceea9fbb354 20160318193101.js
8add06cbb79bc25114bd7a2083067ceea9fbb354 20160319042810.js
8add06cbb79bc25114bd7a2083067ceea9fbb354 20160331051645.js
8add06cbb79bc25114bd7a2083067ceea9fbb354 20160406061855.js
8add06cbb79bc25114bd7a2083067ceea9fbb354 20160408025028.js
555637904dc9e4bfc6f08bdcae92f0ba0f443ebf 20160415083215.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20161120215354.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20170525201720.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20170606090847.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20170703211338.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20170707211652.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20170813090718.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20170915094808.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20171005180631.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20171019162109.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20171109101135.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20171127113945.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20171211042454.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20171227031408.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20180202000800.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20180412213253.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20180419060636.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20180530223228.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20180815042610.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20181029233809.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20181122190948.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20181122205748.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20190324081812.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20190420155244.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20190424200651.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20190903121933.js
d8986247cad3bbc2dd92c3a2a06ac1540da6b286 20200112084838.js

Solo seis versiones difieren entre sí, y la última de ellas se refiere a 2016, aunque algunos sitios todavía usan BlockAdBlock. Esto es genial, porque será suficiente para nosotros aplicar ingeniería inversa a la única versión, y luego invertir las diferencias. Spoiler: veremos el desarrollo de ideas e incluso los restos del código de depuración. Publiqué

todas las versiones en GitHub . Si desea ver diffs, en este repositorio cada confirmación es una nueva versión.

Desempacando


El código del script no está minimizado, sino que está empaquetado por un JS-packer de Dean Edwards con cambios cosméticos y sin ninguna modificación de la lógica 1.

eval(function(p, a, c, k, e, d) {
    e = function(c) {
        return (c < a ? '' : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36))
    };
    if (!''.replace(/^/, String)) {
        while (c--) {
            d[e(c)] = k[c] || e(c)
        }
        k = [function(e) {
            return d[e]
        }];
        e = function() {
            return '\\w+'
        };
        c = 1
    };
    while (c--) {
        if (k[c]) {
            p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c])
        }
    }
    return p
}('0.1("2 3 4 5 6 7 8\'d. 9, h? a b c d e f g");i j=\'a\'+\'k\'+\'e\'+\'l\'+\'n\'+\'m\'+\'e\';',24,24,
'console|log|This|code|will|get|unpacked|then|eval|Cool||||||||huh|let|you|w|s||o'.split('|'),0,{}))

Afortunadamente, esto no es un problema para nosotros. La debilidad del empacador es que todo el código durante el desempaquetado se pasa a eval(). Si reemplazamos eval()con algo así console.log(), de repente obtenemos todo el código fuente, y el empacador es derrotado 2.

Una vez hecho esto para cada versión, podemos examinar cada una de ellas y ver qué funciones se agregaron allí con el tiempo.

v1 :? - Noviembre de 2015: guión inicial


Código fuente

Comencemos con un estudio 20151007203811.jspublicado alrededor de noviembre de 2015 3. Aunque esta primera versión no bloquea muy bien los bloqueadores, le permite evaluar la arquitectura BlockAdBlock sin la basura que se ha acumulado a lo largo de los años.

Arquitectura


En tres oraciones:

  • BlockAdBlock es un cierre que devuelve un objeto con tres funciones:
    • bab() pone el cebo y llama un cheque check
    • check() comprueba si el bloqueador ha bloqueado el cebo, causando arm
    • arm() cubrir
  • El punto de entrada bab()comienza luego de un período de tiempo especificado.
  • Se generan tres funciones con argumentos que se establecen en el configurador BlockAdBlock .

El código se construye alrededor de un cierre asignado a un objeto global con un nombre aleatorio.

var randomID = '',
    e = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i = 0; i < 12; i++) randomID += 
    e.charAt(Math.floor(Math.random() * e.length));
var setTimeoutDelay = 7; // Delay after which to call BlockAdBlock
window['' + randomID + ''] = ...

El autor proporcionó una aleatorización exhaustiva para evitar el bloqueo estático.

A continuación, devuelve un objeto con tres funciones: bab, checky arm.

window['' + randomID + ''] = (function() {
    var eid = ...
    return {
        bab: function(check, passed_eid) {},
        check: function(checkPredicate, unused) {},
        arm: function() {}
    }
})();

Estos son mis propios nombres. Todas las variables están minimizadas, y algunas están especialmente ofuscadas.
Se bab()llama al punto de entrada setTimeout().

setTimeout('window[\'\' + randomID + \'\'] \
.bab(window[\'\' + randomID + \'\'].check, \
     window[\'\' + randomID + \'\'].bab_elementid)', setTimeoutDelay * 1000)

bab_elementidNo se utiliza en ninguna versión del código. setTimeoutpasado como una cuerda.

Un cierre tiene variables externas. Dos de ellos se usan para guardar el estado en un script:

  • adblockDetected igual a 1 si se detecta un bloqueador de anuncios.
  • nagMode- Esta es una opción de configuración. Si está instalado, el script no bloquea el acceso a la página, sino que solo se enciende una vez.

Otras variables para controlar la apariencia y el comportamiento se establecen en el configurador .

var eid = ' ad_box', // Name of the bait.
    __u1 = 1, // Unused.

    // Colors for the blockadblock prompt.
    overlayColor = '#EEEEEE',
    textColor = '#777777',
    buttonBackgroundColor = '#adb8ff',
    buttonColor = '#FFFFFF',

    __u2 = '', // Unused.

    // Text to display when the blockadblock prompt is shown.
    welcomeText = 'Sorry for the interruption...',
    primaryText = 'It looks like you\'re using an ad blocker. That\'s okay.  Who doesn\'t?',
    subtextText = 'But without advertising-income, we can\'t keep making this site awesome.',
    buttonText = 'I understand, I have disabled my ad blocker.  Let me in!',

    // If 1, adblock was detected.
    adblockDetected = 0,
    // If 1, BlockAdBlock will only nag the visitor once, rather than block access.
    nagMode = 0,

    // The blockadblock domain, reversed.
    bab_domain = 'moc.kcolbdakcolb';

bab_domain establecido aquí en un intento de ofuscar el dominio BlockAdBlock.

bab: crea un banner de señuelo


El método principal de trabajar con BlockAdBlock es crear "cebo" o "cebo" a partir de elementos publicitarios que parecen pancartas reales. Luego verifica si su bloqueador ha bloqueado.

Esto crea un señuelo: un div falso que finge ser un anuncio pero está oculto a la vista.

bab: function(check, passed_eid) {
    // Wait for the document to be ready.
    if (typeof document.body == 'undefined') {
        return
    };

    var delay = '0.1', 
        passed_eid = eid ? eid : 'banner_ad',
        bait = document.createElement('DIV');
        
    bait.id = passed_eid;
    bait.style.position = 'absolute';
    bait.style.left = '-999px';
    bait.appendChild(document.createTextNode(' '));
    document.body.appendChild(bait);
    ...

Aparentemente, está passed_eiddestinado a configurar el identificador del cebo, pero no se utiliza.

Después de eso, se verifica si el cebo ha sido eliminado por el bloque de anuncios.

    ...
    setTimeout(function() {
        if (bait) {
            check((bait.clientHeight == 0), delay);
            check((bait.clientWidth == 0), delay);
            check((bait.display == 'hidden'), delay);
            check((bait.visibility == 'none'), delay);
            check((bait.opacity == 0), delay);
            check((bait.left < 1000), delay);
            check((bait.top < 1000), delay)
        } else {
            check(true, delay)
        }
    }, 125)
}

Si el cebo ya no existe, el elemento se elimina (y comenzamos la superposición).

La función checkfuncionará si Predicatedevuelve un valor truey comienza arm.

check: function(checkPredicate, unused) {
    if ((checkPredicate) && (adblockDetected == 0)) {
        adblockDetected = 1;
        window['' + randomID + ''].arm()
    } else {}
}

Como la prueba se checkdispara varias veces, como se muestra arriba, se adblockDetectedestablece en la primera prueba correcta para evitar disparos repetidos arm.

Modo gruñido


El script tiene una función llamada "modo molesto": en este modo, BlockAdBlock solo dirá una vez para deshabilitar el bloqueador de anuncios, pero no lo bloqueará cada vez que lo visite. Esto se hace configurando el elemento localStorageen la primera visita.

Si pudiéramos instalar este elemento nosotros mismos, ¿podríamos desactivar el bloqueo para siempre? Desafortunadamente, BlockAdBlock verifica de antemano si la secuencia de comandos se configuró para modo molesto, por lo que este método no funcionará cuando funcione en modo predeterminado, es decir, con bloqueo de acceso.

arm: function() {
    if (nagMode == 1) {
        var babNag = sessionStorage.getItem('babn');
        if (babNag > 0) {
            return true // Stop the script.
        } else {
            sessionStorage.setItem('babn', (Math.random() + 1) * 1000)
        }
    };
    ...

Desafortunadamente, está nagModeinstalado en el configurador, y por defecto es igual 0.

BlockAdBlock versión 1


Los bloqueadores de anuncios usan los llamados filtros: líneas de código que pueden bloquear solicitudes de red y ocultar elementos en la página. Al crear elementos de cebo, BlockAdBlock lanza específicamente estos filtros.

Con esta defensa simple, BlockAdBlock es efectivo contra todos los principales bloqueadores de anuncios como uBlock Origin, AdBlock Plus y Ghostery. Para contrarrestar esto, debemos escribir nuestro propio filtro, que se activa solo en los sitios que ejecutan BlockAdBlock.

Escribir filtros para un bloqueador es un poco complicado. Necesitamos un filtro de contenido que bloquee los elementos de la página generados después de la carga. Como el cebo tiene un identificador banner_ad, creamos una excepción para ocultar elementosmarcado #@#para todos los elementos #con un identificador banner_ady ponerlo en la lista de filtros de usuario de nuestro bloqueador.

El resultado es el siguiente:

localhost#@# #banner_ad

Tengo localhost aquí para demostración, puede reemplazarlo con su URL.

Esto desactiva correctamente BlockAdBlock. La solución puede parecer simple, pero lleva mucho tiempo funcionando con éxito en la lista de filtros Anti-AdBlock-Killer .

Versión 2 (noviembre de 2015 - enero de 2016): varias mejoras


Diferencia de código fuente
v1 / v2

Creación de cebo: menos errores


Hay un error sutil en la primera versión de crear el cebo: el div creado no tiene contenido, por lo que se genera un div con una altura de 0 y un ancho de 0. Más tarde, el código verifica si el div se elimina al verificar su altura y ancho. Pero como tenía una altura cero, BlockAdBlock siempre funcionó 4.

Se corrigió el error de un div vacío.

bab: function(...) {
    bait = document.createElement('DIV');
    ...
    bait.appendChild(document.createTextNode('Â '));

Se crea un div hijo con algún contenido.

Detección de bloqueadores a través de pancartas gráficas falsas


En este método, creamos una imagen falsa con un nombre aleatorio doubleclick.net. Los bloqueadores de anuncios bloquearán la imagen, pensando que es un banner publicitario. Pero esto no requiere ningún cambio en nuestro filtro.

bab: function(...) {
    bait = document.createElement('DIV');
    bait.innerHTML = '<img src="http://doubleclick.net/' + randomStr() + '.jpg">';
    ...

randomStr()genera una cadena de longitud arbitraria.

Otra diferencia notable fue el uso de un temporizador en setIntervallugar de una simple verificación única para ver si hay un disparador instalado. Vuelve a verificar si se muestra el banner gráfico y si no se cambia su atributo src, verificando el contenido del cebo.

Nuevo setIntervaly verifique la disponibilidad de la imagen:

    ...
    checkCallback = setInterval(function() {
        if (bait) {
            check((bait.clientHeight == 0), delay);
            check((bait.clientWidth == 0), delay);
            check((bait.display == 'hidden'), delay);
            check((bait.visibility == 'none'), delay);
            check((bait.opacity == 0), delay);
            try {
                check((document.getElementById('banner_ad').innerHTML.indexOf('click') == -1), delay)
            } catch (e) {}
        } else {
            check(true, delay)
        }
    }, 1000

¿Por qué indexof ('click')? Debido a la fuente de la imagen src="doubleclick.net/abcdefg.jpg"y verificamos si se conserva el fragmento de la cadena click.

Versión 3 (noviembre de 2015 - marzo de 2016): cebo generalizado


Diferencia de código fuente
v2 / v3

Creación de cebo: identificadores aleatorios


El único cambio en esta versión, aunque significativo, es la aparición de identificadores aleatorios para el cebo. El nuevo identificador se toma de la lista de identificadores al cargar la página y se usa para el cebo, que ahora se coloca en el medio de la página.

Una larga lista de identificadores aleatorios demuestra un buen conocimiento del área temática.

var baitIDs = [
  "ad-left",
  "adBannerWrap",
  "ad-frame",
  "ad-header",
  "ad-img",
  "ad-inner",
  "ad-label",
  "ad-lb",
  "ad-footer",
  "ad-container",
  "ad-container-1",
  "ad-container-2",
  "Ad300x145",
  "Ad300x250",
  "Ad728x90",
  "AdArea",
  "AdFrame1",
  "AdFrame2",
  "AdFrame3",
  "AdFrame4",
  "AdLayer1",
  "AdLayer2",
  "Ads_google_01",
  "Ads_google_02",
  "Ads_google_03",
  "Ads_google_04",
  "DivAd",
  "DivAd1",
  "DivAd2",
  "DivAd3",
  "DivAdA",
  "DivAdB",
  "DivAdC",
  "AdImage",
  "AdDiv",
  "AdBox160",
  "AdContainer",
  "glinkswrapper",
  "adTeaser",
  "banner_ad",
  "adBanner",
  "adbanner",
  "adAd",
  "bannerad",
  " ad_box",
  " ad_channel",
  " adserver",
  " bannerid",
  "adslot",
  "popupad",
  "adsense",
  "google_ad",
  "outbrain-paid",
  "sponsored_link"
];

Generación de identificación aleatoria


    randomBaitID = baitIDs[ Math.floor(Math.random() * baitIDs.length) ],
    ...
    var passed_eid = randomBaitID;
    bait = document.createElement('DIV');    
    bait.id = passed_eid;

Como esto funciona en cada arranque, el identificador será diferente cada vez.

BlockAdBlock, penúltima versión


BlockAdBlock explota el punto ciego de los bloqueadores de anuncios: si un filtro omite todos los identificadores anteriores, también omitirá los anuncios reales. Por lo tanto, BlockAdBlock obliga al bloqueador de anuncios a volverse inútil .

En los bloqueadores, podemos ejecutar scripts arbitrarios antes de cargar la página. Puede intentar eliminar el objeto BlockAdBlock de antemano. Pero para esto necesitamos el nombre del objeto BlockAdBlock, que se aleatoriza cada vez que se inicia.

uBlock Origin tomó un enfoque diferente. Dado que el código es ejecutado por una función eval, podemos definir nuestra propia función evalque bloqueará la ejecución si encontramos BlockAdBlock. En JS, un objeto es capaz de esto Proxy: puede reemplazar cualquier propiedad y método en cualquier objeto.

Esto se puede evitar al no pasar la carga útil inicial de BlockAdBlock eval, sino al usarla directamente, por lo que también representamos el punto de entrada: la llamada setTimeout. Como lo setTimeoutpasa una cadena, no una función, verificamos esta cadena.

Implementación en uBlock Origin ( fuente ):

const signatures = [
    [ 'blockadblock' ],
    [ 'babasbm' ],
    [ /getItem\('babn'\)/ ],
    [
        'getElementById',
        'String.fromCharCode',
        'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
        'charAt',
        'DOMContentLoaded',
        'AdBlock',
        'addEventListener',
        'doScroll',
        'fromCharCode',
        '<<2|r>>4',
        'sessionStorage',
        'clientWidth',
        'localStorage',
        'Math',
        'random'
    ],
];
const check = function(s) {
    // check for signature 
};

Lista de firmas: definición de plantillas de código. La función checkverifica la cadena después evalpara el cumplimiento de estos patrones.

A continuación, delegue las funciones evaly setTimeout.

window.eval = new Proxy(window.eval, {
    apply: function(target, thisArg, args) {
        const a = args[0];
        if ( typeof a !== 'string' || !check(a) ) {
            return target.apply(thisArg, args);
        } 
        // BAB detected: clean up.
        if ( document.body ) {
            document.body.style.removeProperty('visibility');
        }
        let el = document.getElementById('babasbmsgx');
        if ( el ) {
            el.parentNode.removeChild(el);
        }
    }
});
window.setTimeout = new Proxy(window.setTimeout, {
    apply: function(target, thisArg, args) {
        const a = args[0];
        // Check that the passed string is not the BAB entrypoint.
        if (
            typeof a !== 'string' ||
            /\.bab_elementid.$/.test(a) === false
        ) {
            return target.apply(thisArg, args);
        }
    }
});

Como ahora estamos usando un scriptlet , un fragmento de código personalizado especial ejecutado por el bloqueador, el filtro cambia un poco:

localhost## +js(nobab)

No se inicia de manera predeterminada en todos los sitios por razones de rendimiento, por lo que debe asignarlo a cada sitio mediante un script.

Versión 4 (enero de 2016 - abril de 2016): funciones experimentales



Diferencia de código fuente v3 / v4

El método descrito para bloquear los anti-bloqueadores se desarrolló en enero de 2016, de acuerdo con la historia de los compromisos de uBlock Origin , y no ha cambiado conceptualmente desde su inicio. BlockAdBlock nunca intentó evitar este filtro cambiando su arquitectura. En cambio, continuó desarrollando nuevas características. Y cuando vamos a la página BlockAdBlock, vemos una pestaña interesante: "¿Necesita más poder antibloqueo?"



Aunque estos métodos de protección están disponibles solo a través de una pestaña especial, se incluyen en todos los scripts y se ejecutan a través de variables con los nombres correspondientes. La cuarta versión implementa dos métodos:

  • aDefOne, "Protección específica para sitios adsense"
  • aDefTwo, "Característica de seguridad especial"

Comentarios de depuración aleatorios


Antes de despedirme, debo mencionar una cosa más. En el proceso de ingeniería inversa, una función me llamó la atención: ¡

Depuración console.log()directamente en el código!

function consolelog(e) {
    // "Dev mode" check: developpers of BAB must set window.consolelog to 1.
    if (window.consolelog == 1) {
        console.log(e)
    }
};

Esto solo se hace si se establece global consolelog, por ejemplo window.consolelog = 1.

Los comentarios de depuración solo están disponibles en esta versión. Si no hubiera revertido todas las versiones, nunca las habría notado. Proporcionan información valiosa sobre cómo funciona el código.

Seguridad avanzada: AdSense


Todos estos métodos de protección especiales están codificados en check, no en arm, como sugiere la arquitectura. Quizás un nuevo desarrollador que no esté familiarizado con el código base haya comenzado a trabajar en el producto.

Si AdSense está activo en la página, buscamos anuncios. Si desaparecieron debido a un bloqueador, BlockAdBlock se activa.

function check() {
    ...
    var q = 'ins.adsbygoogle',
        // Selects all Google ads in the document.
        adsbygoogleQuery = document.querySelector(q);

    if ((adsbygoogleQuery) && (adblockDetected == 0)) {
        // Ads are not blocked, since the bait ad is still there,
        // and adblockDetected hasn't been set
        if (aDefOne == 'yes') {
            consolelog('case2: standard bait says ads are NOT blocked.');
            var adsbygoogle = '//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js';
            if (scriptExists(adsbygoogle)) {
                consolelog('case2: And Adsense pre-exists.');
                if (adsbygoogleQuery.innerHTML.replace(/\s/g, '').length == 0) {
                    // The ad's content was cleared, so...
                    consolelog('case2: Ads are blocked.');
                    window['' + randomID + ''].arm()
                }
            }
        };
        adblockDetected = 1
    }
    ...

scriptExistsbusca en la página completa un script con una URL dada. En este caso, el script de AdSense 5.

La URL de la secuencia de comandos se compara con todas las secuencias de comandos de la página. Por alguna razón, la URL se trunca a 15 caracteres.

function scriptExists(href) {
    if (href) href = href.substr(href.length - 15);
    var scripts = document.getElementsByTagName('script');
    for (var i = scripts.length; i--;) {
        var src = String(scripts[i].src);
        if (src) src = src.substr(src.length - 15);
        if (src === href) return true
    };
    return false
};

Protección avanzada: elemento especial


A diferencia del primero, este método va acompañado de un descargo de responsabilidad: "Realice una prueba después de la instalación para garantizar la compatibilidad con su sitio".

Esta protección especial solo funciona si no se encuentra un bloqueador y no hay un script de AdSense en la página. Aquí está el fragmento de código relevante check:

check: function(checkPredicate, unused) {
    if ((checkPredicate) && (adblockDetected == 0)) {
        // Adblocker detected, arm
    } else {
        var q = 'ins.adsbygoogle',
            adsbygoogleQuery = document.querySelector(q);

        if ((adsbygoogleQuery) && (adblockDetected == 0)) {
            if (aDefOne == 'yes') {
                // Special defense one: AdSense defense (see above)
            };
        } else {
            if (adblockDetected == 0) {
                if (aDefTwo == 'yes') {
                    // Special defense two: Special element defense
                }
            }
        }
    }

El método supone que los propietarios de sitios usan solo AdSense: si no existe un script de AdSense, entonces algo está mal.

¿Por qué hubo una advertencia? Este método intenta habilitar el script de AdSense. Si no se carga, lo más probable es que el bloqueador haya bloqueado la solicitud de red, por lo tanto, se activa BlockAdBlock. Pero esto puede arruinar algunos sitios, de ahí la advertencia.

Si AdSense no se ha cargado, se inicia la superposición.

if (aDefTwo == 'yes') {
    /* Add Google ad code to head.
        If it errors, the adblocker must have blocked the connection. */
    var googleAdCode = '//static.doubleclick.net/instream/ad_status.js';
    consolelog('case3: standard bait says ads are NOT blocked. Maybe ???\
      No Adsense is found. Attempting to add Google ad code to head...');
    var script = document.createElement('script');
    script.setAttribute('type', 'text/javascript');
    script.setAttribute('src', googleAdCode);
    script.onerror = function() {
        window['' + randomID + ''].arm()
    };
    adblockDetected = 1;
    if (!scriptExists(googleAdCode)) {
        document.getElementsByTagName('head')[0].appendChild(script)
    };
    adsbygoogleQuery = 0;
    window['' + randomID + ''].check = function() {
        return
    }
}

Cuando ocurre una falla a nivel de red, funciona onerror, como con un bloqueador de anuncios.

De hecho, la mayoría de los bloqueadores de anuncios responden a esto y bloquean la solicitud. Pero hay un bloqueador que aún no he mencionado. Habla sobre el navegador Brave .

Respuesta valiente del navegador


Hasta ahora, hemos estado estudiando cómo se detecta el antibloqueo en uBlock Origin. Y funciona, solo se requiere un filtro específico para cada sitio donde está instalado BlockAdBlock. El navegador Brave es impresionante porque detecta y omite BlockAdBlock de todas las versiones sin ninguna acción necesaria por parte del usuario. Para hacer esto, falsifica la solicitud directamente en la capa de red 6.

En lugar de bloquear la solicitud, ad_status.jsla omite, pero carga Google Ads falsos de 0 bytes de tamaño . Este truco engañoso engaña a BlockAdBlock, porque onerrorsolo funciona si la solicitud de red falla.



Versión 5 (marzo de 2016 - noviembre de 2016)


Diferencia de código fuente
v4 / v5

Protección avanzada: favicons de spam


El único cambio en esta versión es que la segunda protección extendida se reescribió, aunque todavía se adhiere al mismo principio básico: verificar las solicitudes de red que serán bloqueadas por el bloqueador. Pero ahora se están cargando favicons en lugar de AdSense.

Valiente evade este ataque de la misma manera. No bloquea las solicitudes, pero crea imágenes falsas 1 × 1.

if (aDefTwo == 'yes') {
    if (! window['' + randomID + ''].ranAlready) {/
        var favicons = [
            "//www.google.com/adsense/start/images/favicon.ico",
            "//www.gstatic.com/adx/doubleclick.ico",
            "//advertising.yahoo.com/favicon.ico",
            "//ads.twitter.com/favicon.ico",
            "//www.doubleclickbygoogle.com/favicon.ico"
            ],
            len = favicons.length,
            img = favicons[Math.floor(Math.random() * len)],
        ...
        baitImages(Math.floor(Math.random() * 2) + 1); // creates bait images
        var m = new Image();
        m.onerror = function() {
            baitImages(Math.floor(Math.random() * 2) + 1);
            c.src = imgCopy;
            baitImages(Math.floor(Math.random() * 2) + 1)
        };
        c.onerror = function() {
            adblockDetected = 1;
            baitImages(Math.floor(Math.random() * 3) + 1);
            window['' + randomID + ''].arm()
        };
        m.src = img;
        baitImages(Math.floor(Math.random() * 3) + 1);
        window['' + randomID + ''].ranAlready = true
    };
}

La función baitImagesse puede llamar con frecuencia, con un número aleatorio de imágenes, para evitar bloqueadores estáticos.

Versión 6 (abril de 2016 - noviembre de 2016): Brave lock



Diferencia de código fuente v5 / v6

Los métodos BlockAdBlock, aunque simples a primera vista, gradualmente se volvieron más complejos y más eficientes. Pero el último enemigo invicto permaneció: el navegador Brave.

Protección avanzada: definición de un falso icono


¿Por qué BlockAdBlock cambió de intentar cargar un script para cargar imágenes (favicons)? La respuesta está en el código que se agrega a la protección a través de favicons de spam y que se activa contra la protección de Brave.

Verificando la respuesta para una imagen falsa:

if (aDefTwo == 'yes') {
    baitImages(Math.floor(Math.random() * 3) + 1);
    // earlier favicon code...
    var m = new Image();
    if ((aDefThree % 3) == 0) {
        m.onload = function() {
            if ((m.width < 8) && (m.width > 0)) {
                window['' + randomID + ''].arm()
            }
        }
    };
}

Si el tamaño del favicon es inferior a 8 × 8, entonces esto es probablemente falso del navegador Brave.

Con este truco, BlockAdBlock evita el disfraz de Brave y otros bloqueadores que ejecutan este código (la mayoría, como uBlock Origin, lo bloquea primero).

Después de esta actualización, a fines de noviembre de 2016, BlockAdBlock desapareció de Internet. Aunque sus "métodos de seguridad avanzados" funcionan, nunca se han activado para la mayoría de los usuarios. Esta fue la última actualización. La última publicación en Twitter y en el sitio se publicó en algún lugar a fines de 2017.

Sin embargo, el legado de BlockAdBlock sigue vivo. Aunque es trivial bloquearlo en estos días, algunos sitios modernos todavía usan este script.

Conclusión


¿Quién ganará la carrera armamentista entre los bloqueadores de anuncios y los antibloqueadores que bloquean los bloqueadores de anuncios? Sólo el tiempo dirá. A medida que se desarrolle la carrera armamentista, los antibloqueadores tendrán que usar métodos más sofisticados y códigos especiales, como lo demuestra la evolución de BlockAdBlock.

Por otro lado, los bloqueadores tienen la ventaja de sistemas estables y potentes herramientas de filtrado a través de listas de filtros, así como acceso a JavaScript. Con dicho sistema, es suficiente que una persona entienda cómo vencer al enemigo y actualice la lista de filtros con nuevos sitios.

Al analizar la evolución de BlockAdBlock, así como las diversas respuestas de los bloqueadores de anuncios, pudimos pintar una imagen de una pequeña guerra entre BlockAdBlock y los bloqueadores. En el proceso, aprendimos qué métodos se usan en las hostilidades.

Mi código de ingeniería inversa se publica en GitHub . Gracias por leer.



1. Si desea tener una idea de cómo funciona esto, intente pegar el siguiente ejemplo en la consola JS y luego mire el código. Si está interesado en su funcionamiento interno, aquí está el código fuente . [volver]

2. ¿No lo crees? Intenta cambiar evala console.logen la primera línea.
[regresar]

3. La marca de tiempo dice 201510, entonces quizás octubre. Pero no sabemos cuándo cambió el guión. Todo lo que sabemos:

  • 2015-10, se guardó una versión: 20151007203811.js
  • 2015-11 hay una nueva versión: 20151113115955.js

Hasta donde sabemos, el script podría cambiarse el día anterior a la segunda marca de tiempo. Por lo tanto, me acerco conservadoramente a las citas. [volver]

4. Durante la corrección de este error se desarrollaron pruebas para v1. [volver]

5. Gracias a McStroyer en Reddit, que llamó la atención sobre esto. [volver]

6. El componente bloqueador de anuncios Brave está abierto, por lo que podemos ver el código fuente para tener una idea de cómo funciona.


Gracias a François Marie por señalar el código fuente de Brave. [volver]

All Articles