BlockAdBlock Advertising Anti-Blocking Reverse Engineering

Jika Anda menggunakan pemblokir iklan, Anda mungkin menemukan BlockAdBlock . Skrip ini mendeteksi pemblokir Anda dan tidak mengizinkannya untuk situs sampai Anda menonaktifkannya. Tapi saya bertanya-tanya bagaimana cara kerjanya. Bagaimana cara anti-blocker mendeteksi blocker? Dan bagaimana reaksi blocker terhadap ini dan bagaimana mereka memblokir anti-blocker?

Sejarah rekayasa terbalik


Hal pertama yang saya lakukan adalah melihat situs mereka . BlockAdBlock menawarkan konfigurator dengan pengaturan: interval tunggu dan bagaimana peringatan akan terlihat, menghasilkan versi skrip yang berbeda.

Ini membuat saya memikirkan versi. Bagaimana jika dia tidak bisa melihat satu versi, dan semua sekaligus? Jadi saya lakukan. Saya kembali ke masa lalu menggunakan Mesin Wayback . Setelah itu, saya mengunduh semua versi BlockAdBlock dan memotongnya.

Daftar semua versi BlockAdBlock, dengan 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

Hanya enam versi yang berbeda satu sama lain, dan yang terakhir merujuk ke 2016, meskipun beberapa situs masih menggunakan BlockAdBlock. Ini bagus, karena cukup bagi kita untuk merekayasa balik satu-satunya versi, dan kemudian membalikkan perbedaan. Spoiler: kita akan melihat pengembangan ide dan bahkan sisa-sisa kode debugging.

Saya memposting semua versi di GitHub . Jika Anda ingin melihat diff, maka dalam repositori ini setiap komit adalah versi baru.

Membongkar


Kode skrip tidak diperkecil, tetapi dikemas oleh JS-packer dari Dean Edwards dengan perubahan kosmetik dan tanpa modifikasi logika 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,{}))

Untungnya, ini bukan masalah bagi kami. Kelemahan dari pengepak adalah bahwa semua kode selama pembongkaran diteruskan ke eval(). Jika kita ganti eval()dengan sesuatu seperti console.log(), maka kita tiba-tiba mendapatkan semua kode sumber, dan pengepaknya dikalahkan 2.

Setelah melakukan ini untuk setiap versi, kita dapat memeriksa masing-masing dan melihat fungsi apa yang ditambahkan di sana dari waktu ke waktu.

v1 :? - November 2015: skrip awal


Kode Sumber

Mari kita mulai dengan sebuah penelitian yang 20151007203811.jsditerbitkan sekitar bulan November 2015 3. Meskipun versi pertama ini tidak memblokir pemblokir dengan baik, ini memungkinkan Anda untuk mengevaluasi arsitektur BlockAdBlock tanpa sampah yang telah terakumulasi selama bertahun-tahun.

Arsitektur


Dalam tiga kalimat:

  • BlockAdBlock adalah penutupan yang mengembalikan objek dengan tiga fungsi:
    • bab() mengatur umpan dan memanggil cek check
    • check() memeriksa apakah blocker telah memblokir umpan, menyebabkan arm
    • arm() hamparan
  • Titik masuk bab()kemudian mulai setelah jumlah waktu yang ditentukan.
  • Tiga fungsi dihasilkan dengan argumen yang diatur dalam konfigurator BlockAdBlock .

Kode ini dibangun di sekitar penutupan yang ditugaskan ke objek global dengan nama acak.

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

Penulis memberikan pengacakan menyeluruh untuk menghindari pemblokiran statis.

Kemudian mengembalikan sebuah objek dengan tiga fungsi: bab, checkdan arm.

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

Ini adalah nama saya sendiri. Semua variabel diperkecil, dan beberapa dikaburkan secara khusus.
Titik masuk bab()dipanggil melalui setTimeout().

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

bab_elementidtidak digunakan dalam versi kode apa pun. setTimeoutdisahkan sebagai string.

Penutupan memiliki variabel eksternal. Dua di antaranya digunakan untuk menyimpan status dalam skrip:

  • adblockDetected sama dengan 1 jika pemblokir iklan terdeteksi.
  • nagMode- Ini adalah opsi konfigurasi. Jika diinstal, maka skrip tidak memblokir akses ke halaman, tetapi hanya menyalakan Anda sekali.

Variabel lain untuk mengendalikan penampilan dan perilaku diatur dalam konfigurator .

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 atur di sini dalam upaya untuk mengaburkan domain BlockAdBlock.

bab: buat spanduk umpan


Metode utama bekerja dengan BlockAdBlock adalah membuat "umpan" atau "umpan" dari elemen iklan yang terlihat seperti spanduk nyata. Dia kemudian memeriksa untuk melihat apakah pemblokir mereka telah diblokir.

Ini menciptakan umpan: div palsu yang berpura-pura menjadi iklan tetapi tersembunyi dari pandangan.

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

Rupanya, itu passed_eiddimaksudkan untuk mengkonfigurasi pengidentifikasi umpan, tetapi tidak digunakan.

Setelah itu, diperiksa apakah umpan telah dihapus oleh unit iklan.

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

Jika umpan tidak ada lagi, maka elemen dihapus (dan kami memulai overlay).

Fungsi checkakan bekerja jika Predicatemengembalikan nilai true, dan itu dimulai arm.

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

Karena tes checkdipicu beberapa kali, seperti yang ditunjukkan di atas, itu adblockDetecteddiatur ke tes yang benar pertama untuk menghindari tersandung berulang arm.

Mode mendengus


Script memiliki fungsi yang disebut "mode nag": dalam mode ini, BlockAdBlock hanya akan mengatakan sekali untuk menonaktifkan pemblokir iklan, tetapi tidak akan memblokir Anda setiap kali Anda mengunjungi. Ini dilakukan dengan mengatur item localStoragepada kunjungan pertama.

Jika kita dapat menginstal elemen ini sendiri, bisakah kita menonaktifkan kunci selamanya? Sayangnya, BlockAdBlock memeriksa terlebih dahulu apakah skrip telah dikonfigurasi untuk mode nag, jadi metode ini tidak akan berfungsi ketika ia bekerja dalam mode default, yaitu dengan kunci akses.

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

Sayangnya, ini nagModedipasang di konfigurator, dan secara default sama 0.

BlockAdBlock versi 1


Pemblokir iklan menggunakan filter yang disebut: baris kode yang dapat memblokir permintaan jaringan dan menyembunyikan elemen pada halaman. Dengan membuat elemen umpan, BlockAdBlock secara khusus meluncurkan filter ini.

Dengan pertahanan sederhana ini, BlockAdBlock efektif terhadap semua pemblokir iklan utama seperti uBlock Origin, AdBlock Plus dan Ghostery. Untuk mengatasi ini, kita harus menulis filter kita sendiri, yang hanya diaktifkan di situs yang menjalankan BlockAdBlock.

Menulis filter untuk pemblokir agak rumit. Kami membutuhkan filter konten yang memblokir elemen pada halaman yang dihasilkan setelah memuat. Karena umpan memiliki pengidentifikasi banner_ad, kami membuat pengecualian untuk menyembunyikan elemenditandai #@#untuk semua elemen #dengan pengenal banner_addan memasukkannya ke dalam daftar filter pengguna dari pemblokir kami.

Hasilnya adalah sebagai berikut:

localhost#@# #banner_ad

Saya punya localhost di sini untuk demonstrasi, Anda dapat menggantinya dengan URL Anda.

Ini berhasil menonaktifkan BlockAdBlock. Solusinya mungkin tampak sederhana, tetapi telah lama berhasil bekerja di daftar filter Anti-AdBlock-Killer .

Versi 2 (November 2015 - Januari 2016): beberapa peningkatan


Perbedaan Kode Sumber
v1 / v2

Pembuatan Umpan: Lebih Sedikit Bug


Ada kesalahan yang tidak kentara di versi pertama pembuatan umpan: div yang dibuat tidak memiliki konten, sehingga div dibuat dengan ketinggian 0 dan lebar 0. Kemudian, kode memeriksa untuk melihat apakah div dihapus dengan memeriksa tinggi dan lebarnya. Tetapi karena ketinggiannya nol, BlockAdBlock selalu berfungsi 4.

Kesalahan dari div kosong sudah diperbaiki.

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

Div anak dibuat dengan beberapa konten.

Deteksi Blocker Melalui Spanduk Grafis Palsu


Dalam metode ini, kami membuat gambar palsu dengan nama acak menyala doubleclick.net. Pemblokir iklan akan memblokir gambar, menganggapnya spanduk iklan. Tetapi ini tidak memerlukan perubahan apa pun pada filter kami.

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

randomStr()menghasilkan string dengan panjang sewenang-wenang.

Perbedaan penting lainnya adalah penggunaan timer setIntervalalih-alih pemeriksaan satu kali sederhana untuk melihat apakah pemicu diinstal. Dia memeriksa ulang apakah spanduk grafis ditampilkan dan jika atributnya tidak diubah src, memeriksa isi umpan.

Baru setIntervaldan periksa ketersediaan gambar:

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

Mengapa indexof ('click')? Karena sumber gambar src="doubleclick.net/abcdefg.jpg"dan kami memeriksa apakah fragmen string tetap terjaga click.

Versi 3 (November 2015 - Maret 2016): umpan umum


Perbedaan Kode Sumber
v2 / v3

Pembuatan Umpan: Pengidentifikasi Acak


Satu-satunya perubahan dalam versi ini, meskipun signifikan, adalah munculnya pengidentifikasi acak untuk umpan. Pengidentifikasi baru diambil dari daftar pengidentifikasi saat memuat halaman dan digunakan untuk umpan, yang sekarang ditempatkan di tengah halaman.

Daftar panjang pengidentifikasi acak menunjukkan pengetahuan yang baik tentang bidang subjek.

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

Pembuatan ID acak


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

Karena ini berfungsi pada setiap boot, pengenal akan berbeda setiap saat.

BlockAdBlock, versi ketiga hingga terakhir


BlockAdBlock mengeksploitasi blind spot dari pemblokir iklan: jika filter melewatkan semua pengidentifikasi di atas, maka itu juga akan melewati iklan nyata. Dengan demikian, BlockAdBlock memaksa pemblokir iklan untuk membuat dirinya tidak berguna .

Di pemblokir, kita dapat mengeksekusi skrip arbitrer sebelum memuat halaman. Anda dapat mencoba untuk menghapus objek BlockAdBlock terlebih dahulu. Tetapi untuk ini kita perlu nama objek BlockAdBlock, yang diacak setiap kali dimulai.

uBlock Origin mengambil pendekatan yang berbeda. Karena kode dieksekusi oleh suatu fungsi eval, kita dapat mendefinisikan fungsi kita sendiri evalyang akan memblokir eksekusi jika kita menemukan BlockAdBlock. Di JS, objek mampu melakukan ini Proxy: Anda bisa mengganti properti dan metode apa pun di objek apa pun.

Ini dapat dielakkan dengan tidak melewati payload BlockAdBlock awal eval, tetapi menggunakannya secara langsung, jadi kami juga proksi titik masuk: panggilan setTimeout. Karena setTimeoutdilewatkan oleh string, bukan fungsi, kami memeriksa string ini.

Implementasi di Asal usullock ( sumber ):

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

Daftar Tanda Tangan: Menentukan Template Kode. Fungsi checkmemeriksa string setelah evaluntuk kepatuhan dengan pola-pola ini.

Selanjutnya, proksi fungsi evaldan 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);
        }
    }
});

Karena kita sekarang menggunakan skriplet , sebuah fragmen kode khusus yang dijalankan oleh pemblokir, filter berubah sedikit:

localhost## +js(nobab)

Ini tidak dimulai secara default di semua situs karena alasan kinerja, jadi Anda harus menetapkannya untuk setiap situs menggunakan skrip.

Versi 4 (Januari 2016 - April 2016): fungsi eksperimental



Perbedaan Kode Sumber v3 / v4

Metode yang dijelaskan untuk memblokir anti-blocker dikembangkan pada Januari 2016, sesuai dengan sejarah komitmen uBlock Origin , dan tidak berubah secara konseptual sejak awal. BlockAdBlock tidak pernah mencoba menyiasati filter ini dengan mengubah arsitekturnya. Sebaliknya, ia terus mengembangkan fitur-fitur baru. Dan ketika kita pergi ke halaman BlockAdBlock, kita melihat tab yang menarik: "Apakah Anda membutuhkan lebih banyak kekuatan anti-blocking?"



Meskipun metode perlindungan ini hanya tersedia melalui tab khusus, mereka termasuk dalam semua skrip dan dieksekusi melalui variabel dengan nama yang sesuai. Versi keempat mengimplementasikan dua metode:

  • aDefOne, "Perlindungan spesifik untuk situs adsense"
  • aDefTwo, "Fitur keamanan khusus"

Komentar debug acak


Sebelum mengucapkan selamat tinggal kepada Anda, saya harus menyebutkan satu hal lagi. Dalam proses reverse engineering, satu fungsi menarik perhatian saya:

Debugging console.log()tepat di kode!

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

Ini hanya dilakukan jika global consolelog, misalnya, diatur window.consolelog = 1.

Komentar debug hanya tersedia dalam versi ini. Jika saya tidak membalik semua versi, saya tidak akan pernah memperhatikan mereka. Mereka memberikan informasi berharga tentang cara kerja kode.

Keamanan Lanjutan: AdSense


Semua metode perlindungan khusus ini dikodekan dalam check, bukan di arm, seperti yang disarankan arsitektur. Mungkin pengembang baru yang tidak terbiasa dengan basis kode sudah mulai bekerja pada produk.

Jika AdSense aktif di halaman, maka kami memeriksa iklan. Jika mereka menghilang karena pemblokir, BlockAdBlock diaktifkan.

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

scriptExistsmemeriksa seluruh halaman untuk skrip dengan URL yang diberikan. Dalam hal ini, skrip AdSense 5.

URL skrip dibandingkan dengan semua skrip pada halaman. Untuk beberapa alasan, URL dipotong hingga 15 karakter.

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

Perlindungan Lanjutan: Elemen Khusus


Berbeda dengan yang pertama, metode ini disertai dengan penafian: "Silakan uji setelah instalasi untuk memastikan kompatibilitas dengan situs Anda."

Perlindungan khusus ini hanya berfungsi jika pemblokir tidak ditemukan dan tidak ada skrip AdSense di halaman. Berikut ini cuplikan kode yang relevan 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
                }
            }
        }
    }

Metode ini mengasumsikan bahwa pemilik situs hanya menggunakan AdSense: jika skrip AdSense tidak ada, maka ada sesuatu yang salah.

Mengapa ada peringatan? Metode ini mencoba mengaktifkan skrip AdSense. Jika tidak dimuat, maka kemungkinan besar pemblokir memblokir permintaan jaringan, oleh karena itu BlockAdBlock dipicu. Tetapi ini dapat merusak beberapa situs, karenanya peringatan.

Jika AdSense belum dimuat, hamparan dimulai.

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

Ketika terjadi kegagalan di tingkat jaringan, itu berfungsi onerrorseolah-olah pemblokir iklan berfungsi.

Memang, sebagian besar pemblokir iklan merespons hal ini dan memblokir permintaan. Tapi ada satu pemblokir yang belum saya sebutkan. Bicara tentang browser Brave .

Respons Browser yang Berani


Sejauh ini, kami telah mempelajari bagaimana anti-pemblokiran terdeteksi di uBlock Origin. Dan itu berhasil, hanya filter khusus yang diperlukan untuk setiap situs tempat BlockAdBlock diinstal. Browser Brave mengesankan karena mendeteksi dan mem-bypass BlockAdBlock dari semua versi tanpa ada tindakan yang diperlukan dari pihak pengguna. Untuk melakukan ini, ia memalsukan permintaan langsung di lapisan jaringan 6.

Alih-alih memblokir permintaan, ad_status.jsia melewatinya, tetapi memuat iklan Google palsu berukuran 0 byte . Trik rumit ini menipu BlockAdBlock, karena itu onerrorhanya berfungsi jika permintaan jaringan gagal.



Versi 5 (Maret 2016 - November 2016)


Perbedaan Kode Sumber
v4 / v5

Perlindungan lanjutan: favicons spam


Satu-satunya perubahan dalam versi ini adalah bahwa perlindungan tambahan yang kedua telah ditulis ulang, meskipun masih menganut prinsip dasar yang sama: memeriksa permintaan jaringan yang akan diblokir oleh pemblokir. Tapi sekarang favicon memuat bukan AdSense.

Berani menghindari serangan ini dengan cara yang sama. Itu tidak memblokir permintaan, tetapi membuat gambar 1 × 1 palsu.

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

Fungsi baitImagesini dapat sering dipanggil, dengan jumlah gambar acak, untuk mem-bypass pemblokir statis.

Versi 6 (April 2016 - November 2016): Kunci berani



Perbedaan Kode Sumber v5 / v6

Metode BlockAdBlock, meskipun sederhana pada pandangan pertama, secara bertahap menjadi lebih kompleks dan lebih efisien. Tetapi musuh terakhir yang tak terkalahkan tetap: browser Berani.

Perlindungan Tingkat Lanjut: Mendefinisikan Favoricon Palsu


Mengapa BlockAdBlock beralih dari mencoba memuat skrip ke memuat gambar (favicons)? Jawabannya ada dalam kode yang ditambahkan ke perlindungan melalui favicons spam, dan yang diaktifkan terhadap perlindungan Brave.

Memeriksa respons untuk gambar palsu:

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

Jika ukuran favicon kurang dari 8 × 8, maka ini mungkin palsu dari browser Brave.

Dengan trik ini, BlockAdBlock mem-bypass penyamaran Brave dan pemblokir lain yang menjalankan kode ini (kebanyakan, seperti uBlock Origin, blokir dulu).

Setelah pembaruan ini, sekitar akhir November 2016, BlockAdBlock menghilang dari Internet. Meskipun "metode keamanan canggih" mereka berfungsi, mereka tidak pernah diaktifkan untuk sebagian besar pengguna. Ini adalah pembaruan terakhir. Posting terakhir di Twitter dan di situs diterbitkan di suatu tempat pada akhir 2017.

Namun, warisan BlockAdBlock tetap hidup. Meskipun sepele untuk memblokirnya hari ini, skrip ini masih digunakan oleh beberapa situs modern.

Kesimpulan


Siapa yang akan memenangkan perlombaan senjata antara pemblokir iklan dan pemblokir anti yang memblokir pemblokir iklan? Hanya waktu yang akan memberitahu. Ketika perlombaan senjata berkembang, anti-blocker harus menggunakan metode yang lebih canggih dan kode khusus, seperti yang ditunjukkan oleh evolusi BlockAdBlock.

Di sisi lain, pemblokir memiliki keuntungan dari sistem yang stabil dan alat penyaringan yang kuat melalui daftar filter, serta akses ke JavaScript. Dengan sistem seperti itu, cukup bagi satu orang untuk memahami cara mengalahkan musuh - dan memperbarui daftar filter dengan situs baru.

Dengan menganalisis evolusi BlockAdBlock, serta berbagai respons pemblokir iklan, kami dapat melukiskan gambar perang kecil antara BlockAdBlock dan pemblokir. Dalam prosesnya, kami mempelajari metode apa yang digunakan dalam permusuhan.

Kode reverse engineering saya dipublikasikan di GitHub . Terima kasih telah membaca.



1. Jika Anda ingin mengetahui cara kerjanya, coba tempelkan contoh di bawah ini ke konsol JS, dan kemudian lihat kodenya. Jika Anda tertarik dengan pekerjaan batinnya, inilah kode sumbernya . [kembali]

2. Tidak percaya? Coba ubah evalke console.logpada baris pertama.
[mengembalikan]

3. Stempel waktu mengatakan 201510, jadi mungkin Oktober. Tetapi kita tidak tahu kapan naskahnya diubah. Semua yang kita tahu:

  • 2015-10, satu versi disimpan: 20151007203811.js
  • 2015-11 ada versi baru: 20151113115955.js

Sejauh yang kami tahu, skrip bisa diubah sehari sebelum cap waktu kedua. Jadi, saya secara konservatif mendekati kencan. [kembali]

4. Selama koreksi tes kesalahan ini dikembangkan untuk v1. [kembali]

5. Terima kasih kepada McStroyer di Reddit, yang menarik perhatian untuk ini. [kembali]

6. Komponen pemblokir iklan Berani terbuka, sehingga kita dapat melihat kode sumber untuk mendapatkan ide tentang cara kerjanya.


Terima kasih kepada François Marie karena menunjukkan kode sumber untuk Brave. [kembali]

All Articles