BlockAdBlock Werbung Anti-Blocking Reverse Engineering

Wenn Sie Werbeblocker verwenden, kann BlockAdBlock auftreten . Dieses Skript erkennt Ihren Blocker und lässt ihn erst dann auf der Site zu, wenn Sie ihn deaktivieren. Aber ich habe mich gefragt, wie es funktioniert. Wie erkennt Anti-Blocker Blocker? Und wie reagieren Blocker darauf und wie blockieren sie Anti-Blocker?

Geschichte des Reverse Engineering


Das erste, was ich tat, war einen Blick auf ihre Website . BlockAdBlock bietet einen Konfigurator mit Einstellungen: dem Warteintervall und dem Aussehen der Warnung, wodurch verschiedene Versionen des Skripts generiert werden .

Dies ließ mich an Versionen denken. Was ist, wenn er nicht eine Version sehen kann, und alles auf einmal? So tat ich. Ich bin mit der Wayback-Maschine in die Vergangenheit gereist . Danach habe ich alle Versionen von BlockAdBlock heruntergeladen und gehasht.

Liste aller Versionen von BlockAdBlock mit 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

Nur sechs Versionen unterscheiden sich voneinander, und die letzte bezieht sich auf 2016, obwohl einige Websites immer noch BlockAdBlock verwenden. Das ist großartig, denn es wird für uns ausreichen, die einzige Version zurückzuentwickeln und dann die Unterschiede umzukehren. Spoiler: Wir werden die Entwicklung von Ideen und sogar die Überreste von Debugging-Code sehen.

Ich habe alle Versionen auf GitHub gepostet . Wenn Sie sich Unterschiede ansehen möchten, ist in diesem Repository jedes Commit eine neue Version.

Auspacken


Der Skriptcode wird nicht minimiert, sondern von einem JS-Packer von Dean Edwards mit kosmetischen Änderungen und ohne Änderung der Logik 1 gepackt.

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,{}))

Zum Glück ist dies für uns kein Problem. Die Schwäche des Packers besteht darin, dass der gesamte Code beim Entpacken an übergeben wird eval(). Wenn wir durch so eval()etwas ersetzen console.log(), erhalten wir plötzlich den gesamten Quellcode und der Packer ist besiegt 2.

Nachdem wir dies für jede Version getan haben, können wir jede von ihnen untersuchen und sehen, welche Funktionen dort im Laufe der Zeit hinzugefügt wurden.

v1:? - November 2015: Erstes Drehbuch


Quellcode

Beginnen wir mit einer Studie, 20151007203811.jsdie um den November 2015 veröffentlicht wurde 3. Obwohl diese erste Version Blocker nicht sehr gut blockiert, können Sie die BlockAdBlock-Architektur ohne den Müll bewerten, der sich im Laufe der Jahre angesammelt hat.

Die Architektur


In drei Sätzen:

  • BlockAdBlock ist ein Abschluss, der ein Objekt mit drei Funktionen zurückgibt:
    • bab() setzt den Köder und ruft einen Scheck check
    • check() prüft, ob der Blocker den Köder blockiert hat, was dazu führt arm
    • arm() Overlay
  • Der Einstiegspunkt bab()beginnt dann nach einer bestimmten Zeit.
  • Drei Funktionen werden mit Argumenten generiert, die im BlockAdBlock-Konfigurator festgelegt sind .

Der Code basiert auf einem Abschluss, der einem globalen Objekt mit einem zufälligen Namen zugewiesen ist.

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

Der Autor sah eine gründliche Randomisierung vor, um statische Blockierungen zu umgehen.

Gibt dann ein Objekt mit drei Funktionen zurück : bab, checkund arm.

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

Das sind meine eigenen Namen. Alle Variablen werden minimiert und einige sind speziell verschleiert.
Der Einstiegspunkt wird bab()durchgerufen setTimeout().

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

bab_elementidwird in keiner Version des Codes verwendet. setTimeoutals Zeichenfolge übergeben.

Ein Abschluss hat externe Variablen. Zwei davon werden verwendet, um den Status in einem Skript zu speichern:

  • adblockDetected gleich 1, wenn ein Werbeblocker erkannt wird.
  • nagMode- Dies ist eine Konfigurationsoption. Wenn es installiert ist, blockiert das Skript den Zugriff auf die Seite nicht, sondern schaltet Sie nur einmal ein.

Weitere Variablen zur Steuerung von Erscheinungsbild und Verhalten werden im Konfigurator festgelegt .

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 Legen Sie hier fest, um die BlockAdBlock-Domäne zu verschleiern.

bab: erstelle ein Lockvogel-Banner


Die Hauptmethode für die Arbeit mit BlockAdBlock besteht darin, aus Werbeelementen, die wie echte Banner aussehen, „Köder“ oder „Köder“ zu erstellen. Dann prüft er, ob der Blocker blockiert ist.

Dies erzeugt einen Köder: ein gefälschter Div, der vorgibt, eine Anzeige zu sein, aber nicht sichtbar ist.

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

Anscheinend ist passed_eidbeabsichtigt, die Kennung des Köders zu konfigurieren, aber es wird nicht verwendet.

Danach wird geprüft, ob der Köder vom Anzeigenblock entfernt wurde.

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

Wenn der Köder nicht mehr existiert, wird das Element gelöscht (und wir starten die Überlagerung).

Die Funktion checkfunktioniert, wenn sie Predicateeinen Wert zurückgibt trueund startet arm.

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

Da der Test checkwie oben gezeigt mehrmals ausgelöst wird adblockDetected, wird er auf den ersten richtigen Test gesetzt, um ein wiederholtes Auslösen zu vermeiden arm.

Grunzmodus


Das Skript hat eine Funktion namens "Nag-Modus": In diesem Modus sagt BlockAdBlock nur einmal, dass der Werbeblocker deaktiviert werden soll, blockiert Sie jedoch nicht bei jedem Besuch. Dies erfolgt durch Einstellen des Elements localStoragebeim ersten Besuch.

Wenn wir dieses Element selbst installieren könnten, könnten wir die Sperre für immer deaktivieren? Leider prüft BlockAdBlock im Voraus, ob das Skript für den Nag-Modus konfiguriert wurde, sodass diese Methode nicht funktioniert, wenn sie im Standardmodus, dh mit Zugriffssperre, arbeitet.

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

Leider ist es nagModeim Konfigurator installiert und standardmäßig gleich 0.

BlockAdBlock Version 1


Werbeblocker verwenden sogenannte Filter: Codezeilen, die Netzwerkanforderungen blockieren und Elemente auf der Seite ausblenden können. Durch das Erstellen von Köderelementen startet BlockAdBlock diese Filter speziell.

Mit dieser einfachen Verteidigung ist BlockAdBlock gegen alle wichtigen Werbeblocker wie uBlock Origin, AdBlock Plus und Ghostery wirksam. Um dem entgegenzuwirken, müssen wir unseren eigenen Filter schreiben, der nur auf Sites aktiviert wird, auf denen BlockAdBlock ausgeführt wird.

Das Schreiben von Filtern für einen Blocker ist etwas kompliziert. Wir benötigen einen Inhaltsfilter , der Elemente auf der Seite blockiert, die nach dem Laden generiert wurden. Da der Köder eine Kennung hat banner_ad, erstellen wir eine Ausnahme, um Elemente auszublendenmarkiert #@#für alle Elemente #mit einem Bezeichner banner_adund fügt ihn in die Liste der Benutzerfilter unseres Blockers ein.

Das Ergebnis ist folgendes:

localhost#@# #banner_ad

Ich habe localhost hier zur Demonstration, Sie können es durch Ihre URL ersetzen.

Dadurch wird BlockAdBlock erfolgreich deaktiviert. Die Lösung mag einfach erscheinen, funktioniert aber seit langem erfolgreich in der Anti-AdBlock-Killer-Filterliste .

Version 2 (November 2015 - Januar 2016): mehrere Verbesserungen


Quellcodedifferenz
v1 / v2

Ködererstellung: Weniger Bugs


In der ersten Version des Erstellens des Köders gibt es einen subtilen Fehler: Das erstellte Div hat keinen Inhalt, daher wird ein Div mit einer Höhe von 0 und einer Breite von 0 generiert. Später prüft der Code, ob das Div gelöscht wird, indem seine Höhe und Breite überprüft werden. Da BlockAdBlock jedoch keine Höhe hatte, funktionierte es immer 4.

Der Fehler eines leeren Div ist behoben.

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

Ein untergeordnetes Div wird mit einigen Inhalten erstellt.

Blockererkennung durch gefälschte Grafikbanner


Bei dieser Methode erstellen wir ein gefälschtes Bild mit einem zufälligen Namen doubleclick.net. Werbeblocker blockieren das Bild und denken, es sei ein Werbebanner. Dies erfordert jedoch keine Änderungen an unserem Filter.

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

randomStr()generiert eine Zeichenfolge beliebiger Länge.

Ein weiterer bemerkenswerter Unterschied war die Verwendung eines Timers setIntervalanstelle einer einfachen einmaligen Überprüfung, ob ein Trigger installiert ist. Er überprüft erneut, ob das Grafikbanner angezeigt wird und ob sein Attribut nicht geändert wird src, und überprüft den Inhalt des Köders.

Neu setIntervalund auf Bildverfügbarkeit prüfen:

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

Warum indexof ('click')? Weil die Quelle des Bildes src="doubleclick.net/abcdefg.jpg"und wir prüfen, ob das Fragment der Zeichenfolge erhalten bleibt click.

Version 3 (November 2015 - März 2016): generalisierter Köder


Quellcodedifferenz
v2 / v3

Ködererstellung: Zufällige Identifikatoren


Die einzige Änderung in dieser Version, obwohl signifikant, ist das Auftreten von zufälligen Identifikatoren für den Köder. Der neue Bezeichner wird beim Laden der Seite aus der Liste der Bezeichner entnommen und für den Köder verwendet, der jetzt in der Mitte der Seite platziert wird.

Eine lange Liste von Zufallskennungen zeigt eine gute Kenntnis des Themenbereichs.

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

Zufällige ID-Generierung


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

Da dies bei jedem Start funktioniert, ist die Kennung jedes Mal anders.

BlockAdBlock, drittletzte Version


BlockAdBlock nutzt den blinden Fleck von Werbeblockern aus: Wenn ein Filter alle oben genannten Kennungen überspringt, werden auch echte Anzeigen übersprungen. Daher zwingt BlockAdBlock den Werbeblocker , sich selbst unbrauchbar zu machen .

In Blockern können wir vor dem Laden der Seite beliebige Skripte ausführen. Sie können versuchen, das BlockAdBlock-Objekt im Voraus zu entfernen. Dafür benötigen wir jedoch den Namen des BlockAdBlock-Objekts, das bei jedem Start zufällig ausgewählt wird.

uBlock Origin verfolgte einen anderen Ansatz. Da der Code von einer Funktion ausgeführt wird eval, können wir unsere eigene Funktion definieren eval, die die Ausführung blockiert, wenn wir BlockAdBlock finden. In JS ist ein Objekt dazu in der Lage Proxy: Sie können jede Eigenschaft und Methode in jedem Objekt ersetzen.

Dies kann umgangen werden, indem die anfängliche BlockAdBlock-Nutzlast nicht weitergeleitet eval, sondern direkt verwendet wird, sodass wir auch den Einstiegspunkt als Proxy verwenden: den Aufruf setTimeout. Da es setTimeoutvon einer Zeichenfolge und nicht von einer Funktion übergeben wird, überprüfen wir diese Zeichenfolge.

Implementierung in uBlock Origin ( Quelle ):

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

Signaturliste: Definieren von Codevorlagen. Die Funktion checküberprüft die Zeichenfolge anschließend evalauf Übereinstimmung mit diesen Mustern.

Als nächstes Proxy die Funktionen evalund 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);
        }
    }
});

Da wir jetzt ein Scriptlet verwenden , ein spezielles benutzerdefiniertes Codefragment, das vom Blocker ausgeführt wird, ändert sich der Filter ein wenig:

localhost## +js(nobab)

Es wird aus Leistungsgründen nicht standardmäßig auf allen Sites gestartet, daher müssen Sie es jeder Site mithilfe eines Skripts zuweisen.

Version 4 (Januar 2016 - April 2016): experimentelle Funktionen


Quellcode-
Unterschied v3 / v4

Die beschriebene Methode zum Blockieren von Anti-Blockern wurde im Januar 2016 gemäß der Historie der uBlock Origin-Commits entwickelt und hat sich seit ihrer Einführung konzeptionell nicht geändert. BlockAdBlock hat nie versucht, diesen Filter zu umgehen, indem er seine Architektur geändert hat. Stattdessen entwickelte er weiterhin neue Funktionen. Und wenn wir zur BlockAdBlock-Seite gehen, sehen wir eine interessante Registerkarte: "Benötigen Sie mehr Anti-Blocking-Leistung?"



Obwohl diese Schutzmethoden nur über eine spezielle Registerkarte verfügbar sind, sind sie in allen Skripten enthalten und werden über Variablen mit den entsprechenden Namen ausgeführt. Die vierte Version implementiert zwei Methoden:

  • aDefOne, "Spezifischer Schutz für Adsense-Sites"
  • aDefTwo, "Spezielle Sicherheitsfunktion"

Zufällige Debug-Kommentare


Bevor ich mich von Ihnen verabschiede, muss ich noch etwas erwähnen. Beim Reverse Engineering fiel mir eine Funktion auf:

Debuggen console.log()direkt im Code!

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

Dies erfolgt nur, wenn beispielsweise global consolelogeingestellt ist window.consolelog = 1.

Debug-Kommentare sind nur in dieser Version verfügbar. Wenn ich nicht alle Versionen umgekehrt hätte, hätte ich sie nie bemerkt. Sie liefern wertvolle Informationen zur Funktionsweise des Codes.

Erweiterte Sicherheit: AdSense


Alle diese speziellen Schutzmethoden sind in checkund nicht in codiert arm, wie es die Architektur vorschlägt. Möglicherweise hat ein neuer Entwickler, der mit der Codebasis nicht vertraut ist, begonnen, an dem Produkt zu arbeiten.

Wenn AdSense auf der Seite aktiv ist, suchen wir nach Anzeigen. Wenn sie aufgrund eines Blockers verschwunden sind, wird BlockAdBlock aktiviert.

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

scriptExistsÜberprüft die gesamte Seite auf ein Skript mit einer bestimmten URL. In diesem Fall das AdSense 5- Skript.

Die URL des Skripts wird mit allen Skripten auf der Seite verglichen. Aus irgendeinem Grund wird die URL auf 15 Zeichen gekürzt.

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

Erweiterter Schutz: Spezielles Element


Im Gegensatz zur ersten Methode wird diese Methode von einem Haftungsausschluss begleitet: "Bitte testen Sie nach der Installation, um die Kompatibilität mit Ihrer Site sicherzustellen."

Dieser spezielle Schutz funktioniert nur, wenn kein Blocker gefunden wird und auf der Seite kein AdSense-Skript vorhanden ist. Hier ist das relevante Code-Snippet 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
                }
            }
        }
    }

Bei dieser Methode wird davon ausgegangen, dass Websitebesitzer nur AdSense verwenden. Wenn kein AdSense-Skript vorhanden ist, stimmt etwas nicht.

Warum gab es eine Warnung? Diese Methode versucht, das AdSense-Skript zu aktivieren. Wenn es nicht geladen wird, hat der Blocker höchstwahrscheinlich die Netzwerkanforderung blockiert, daher wird BlockAdBlock ausgelöst. Dies kann jedoch einige Websites ruinieren, daher die Warnung.

Wenn AdSense nicht geladen wurde, wird das Overlay gestartet.

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

Wenn auf Netzwerkebene ein Fehler auftritt, funktioniert dies so, onerrorals würde ein Werbeblocker funktionieren.

In der Tat reagieren die meisten Werbeblocker darauf und blockieren die Anfrage. Aber es gibt einen Blocker, den ich noch nicht erwähnt habe. Sprechen Sie über den Brave-Browser .

Mutige Browser-Antwort


Bisher haben wir untersucht, wie Anti-Blocking in uBlock Origin erkannt wird. Und es funktioniert, für jeden Standort, an dem BlockAdBlock installiert ist, ist nur ein bestimmter Filter erforderlich. Der Brave-Browser ist insofern beeindruckend, als er BlockAdBlock aller Versionen erkennt und umgeht, ohne dass der Benutzer etwas unternehmen muss. Dazu fälscht er die Anfrage direkt auf der Netzwerkebene 6.

Anstatt die Anforderung zu blockieren, wird ad_status.jssie übersprungen, aber gefälschte Google Ads mit einer Größe von 0 Byte geladen . Dieser knifflige Trick täuscht BlockAdBlock vor, da er onerrornur funktioniert, wenn die Netzwerkanforderung fehlschlägt.



Version 5 (März 2016 - November 2016)


Quellcodedifferenz
v4 / v5

Erweiterter Schutz: Spam-Favoriten


Die einzige Änderung in dieser Version besteht darin, dass der zweite erweiterte Schutz neu geschrieben wurde, obwohl er immer noch dem gleichen Grundprinzip entspricht: Überprüfen von Netzwerkanforderungen, die vom Blocker blockiert werden. Aber jetzt werden Favicons anstelle von AdSense geladen.

Brave weicht diesem Angriff auf die gleiche Weise aus. Es blockiert keine Anforderungen, sondern erstellt gefälschte 1 × 1-Bilder.

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

Die Funktion baitImageskann häufig mit einer zufälligen Anzahl von Bildern aufgerufen werden, um statische Blocker zu umgehen.

Version 6 (April 2016 - November 2016): Tapferes Schloss


Quellcodeunterschied
v5 / v6

BlockAdBlock-Methoden waren zwar auf den ersten Blick einfach, wurden jedoch allmählich komplexer und effizienter. Aber der letzte unbesiegte Feind blieb: der tapfere Browser.

Erweiterter Schutz: Definieren eines gefälschten Favoricon


Warum hat BlockAdBlock vom Versuch, ein Skript zu laden, zum Laden von Bildern (Favicons) gewechselt? Die Antwort befindet sich in dem Code, der dem Schutz durch Spam-Favoriten hinzugefügt wird und der gegen den Schutz von Brave aktiviert ist.

Überprüfen der Antwort auf ein falsches Bild:

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

Wenn die Favicon-Größe weniger als 8 × 8 beträgt, handelt es sich wahrscheinlich um eine Fälschung des Brave-Browsers.

Mit diesem Trick umgeht BlockAdBlock die Verkleidung von Brave und anderen Blockern, die diesen Code ausführen (die meisten, wie uBlock Origin, blockieren ihn zuerst).

Nach diesem Update verschwand BlockAdBlock Ende November 2016 aus dem Internet. Obwohl ihre "erweiterten Sicherheitsmethoden" funktionieren, wurden sie für die meisten Benutzer nie aktiviert. Dies war das letzte Update. Der letzte Beitrag auf Twitter und auf der Website wurde Ende 2017 veröffentlicht.

Das Erbe von BlockAdBlock lebt jedoch weiter. Obwohl es heutzutage trivial ist, es zu blockieren, wird dieses Skript immer noch von einigen modernen Websites verwendet.

Fazit


Wer gewinnt das Wettrüsten zwischen Werbeblockern und Anti-Blockern, die Werbeblocker blockieren? Nur die Zeit kann es verraten. Während sich das Wettrüsten entwickelt, müssen Anti-Blocker ausgefeiltere Methoden und speziellen Code verwenden, wie die Entwicklung von BlockAdBlock zeigt.

Auf der anderen Seite haben Blocker den Vorteil stabiler Systeme und leistungsstarker Filterwerkzeuge durch Filterlisten sowie des Zugriffs auf JavaScript. Mit einem solchen System reicht es aus, wenn eine Person versteht, wie man den Feind besiegt - und die Filterliste mit neuen Sites aktualisiert.

Durch die Analyse der Entwicklung von BlockAdBlock sowie der verschiedenen Reaktionen von Werbeblockern konnten wir ein Bild eines kleinen Krieges zwischen BlockAdBlock und Blockern zeichnen. Dabei haben wir gelernt, welche Methoden bei Feindseligkeiten eingesetzt werden.

Mein Reverse Engineering Code wird auf GitHub veröffentlicht . Danke fürs Lesen.



1. Wenn Sie sich ein Bild davon machen möchten, wie dies funktioniert, fügen Sie das folgende Beispiel in die JS-Konsole ein und sehen Sie sich dann den Code an. Wenn Sie an seinem Innenleben interessiert sind, finden Sie hier den Quellcode . [zurück]

2. Glaubst du nicht? Versuchen Sie eval, console.login der ersten Zeile zu wechseln .
[zurückgeben]

3. Der Zeitstempel sagt 201510, also vielleicht Oktober. Wir wissen jedoch nicht, wann sich das Skript geändert hat. Alles was wir wissen:

  • 2015-10 wurde eine Version gespeichert: 20151007203811.js
  • 2015-11 gibt es eine neue Version: 20151113115955.js

Soweit wir wissen, könnte das Skript am Tag vor dem zweiten Zeitstempel geändert werden. Daher gehe ich konservativ mit Dating um. [zurück]

4. Während der Korrektur dieses Fehlers wurden Tests für v1 entwickelt. [zurück]

5. Vielen Dank an McStroyer auf Reddit, der darauf aufmerksam gemacht hat. [zurück]

6. Die Brave Ad Blocker-Komponente ist geöffnet, sodass wir uns den Quellcode ansehen können, um eine Vorstellung davon zu bekommen, wie er funktioniert.


Vielen Dank an François Marie für den Hinweis auf den Quellcode für Brave. [zurück]

All Articles