هندسة BlockAdBlock للإعلانات المضادة للحظر العكسي

إذا كنت تستخدم حاصرات الإعلانات ، فقد تواجه BlockAdBlock . يكتشف هذا النص البرمجي مانعك ولا يسمح له بالدخول إلى الموقع حتى تقوم بتعطيله. لكنني تساءلت كيف يعمل. كيف يكتشف مضاد الحاصرات الحاصرات؟ وكيف تتفاعل الحاصرات مع هذا وكيف تحجب مضادات الحجب؟

تاريخ الهندسة العكسية


أول شيء فعلته هو النظر إلى موقعهم . يقدم BlockAdBlock أداة تكوين مع الإعدادات: فترة الانتظار وكيف سيبدو التحذير ، وإنشاء إصدارات مختلفة من البرنامج النصي.

هذا جعلني أفكر في الإصدارات. ماذا لو لم يتمكن من رؤية نسخة واحدة ، وكل ذلك دفعة واحدة؟ لذلك أنا فعلت. عدت في الوقت المناسب باستخدام آلة Wayback . بعد ذلك ، قمت بتنزيل جميع إصدارات BlockAdBlock وتجزئتها.

قائمة بجميع إصدارات BlockAdBlock مع sha1sum


6d5eafab2ca816ccd049ad8f796358c0a7a43cf3 20151007203811.js
065b4aa813b219abbce76ad20a3216b3481b11bb 20151113115955.js
d5dec97a775b2e563f3e4359e4f8f1c3645ba0e5 20160121132336.js
8ad06cbb79bc25114bd7a2083067ceea9fbb354 20160318193101.js
8add06cbb79bc25114bd7a2083067ceea9fbb354 20160319042810.js
8ad06cbb79bc25114bd7a2083067ceea9fbb354 20160331051645.js
8add06cbb79bc25114bd7a2083067ceea9fbb354 20160406061855.js
8ad06cbb79bc25114bd7a2083067ceea9fbb354 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

تختلف ستة إصدارات فقط عن بعضها البعض ، وآخرها يشير إلى عام 2016 ، على الرغم من أن بعض المواقع لا تزال تستخدم BlockAdBlock. هذا أمر رائع ، لأنه سيكون كافياً بالنسبة لنا لإجراء هندسة عكسية للإصدار الوحيد ، ثم عكس الاختلافات. المفسد: سنرى تطور الأفكار وحتى بقايا رمز التصحيح.

لقد نشرت جميع الإصدارات على GitHub . إذا كنت تريد إلقاء نظرة على الاختلافات ، فإن كل التزام في هذا المستودع هو إصدار جديد.

تفريغ


لم يتم تصغير كود البرنامج النصي ، ولكن تم تعبئته بواسطة JS-packer من Dean Edwards مع تغييرات تجميلية ودون أي تعديل في المنطق 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,{}))

لحسن الحظ ، هذه ليست مشكلة بالنسبة لنا. ضعف المعبئ هو أنه يتم تمرير جميع التعليمات البرمجية أثناء التفريغ إلى eval(). إذا استبدلنا eval()شيئًا مثل console.log()، فجأة نحصل على كل كود المصدر ، وهزم المعبئ 2.

بعد القيام بذلك لكل إصدار ، يمكننا فحص كل منها ومعرفة الوظائف التي تمت إضافتها هناك بمرور الوقت.

v1:؟ - نوفمبر 2015: النص الأولي


كود المصدر

لنبدأ بدراسة 20151007203811.jsنشرت في نوفمبر 2015 3. على الرغم من أن هذا الإصدار الأول لا يمنع الحاصرات بشكل جيد للغاية ، إلا أنه يسمح لك بتقييم بنية BlockAdBlock دون القمامة التي تراكمت على مر السنين.

هندسة معمارية


في ثلاث جمل:

  • BlockAdBlock هو إغلاق يقوم بإرجاع كائن بثلاث وظائف:
    • bab() يضع الطعم ويستدعي الشيك check
    • check() يتحقق مما إذا كان مانع انسداد الطعم ، مما تسبب arm
    • arm() تراكب
  • bab()ثم تبدأ نقطة الدخول بعد فترة زمنية محددة.
  • يتم إنشاء ثلاث وظائف مع وسيطات تم تعيينها في مكون BlockAdBlock .

تم بناء الكود حول إغلاق مخصص لكائن عمومي باسم عشوائي.

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

قدم المؤلف للعشوائية الشاملة للتحايل على حظر ثابت.

ثم يعود كائن مع ثلاث وظائف: bab، checkو arm.

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

هذه اسمي الخاص يتم تصغير جميع المتغيرات ، وبعضها مشوش بشكل خاص.
يتم bab()استدعاء نقطة الدخول من خلال setTimeout().

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

bab_elementidلا تستخدم في أي نسخة من التعليمات البرمجية. setTimeoutمرت كسلسلة.

يحتوي الإغلاق على متغيرات خارجية. يتم استخدام اثنين منهم لحفظ الحالة في برنامج نصي:

  • adblockDetected يساوي 1 إذا تم الكشف عن مانع الإعلانات.
  • nagMode- هذا خيار تكوين. إذا تم تثبيته ، فإن البرنامج النصي لا يمنع الوصول إلى الصفحة ، ولكنه يقوم بتشغيلك مرة واحدة فقط.

يتم ضبط المتغيرات الأخرى للتحكم في المظهر والسلوك في المكون .

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 تعيين هنا في محاولة للتعتيم على مجال BlockAdBlock.

bab: إنشاء لافتة شرك


الطريقة الرئيسية للعمل مع BlockAdBlock هي إنشاء "طعم" أو "طعم" من عناصر إعلانية تشبه لافتات حقيقية. ثم يتحقق للتحقق مما إذا كان مانعهم قد تم حظره.

هذا يخلق خداعًا: فرقة وهمية تتظاهر بأنها إعلان ولكنها مخفية عن الأنظار.

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

على ما يبدو ، passed_eidالغرض منه هو تكوين معرف الطعم ، ولكن لا يتم استخدامه.

بعد ذلك ، يتم التحقق مما إذا كانت الوحدة الإعلانية قد أزالت الطعم.

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

إذا لم يعد الطعم موجودًا ، فسيتم حذف العنصر (ونبدأ التراكب). ستعمل

الوظيفة checkإذا قامت Predicateبإرجاع قيمة true، وتبدأ arm.

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

نظرًا لأنه يتم checkتشغيل الاختبار عدة مرات ، كما هو موضح أعلاه ، يتم adblockDetectedتعيينه على الاختبار الصحيح الأول لتجنب التعثر المتكرر arm.

وضع النخر


يحتوي النص البرمجي على وظيفة تسمى "وضع nag": في هذا الوضع ، سيقول BlockAdBlock مرة واحدة فقط لتعطيل مانع الإعلانات ، ولكنه لن يمنعك في كل مرة تزور فيها. يتم ذلك عن طريق تعيين العنصر localStorageفي الزيارة الأولى.

إذا تمكنا من تثبيت هذا العنصر بأنفسنا ، فهل يمكننا تعطيل القفل إلى الأبد؟ لسوء الحظ ، يتحقق BlockAdBlock مقدمًا مما إذا تم تكوين البرنامج النصي لوضع تذمر ، وبالتالي لن تعمل هذه الطريقة عندما تعمل في الوضع الافتراضي ، أي مع قفل الوصول.

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

لسوء الحظ ، يتم nagModeتثبيته في المكوّن ، وهو متساوي افتراضيًا 0.

الإصدار BlockAdBlock 1


تستخدم أدوات حظر الإعلانات ما يسمى بالفلاتر: أسطر التعليمات البرمجية التي يمكنها حظر طلبات الشبكة وإخفاء العناصر الموجودة على الصفحة. من خلال إنشاء عناصر الطعم ، يقوم BlockAdBlock بتشغيل هذه الفلاتر على وجه التحديد.

مع هذا الدفاع البسيط ، فإن BlockAdBlock فعال ضد جميع حاصرات الإعلانات الرئيسية مثل uBlock Origin و AdBlock Plus و Ghostery. لمواجهة هذا ، يجب أن نكتب عامل التصفية الخاص بنا ، والذي يتم تنشيطه فقط على المواقع التي تقوم بتشغيل BlockAdBlock.

تعد كتابة الفلاتر لحاجب معقد بعض الشيء. نحتاج إلى فلتر محتوى يمنع العناصر الموجودة على الصفحة التي تم إنشاؤها بعد التحميل. نظرًا لأن الطُعم يحتوي على معرف banner_ad، فإننا ننشئ استثناءً لإخفاء العناصرتم وضع علامة #@#على جميع العناصر #ذات المعرف banner_adووضعها في قائمة فلاتر المستخدم لحاجبنا.

والنتيجة هي ما يلي:

localhost#@# #banner_ad

لدي مضيف محلي هنا للتوضيح ، يمكنك استبداله بعنوان URL الخاص بك.

يؤدي هذا إلى إلغاء تنشيط BlockAdBlock بنجاح. قد يبدو الحل بسيطًا ، ولكنه يعمل منذ فترة طويلة بنجاح في قائمة التصفية Anti-AdBlock-Killer .

الإصدار 2 (نوفمبر 2015 - يناير 2016): العديد من التحسينات


فرق كود المصدر
v1 / v2

إنشاء الطعم: البق أقل


يوجد خطأ دقيق في الإصدار الأول من إنشاء الطُعم: لا يحتوي div الذي تم إنشاؤه على محتوى ، لذلك يتم إنشاء div بارتفاع 0 وعرض 0. في وقت لاحق ، يتحقق الرمز لمعرفة ما إذا تم حذف div بالتحقق من ارتفاعه وعرضه. ولكن نظرًا لكونه لا يساوي ارتفاعًا ، عمل BlockAdBlock دائمًا 4.

تم إصلاح خطأ div فارغ.

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

يتم إنشاء div طفل مع بعض المحتوى.

الكشف عن مانع من خلال لافتات الرسم وهمية


في هذه الطريقة ، نقوم بإنشاء صورة وهمية باسم عشوائي doubleclick.net. ستقوم حاصرات الإعلانات بحظر الصورة ، معتقدة أنها لافتة إعلانية. لكن هذا لا يتطلب أي تغييرات على مرشحنا.

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

randomStr()يولد سلسلة من الطول التعسفي.

اختلاف آخر ملحوظ هو استخدام المؤقت setIntervalبدلاً من الاختيار البسيط لمرة واحدة لمعرفة ما إذا كان المشغل مثبتًا أم لا. يعيد فحص ما إذا كان الشعار الرسومي معروضًا وإذا لم يتم تغيير srcصفته ، يتحقق من محتويات الطعم.

جديد setIntervalوتحقق من توفر الصورة:

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

لماذا indexof ('click')؟ لأن مصدر الصورة src="doubleclick.net/abcdefg.jpg"ونتحقق مما إذا كان جزء من السلسلة محفوظًا click.

الإصدار 3 (نوفمبر 2015 - مارس 2016): الطعم المعمم


فرق كود المصدر
v2 / v3

إنشاء الطعم: معرفات عشوائية


التغيير الوحيد في هذا الإصدار ، على الرغم من أهميته ، هو ظهور معرفات عشوائية للطُعم. يتم أخذ المعرف الجديد من قائمة المعرفات عند تحميل الصفحة ويتم استخدامه للطعم ، والذي يتم وضعه الآن في منتصف الصفحة.

توضح قائمة طويلة من المعرّفات العشوائية معرفة جيدة بموضوع الموضوع.

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

إنشاء معرف عشوائي


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

نظرًا لأن هذا يعمل على كل تمهيد ، فسيختلف المعرف في كل مرة.

BlockAdBlock ، الإصدار الثالث إلى الإصدار الأخير


يستغل BlockAdBlock النقطة العمياء لحاصرات الإعلانات: إذا تخطى المرشح جميع المعرّفات المذكورة أعلاه ، فإنه سيتخطى أيضًا الإعلانات الحقيقية. وبالتالي ، يجبر BlockAdBlock مانع الإعلانات على جعل نفسه عديم الفائدة .

في الحاصرات ، يمكننا تنفيذ نصوص عشوائية قبل تحميل الصفحة. يمكنك محاولة إزالة كائن BlockAdBlock مقدمًا. ولكن لهذا نحن بحاجة إلى اسم كائن BlockAdBlock ، والذي يتم اختياره عشوائيًا في كل مرة يبدأ فيها.

اتخذ uBlock Origin نهجًا مختلفًا. نظرًا لأنه يتم تنفيذ الشفرة بواسطة وظيفة eval، يمكننا تحديد evalوظيفتنا الخاصة التي ستمنع التنفيذ إذا وجدنا BlockAdBlock. في JS ، يكون الكائن قادرًا على ذلك Proxy: يمكنك استبدال أي خاصية وطريقة في أي كائن.

يمكن التحايل على هذا من خلال عدم تمرير حمولة BlockAdBlock الأولية eval، ولكن باستخدامها مباشرةً ، لذلك فإننا أيضًا ندير نقطة الدخول: المكالمة setTimeout. نظرًا لأنه يتم setTimeoutتمريره بسلسلة ، وليس دالة ، فإننا نتحقق من هذه السلسلة.

التنفيذ في uBlock Origin ( المصدر ):

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

قائمة التوقيع: تحديد قوالب الكود. checkتتحقق الوظيفة من السلسلة بعد evalالامتثال لهذه الأنماط.

بعد ذلك ، وكيل وظائف evalو 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);
        }
    }
});

نظرًا لأننا نستخدم الآن نصًا برمجيًا ، وهو جزء من رمز مخصص خاص يتم تنفيذه بواسطة أداة الحظر ، يتغير الفلتر قليلاً:

localhost## +js(nobab)

لا يبدأ بشكل افتراضي في جميع المواقع لأسباب تتعلق بالأداء ، لذلك تحتاج إلى تعيينه لكل موقع باستخدام برنامج نصي.

الإصدار 4 (يناير 2016 - أبريل 2016): الوظائف التجريبية



اختلاف شفرة المصدر v3 / v4

تم تطوير الطريقة الموضحة لحظر مضادات الحجب في يناير 2016 ، وفقًا لتاريخ عمليات uBlock Origin ، ولم تتغير من الناحية المفاهيمية منذ إنشائها. لم يحاول BlockAdBlock أبدًا الالتفاف على هذا الفلتر بتغيير بنيته. بدلاً من ذلك ، واصل تطوير ميزات جديدة. وعندما نذهب إلى صفحة BlockAdBlock ، نرى علامة تبويب مثيرة للاهتمام: "هل تحتاج إلى المزيد من الطاقة المضادة للحظر؟"



على الرغم من أن طرق الحماية هذه متاحة فقط من خلال علامة تبويب خاصة ، إلا أنها مدرجة في جميع البرامج النصية ويتم تنفيذها من خلال المتغيرات ذات الأسماء المقابلة. الإصدار الرابع يطبق طريقتين:

  • aDefOne، "حماية خاصة لمواقع adsense"
  • aDefTwo، "ميزة أمنية خاصة"

تعليقات تصحيح عشوائي


قبل أن أودعك ، يجب أن أذكر شيئًا آخر. في عملية الهندسة العكسية ، لفتت انتباهي وظيفة واحدة:

تصحيح الأخطاء console.log()في التعليمات البرمجية!

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

يتم ذلك فقط إذا تم تعيين عالمي consolelog، على سبيل المثال window.consolelog = 1.

تعليقات التصحيح متاحة فقط في هذا الإصدار. إذا لم أقم بإلغاء جميع الإصدارات ، لما لاحظتها أبدًا. أنها توفر معلومات قيمة حول كيفية عمل التعليمات البرمجية.

الأمان المتقدم: AdSense


يتم ترميز جميع طرق الحماية الخاصة هذه check، وليس في arm، كما تقترح الهندسة المعمارية. ربما بدأ مطور جديد ليس على دراية بقاعدة الكود العمل على المنتج.

إذا كان AdSense نشطًا على الصفحة ، فإننا نتحقق من الإعلانات. إذا اختفت بسبب مانع ، يتم تنشيط BlockAdBlock.

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يتحقق من الصفحة بأكملها بحثًا عن نص برمجي بعنوان URL معين. في هذه الحالة ، برنامج AdSense 5 النصي.

تتم مقارنة عنوان URL الخاص بالبرنامج النصي مع جميع البرامج النصية الموجودة على الصفحة. لسبب ما ، يتم قطع عنوان URL إلى 15 حرفًا.

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

الحماية المتقدمة: عنصر خاص


بخلاف الطريقة الأولى ، فإن هذه الطريقة مصحوبة بإخلاء مسؤولية: "يُرجى الاختبار بعد التثبيت لضمان التوافق مع موقعك".

تعمل هذه الحماية الخاصة فقط إذا لم يتم العثور على مانع ولم يكن هناك نص AdSense على الصفحة. إليك مقتطف الشفرة ذي الصلة 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
                }
            }
        }
    }

تفترض الطريقة أن أصحاب المواقع يستخدمون AdSense فقط: إذا لم يكن هناك نص AdSense ، فهذا يعني أن هناك خطأ ما.

لماذا كان هناك تحذير؟ يحاول هذا الأسلوب تمكين برنامج AdSense النصي. إذا لم يتم تحميله ، فمن المرجح أن المانع حظر طلب الشبكة ، وبالتالي يتم تشغيل BlockAdBlock. ولكن هذا يمكن أن يدمر بعض المواقع ، وبالتالي التحذير.

إذا لم يتم تحميل AdSense ، فسيبدأ التراكب.

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

عندما يحدث فشل على مستوى الشبكة ، فإنه يعمل onerrorكما لو كان مانع الإعلانات يعمل.

في الواقع ، معظم حاصرات الإعلانات تستجيب لهذا وتمنع الطلب. ولكن هناك مانع واحد لم أذكره بعد. تحدث عن متصفح Brave .

استجابة متصفح Brave


حتى الآن ، كنا ندرس كيفية اكتشاف مكافحة الحظر في uBlock Origin. ويعمل ، مطلوب فقط عامل تصفية محدد لكل موقع حيث تم تثبيت BlockAdBlock. متصفح Brave مثير للإعجاب من حيث أنه يكتشف BlockAdBlock لجميع الإصدارات ويتجاوزها دون أي إجراء ضروري من جانب المستخدم. للقيام بذلك ، قام بتزييف الطلب مباشرة على طبقة الشبكة 6.

فبدلاً من حظر الطلب ، ad_status.jsيتخطاه ، ولكنه يحمّل حجمًا زائفًا يبلغ 0 بايت في إعلانات Google . هذه الخدعة الصعبة تخدع BlockAdBlock ، لأنها onerrorتعمل فقط إذا فشل طلب الشبكة.



الإصدار 5 (مارس 2016 - نوفمبر 2016)


فرق كود المصدر
v4 / v5

حماية متقدمة: المفضلات غير المرغوب فيها


التغيير الوحيد في هذا الإصدار هو أنه تمت إعادة كتابة الحماية الموسعة الثانية ، على الرغم من أنها لا تزال تلتزم بالمبدأ الأساسي نفسه: فحص طلبات الشبكة التي سيتم حظرها بواسطة أداة الحظر. ولكن الآن يتم تحميل الرموز المفضلة بدلاً من AdSense.

الشجعان يتهرب من هذا الهجوم بنفس الطريقة. لا يمنع الطلبات ، لكنه ينشئ صورًا زائفة 1 × 1.

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

baitImagesيمكن استدعاء الوظيفة بشكل متكرر ، مع عدد عشوائي من الصور ، لتجاوز الحاصرات الثابتة.

الإصدار 6 (أبريل 2016 - نوفمبر 2016): قفل شجاع



اختلاف شفرة المصدر v5 / v6

طرق BlockAdBlock ، على الرغم من أنها بسيطة للوهلة الأولى ، أصبحت تدريجية أكثر تعقيدًا وأكثر كفاءة. لكن بقي العدو الأخير الذي لم يهزم: متصفح Brave.

الحماية المتقدمة: تحديد مفضلات وهمية


لماذا تحول BlockAdBlock من محاولة تحميل برنامج نصي لتحميل الصور (المفضلة)؟ الجواب في الكود الذي يضاف إلى الحماية من خلال رموز البريد العشوائي ، والتي يتم تنشيطها ضد حماية Brave.

التحقق من الاستجابة لصورة مزيفة:

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

إذا كان حجم الرمز المفضل أقل من 8 × 8 ، فمن المحتمل أن يكون هذا مزيفًا من متصفح Brave.

مع هذه الحيلة ، يتخطى BlockAdBlock تمويه Brave وغيرهم من الحاصرين الذين يشغلون هذا الرمز (معظمهم ، مثل uBlock Origin ، يحظرونه أولاً).

بعد هذا التحديث ، في نهاية نوفمبر 2016 تقريبًا ، اختفى BlockAdBlock من الإنترنت. على الرغم من عمل "أساليب الأمان المتقدمة" ، إلا أنه لم يتم تنشيطها مطلقًا لمعظم المستخدمين. كان هذا آخر تحديث. تم نشر آخر مشاركة على Twitter وعلى الموقع في مكان ما في نهاية عام 2017.

ومع ذلك ، فإن إرث BlockAdBlock موجود. على الرغم من أنه من السهل حظره هذه الأيام ، إلا أن هذا النص لا يزال يستخدم من قبل بعض المواقع الحديثة.

استنتاج


من سيفوز بسباق التسلح بين حاصرات الإعلانات ومضادات الحجب التي تمنع حاصرات الإعلانات؟ فقط الوقت كفيل بإثبات. مع تطور سباق التسلح ، سيتعين على مضادات الحجب استخدام طرق أكثر تعقيدًا ورمزًا خاصًا ، كما يظهر تطور BlockAdBlock.

من ناحية أخرى ، تتمتع الحاصرات بميزة الأنظمة المستقرة وأدوات التصفية القوية من خلال قوائم التصفية ، بالإضافة إلى الوصول إلى JavaScript. مع هذا النظام ، يكفي شخص واحد لفهم كيفية هزيمة العدو - وتحديث قائمة التصفية بمواقع جديدة.

من خلال تحليل تطور BlockAdBlock ، بالإضافة إلى الاستجابات المختلفة لحاصرات الإعلانات ، تمكنا من رسم صورة لحرب صغيرة بين BlockAdBlock والحاصرات. في هذه العملية ، تعلمنا ما هي الأساليب المستخدمة في الأعمال العدائية.

يتم نشر رمز الهندسة العكسية الخاص بي على GitHub . شكرا لقرائتك.



1. إذا كنت ترغب في الحصول على فكرة عن كيفية عمل ذلك ، فحاول لصق المثال أدناه في وحدة تحكم JS ، ثم انظر إلى الرمز. إذا كنت مهتمًا بعمله الداخلي ، فإليك رمز المصدر . return [العودة]

2. لا تصدق؟ حاول التغيير evalإلى console.logالسطر الأول.
[لكي ترجع]

3. يقول الطابع الزمني 201510، لذلك ربما أكتوبر. لكننا لا نعرف متى تغير البرنامج النصي. كل ما نعرف:

  • 2015-10 ، تم حفظ نسخة واحدة: 20151007203811.js
  • 2015-11 هناك إصدار جديد: 20151113115955.js

على حد علمنا ، يمكن تغيير البرنامج النصي في اليوم السابق على الطابع الزمني الثاني. وهكذا ، أقترب بشكل متحفظ من المواعدة. return [العودة]

4. خلال تصحيح هذا الخطأ تم تطوير اختبارات لل v1. return [العودة]

5. بفضل McStroyer على Reddit ، الذي لفت الانتباه إلى هذا. return [العودة]

6. مكوِّن أداة حظر الإعلانات Brave مفتوح ، لذلك يمكننا إلقاء نظرة على شفرة المصدر للحصول على فكرة عن كيفية عمله.


شكرًا لفرانسوا ماري على الإشارة إلى شفرة المصدر لـ Brave. return [العودة]

All Articles