Engenharia reversa anti-bloqueio de publicidade BlockAdBlock

Se você usa bloqueadores de anúncios, pode encontrar o BlockAdBlock . Este script detecta seu bloqueador e não permite o acesso até o site. Mas eu me perguntava como isso funciona. Como o anti-bloqueador detecta os bloqueadores? E como os bloqueadores reagem a isso e como eles bloqueiam os anti-bloqueadores?

História da engenharia reversa


A primeira coisa que fiz foi olhar para o site deles . O BlockAdBlock oferece um configurador com configurações: o intervalo de espera e a aparência do aviso, gerando diferentes versões do script.

Isso me fez pensar em versões. E se ele não podia ver uma versão, e tudo de uma vez? Então eu fiz. Voltei no tempo usando a Wayback Machine . Depois disso, baixei todas as versões do BlockAdBlock e as misturei.

Lista de todas as versões do BlockAdBlock, com 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

Apenas seis versões diferem entre si, e a última delas se refere a 2016, embora alguns sites ainda usem o BlockAdBlock. Isso é ótimo, porque será o suficiente para fazermos engenharia reversa da única versão e depois inverter as diferenças. Spoiler: veremos o desenvolvimento de idéias e até os remanescentes do código de depuração. Publiquei

todas as versões no GitHub . Se você deseja examinar as diferenças, neste repositório cada confirmação é uma nova versão.

Desembalar


O código do script não é minificado, mas compactado por um JS-packer de Dean Edwards com alterações cosméticas e sem nenhuma modificação da 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,{}))

Felizmente, isso não é um problema para nós. O ponto fraco do empacotador é que todo o código durante a descompactação é passado para eval(). Se substituirmos eval()por algo parecido console.log(), obteremos repentinamente todo o código-fonte e o empacotador será derrotado ..

Feito isso para cada versão, podemos examinar cada uma delas e ver quais funções foram adicionadas ao longo do tempo.

v1 :? - novembro de 2015: roteiro inicial


Código-fonte

Vamos começar com um estudo 20151007203811.jspublicado em novembro de 2015 3. Embora essa primeira versão não bloqueie muito bem os bloqueadores, ela permite avaliar a arquitetura BlockAdBlock sem o lixo acumulado ao longo dos anos.

Arquitetura


Em três frases:

  • BlockAdBlock é um fechamento que retorna um objeto com três funções:
    • bab() define a isca e chama um cheque check
    • check() verifica se o bloqueador bloqueou a isca, causando arm
    • arm() sobreposição
  • O ponto de entrada é bab()iniciado após um período de tempo especificado.
  • Três funções são geradas com argumentos definidos no configurador BlockAdBlock .

O código é criado em torno de um fechamento atribuído a um objeto global com um nome aleatório.

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 + ''] = ...

O autor forneceu uma randomização completa para contornar o bloqueio estático.

Em seguida, retorna um objeto com três funções: bab, checke arm.

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

Estes são meus próprios nomes. Todas as variáveis ​​são minificadas e algumas são ofuscadas.
O ponto de entrada é bab()chamado setTimeout().

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

bab_elementidnão usado em nenhuma versão do código. setTimeoutpassado como uma string.

Um fechamento possui variáveis ​​externas. Dois deles são usados ​​para salvar o estado em um script:

  • adblockDetected igual a 1 se um bloqueador de anúncios for detectado.
  • nagMode- Esta é uma opção de configuração. Se estiver instalado, o script não bloqueia o acesso à página, mas apenas o ativa uma vez.

Outras variáveis ​​para controlar a aparência e o comportamento são definidas no 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 definido aqui na tentativa de ofuscar o domínio BlockAdBlock.

bab: crie um banner de chamariz


O principal método de trabalho com o BlockAdBlock é criar "isca" ou "isca" a partir de elementos de publicidade que parecem banners reais. Ele então verifica se o bloqueador está bloqueado.

Isso cria um engodo: uma div falsa que finge ser um anúncio, mas está oculta.

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, passed_eidpretende-se configurar o identificador da isca, mas não é usado.

Depois disso, é verificado se a isca foi removida pelo bloco de anúncios.

    ...
    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)
}

Se a isca não existir mais, o elemento será excluído (e iniciaremos a sobreposição).

A função checkfuncionará se Predicateretornar um valor truee iniciar arm.

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

Como o teste é checkacionado várias vezes, como mostrado acima, é adblockDetecteddefinido como o primeiro teste correto para evitar disparos repetidos arm.

Modo Grunhido


O script possui uma função chamada "modo nag": nesse modo, o BlockAdBlock diz apenas uma vez para desativar o bloqueador de anúncios, mas não o bloqueia toda vez que você o visita. Isso é feito configurando o item localStoragena primeira visita.

Se pudéssemos instalar esse elemento, poderíamos desativar o bloqueio para sempre? Infelizmente, o BlockAdBlock verifica antecipadamente se o script foi configurado para o modo nag; portanto, esse método não funcionará quando funcionar no modo padrão, ou seja, com bloqueio de acesso.

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)
        }
    };
    ...

Infelizmente, ele está nagModeinstalado no configurador e, por padrão, é igual 0.

BlockAdBlock versão 1


Os bloqueadores de anúncios usam os chamados filtros: linhas de código que podem bloquear solicitações de rede e ocultar elementos na página. Ao criar elementos de isca, o BlockAdBlock inicia especificamente esses filtros.

Com essa defesa simples, o BlockAdBlock é eficaz contra todos os principais bloqueadores de anúncios, como uBlock Origin, AdBlock Plus e Ghostery. Para combater isso, precisamos escrever nosso próprio filtro, que é ativado apenas em sites que executam o BlockAdBlock.

Escrever filtros para um bloqueador é um pouco complicado. Precisamos de um filtro de conteúdo que bloqueie elementos na página gerada após o carregamento. Como a isca tem um identificador banner_ad, criamos uma exceção para ocultar elementosmarcado #@#para todos os elementos #com um identificador banner_ade coloque-o na lista de filtros de usuários do nosso bloqueador.

O resultado é o seguinte:

localhost#@# #banner_ad

Eu tenho o host local aqui para demonstração. Você pode substituí-lo pelo seu URL.

Isso desativa com sucesso o BlockAdBlock. A solução pode parecer simples, mas há muito tempo trabalha com êxito na lista de filtros Anti-AdBlock-Killer .

Versão 2 (novembro de 2015 - janeiro de 2016): várias melhorias


Diferença do código fonte
v1 / v2

Criação de iscas: menos bugs


Há um erro sutil na primeira versão da criação da isca: a div criada não tem conteúdo; portanto, uma div é gerada com uma altura de 0 e uma largura de 0. Mais tarde, o código verifica se a div foi excluída, verificando sua altura e largura. Mas como tinha altura zero, o BlockAdBlock sempre funcionou 4.

O erro de uma div vazia foi corrigido.

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

Uma div filho é criada com algum conteúdo.

Detecção de bloqueadores através de banners gráficos falsos


Nesse método, criamos uma imagem falsa com um nome aleatório ativado doubleclick.net. Bloqueadores de anúncios bloquearão a imagem, pensando que é um banner de anúncio. Mas isso não requer nenhuma alteração no nosso filtro.

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

randomStr()gera uma cadeia de comprimento arbitrário.

Outra diferença notável foi o uso de um temporizador, em setIntervalvez de uma simples verificação única para ver se um gatilho está instalado. Ele verifica novamente se o banner gráfico é exibido e se seu atributo não foi alterado src, verificando o conteúdo da isca.

Novo setIntervale verifique a disponibilidade da imagem:

    ...
    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 que indexof ('click')? Porque a fonte da imagem src="doubleclick.net/abcdefg.jpg"e verificamos se o fragmento da string é preservado click.

Versão 3 (novembro de 2015 - março de 2016): isca generalizada


Diferença do código fonte
v2 / v3

Criação de Iscas: Identificadores Aleatórios


A única alteração nesta versão, embora significativa, é a aparência de identificadores aleatórios para a isca. O novo identificador é retirado da lista de identificadores ao carregar a página e é usado para a isca, que agora é colocada no meio da página.

Uma longa lista de identificadores aleatórios demonstra um bom conhecimento da área de assunto.

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"
];

Geração aleatória de ID


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

Como isso funciona em cada inicialização, o identificador será diferente a cada vez.

BlockAdBlock, terceira a última versão


O BlockAdBlock explora o ponto cego dos bloqueadores de anúncios: se um filtro ignorar todos os identificadores acima, ele também ignorará os anúncios reais. Assim, o BlockAdBlock força o bloqueador de anúncios a se tornar inútil .

Nos bloqueadores, podemos executar scripts arbitrários antes de carregar a página. Você pode tentar remover o objeto BlockAdBlock antecipadamente. Mas, para isso, precisamos do nome do objeto BlockAdBlock, que é randomizado cada vez que é iniciado.

O uBlock Origin adotou uma abordagem diferente. Como o código é executado por uma função eval, podemos definir nossa própria função evalque bloqueará a execução se encontrarmos o BlockAdBlock. Em JS, um objeto é capaz disso Proxy: você pode substituir qualquer propriedade e método em qualquer objeto.

Isso pode ser contornado, não passando a carga útil inicial do BlockAdBlock eval, mas usando-a diretamente, portanto, também procuramos o ponto de entrada: a chamada setTimeout. Como é setTimeoutpassado por uma string, não por uma função, verificamos essa string.

Implementação no uBlock Origin ( origem ):

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 assinaturas: definindo modelos de código. A função checkverifica a sequência após evala conformidade com esses padrões.

Em seguida, proxy as funções evale 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 agora estamos usando um scriptlet , um fragmento de código personalizado especial executado pelo bloqueador, o filtro muda um pouco:

localhost## +js(nobab)

Por não iniciar por padrão em todos os sites por motivos de desempenho, você deve atribuí-lo a cada site usando um script.

Versão 4 (janeiro de 2016 - abril de 2016): funções experimentais



Diferença do código-fonte v3 / v4

O método descrito para bloquear anti-bloqueadores foi desenvolvido em janeiro de 2016, de acordo com o histórico de confirmações do uBlock Origin , e não mudou conceitualmente desde o início. O BlockAdBlock nunca tentou contornar esse filtro alterando sua arquitetura. Em vez disso, ele continuou a desenvolver novos recursos. E quando vamos para a página BlockAdBlock, vemos uma guia interessante: "Você precisa de mais poder anti-bloqueio?"



Embora esses métodos de proteção estejam disponíveis apenas através de uma guia especial, eles estão incluídos em todos os scripts e são executados através de variáveis ​​com os nomes correspondentes. A quarta versão implementa dois métodos:

  • aDefOne, "Proteção específica para sites do adsense"
  • aDefTwo, "Recurso especial de segurança"

Comentários de depuração aleatórios


Antes de me despedir de você, devo mencionar mais uma coisa. No processo de engenharia reversa, uma função chamou minha atenção:

Depurando console.log()diretamente no código!

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

Isso é feito apenas se global consolelog, por exemplo, estiver definido window.consolelog = 1.

Os comentários de depuração estão disponíveis apenas nesta versão. Se eu não tivesse revertido todas as versões, nunca as teria notado. Eles fornecem informações valiosas sobre como o código funciona.

Segurança avançada: AdSense


Todos esses métodos especiais de proteção são codificados check, não armcomo, como sugere a arquitetura. Talvez um novo desenvolvedor que não esteja familiarizado com a base de código tenha começado a trabalhar no produto.

Se o AdSense estiver ativo na página, procuraremos anúncios. Se eles desaparecerem devido a um bloqueador, o BlockAdBlock será ativado.

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
    }
    ...

scriptExistsverifica a página inteira em busca de um script com um determinado URL. Nesse caso, o script do AdSense 5.

A URL do script é comparada com todos os scripts da página. Por algum motivo, o URL é truncado para 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
};

Proteção Avançada: Elemento Especial


Diferentemente do primeiro, esse método é acompanhado por um aviso: "Teste após a instalação para garantir a compatibilidade com o site".

Essa proteção especial funciona apenas se um bloqueador não for encontrado e não houver script do AdSense na página. Aqui está o trecho 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
                }
            }
        }
    }

O método pressupõe que os proprietários do site usem apenas o AdSense: se um script do AdSense não existir, algo estará errado.

Por que houve um aviso? Este método tenta ativar o script do AdSense. Se não carregar, provavelmente o bloqueador bloqueou a solicitação de rede, portanto, o BlockAdBlock é acionado. Mas isso pode arruinar alguns sites, daí o aviso.

Se o AdSense não tiver sido carregado, a sobreposição será iniciada.

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
    }
}

Quando ocorre uma falha no nível da rede, ela funciona onerrorcomo se um bloqueador de anúncios estivesse funcionando.

De fato, a maioria dos bloqueadores de anúncios responde a isso e bloqueia a solicitação. Mas há um bloqueador que eu não mencionei ainda. Fale sobre o navegador Brave .

Admirável Resposta do Navegador


Até agora, estudamos como o anti-bloqueio é detectado no uBlock Origin. E funciona, apenas um filtro específico é necessário para cada site em que o BlockAdBlock está instalado. O navegador Brave é impressionante, pois detecta e ignora o BlockAdBlock de todas as versões sem nenhuma ação necessária por parte do usuário. Para fazer isso, ele falsifica a solicitação diretamente na camada de rede 6.

Em vez de bloquear a solicitação, ad_status.jsela a ignora, mas carrega o tamanho de 0 bytes de anúncios do Google Ads . Esse truque engana o BlockAdBlock, porque onerrorfunciona apenas se a solicitação de rede falhar.



Versão 5 (março de 2016 - novembro de 2016)


Diferença do código fonte
v4 / v5

Proteção avançada: favoritos de spam


A única alteração nesta versão é que a segunda proteção estendida foi reescrita, embora ainda siga o mesmo princípio básico: verificar as solicitações de rede que serão bloqueadas pelo bloqueador. Mas agora os favoritos estão sendo carregados, em vez do AdSense.

Brave evita esse ataque da mesma maneira. Ele não bloqueia solicitações, mas cria imagens 1 × 1 falsas.

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
    };
}

A função baitImagespode ser chamada com freqüência, com um número aleatório de imagens, para ignorar bloqueadores estáticos.

Versão 6 (abril de 2016 - novembro de 2016): bloqueio corajoso



Diferença de código-fonte v5 / v6

Os métodos BlockAdBlock, embora simples à primeira vista, gradualmente se tornaram mais complexos e mais eficientes. Mas o último inimigo invicto permaneceu: o navegador Brave.

Proteção Avançada: Definindo um Favoricon Falsificado


Por que o BlockAdBlock mudou de tentativa de carregar um script para carregar imagens (favicons)? A resposta está no código adicionado à proteção por meio de favoritos de spam e ativado contra a proteção do Brave.

Verificando a resposta para uma imagem 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()
            }
        }
    };
}

Se o tamanho do favicon for menor que 8 × 8, provavelmente isso é falso no navegador Brave.

Com esse truque, o BlockAdBlock ignora o disfarce de Brave e outros bloqueadores que executam esse código (a maioria, como o uBlock Origin, bloqueia-o primeiro).

Após essa atualização, no final de novembro de 2016, o BlockAdBlock desapareceu da Internet. Embora seus “métodos avançados de segurança” funcionem, eles nunca foram ativados para a maioria dos usuários. Esta foi a última atualização. A última postagem no Twitter e no site foi publicada em algum lugar no final de 2017.

No entanto, o legado do BlockAdBlock continua vivo. Embora seja trivial bloqueá-lo atualmente, esse script ainda é usado por alguns sites modernos.

Conclusão


Quem vencerá a corrida armamentista entre bloqueadores de anúncios e anti-bloqueadores que bloqueiam anúncios? Só o tempo irá dizer. À medida que a corrida armamentista se desenvolve, os anti-bloqueadores terão que usar métodos mais sofisticados e códigos especiais, como mostra a evolução do BlockAdBlock.

Por outro lado, os bloqueadores têm a vantagem de sistemas estáveis ​​e poderosas ferramentas de filtragem por meio de listas de filtros, além de acesso ao JavaScript. Com esse sistema, basta uma pessoa entender como derrotar o inimigo - e atualizar a lista de filtros com novos sites.

Ao analisar a evolução do BlockAdBlock, bem como as várias respostas dos bloqueadores de anúncios, pudemos desenhar uma imagem de uma pequena guerra entre o BlockAdBlock e os bloqueadores. No processo, aprendemos quais métodos são usados ​​nas hostilidades.

Meu código de engenharia reversa é publicado no GitHub . Obrigado pela leitura.



1. Se você quiser ter uma idéia de como isso funciona, tente colar o exemplo abaixo no console JS e, em seguida, observe o código. Se você está interessado em seu funcionamento interno, aqui está o código fonte . Return [voltar]

2. Não acredita? Tente mudar evalpara console.logna primeira linha.
[para retornar]

3. O registro de data e hora diz 201510, então talvez outubro. Mas não sabemos quando o script mudou. Todos nós sabemos:

  • 2015-10, uma versão foi salva: 20151007203811.js
  • 2015-11, há uma nova versão: 20151113115955.js

Tanto quanto sabemos, o script pode ser alterado no dia anterior ao segundo registro de data e hora. Assim, eu abordo de forma conservadora o namoro. Return [voltar]

4. Durante a correção desse erro, foram desenvolvidos testes para a v1. Return [voltar]

5. Obrigado a McStroyer no Reddit, que chamou a atenção para isso. Return [voltar]

6. O componente Brave bloqueador de anúncios está aberto, para que possamos examinar o código-fonte para ter uma idéia de como ele funciona.


Agradecemos a François Marie por indicar o código fonte do Brave. Return [voltar]

All Articles