Anti-adblock-killer: BlockAdblock beta 4.0 is releasing, and the script no longer works

Created on 10 Aug 2016  路  11Comments  路  Source: reek/anti-adblock-killer

The changes I found are another layer of obfuscation and the removal of the old function with the fixed name. They are now randomizing basically everything and even used JSFuck in their attempts to hide it. (Entirely futile attempt, Chrome Dev Tools can still show any source code.) The point is, the old code doesn't work, at least in Chrome 52 with uBlock Origin.

I've put together this to counter the problem:

setInterval(function () {
  var approved = ['speechSynthesis', 'caches', 'localStorage', 'sessionStorage', 'webkitStorageInfo', 'indexedDB', 'webkitIndexedDB', 'ondeviceorientationabsolute', 'ondeviceorientation', 'ondevicemotion', 'crypto', 'postMessage', 'blur', 'focus', 'close', 'stop', 'onunhandledrejection', 'onrejectionhandled', 'open', 'alert', 'confirm', 'applicationCache', 'performance', 'onunload', 'prompt', 'onstorage', 'onpopstate', 'print', 'onpageshow', 'onpagehide', 'ononline', 'requestAnimationFrame', 'onoffline', 'onmessage', 'onlanguagechange', 'cancelAnimationFrame', 'onhashchange', 'onbeforeunload', 'onwaiting', 'captureEvents', 'onvolumechange', 'ontoggle', 'ontimeupdate', 'onsuspend', 'releaseEvents', 'onsubmit', 'onstalled', 'getComputedStyle', 'onshow', 'onselect', 'onseeking', 'onseeked', 'matchMedia', 'onscroll', 'onresize', 'moveTo', 'onreset', 'onratechange', 'onprogress', 'onplaying', 'moveBy', 'onplay', 'onpause', 'resizeTo', 'onmousewheel', 'onmouseup', 'onmouseover', 'onmouseout', 'resizeBy', 'onmousemove', 'onmouseleave', 'getSelection', 'onmouseenter', 'onmousedown', 'onloadstart', 'onloadedmetadata', 'find', 'onloadeddata', 'onload', 'onkeyup', 'getMatchedCSSRules', 'onkeypress', 'onkeydown', 'webkitRequestAnimationFrame', 'oninvalid', 'oninput', 'onfocus', 'onerror', 'webkitCancelAnimationFrame', 'onended', 'onemptied', 'webkitCancelRequestAnimationFrame', 'ondurationchange', 'ondrop', 'ondragstart', 'ondragover', 'btoa', 'ondragleave', 'ondragenter', 'atob', 'ondragend', 'ondrag', 'ondblclick', 'setTimeout', 'oncuechange', 'oncontextmenu', 'onclose', 'onclick', 'clearTimeout', 'onchange', 'oncanplaythrough', 'oncanplay', 'setInterval', 'oncancel', 'onblur', 'clearInterval', 'onabort', 'createImageBitmap', 'requestIdleCallback', 'cancelIdleCallback', 'scroll', 'scrollTo', 'scrollBy', 'fetch', 'webkitRequestFileSystem', 'webkitResolveLocalFileSystemURL', 'openDatabase', 'external', 'chrome', 'console', 'isSecureContext', 'onwheel', 'onwebkittransitionend', 'onwebkitanimationstart', 'onwebkitanimationiteration', 'onwebkitanimationend', 'ontransitionend', 'onsearch', 'onanimationstart', 'onanimationiteration', 'onanimationend', 'styleMedia', 'defaultstatus', 'defaultStatus', 'screenTop', 'screenLeft', 'clientInformation', 'devicePixelRatio', 'outerHeight', 'outerWidth', 'screenY', 'screenX', 'pageYOffset', 'scrollY', 'pageXOffset', 'scrollX', 'innerHeight', 'innerWidth', 'screen', 'navigator', 'frameElement', 'parent', 'opener', 'top', 'length', 'frames', 'closed', 'status', 'toolbar', 'statusbar', 'scrollbars', 'personalbar', 'menubar', 'locationbar', 'history', 'location', 'name', 'document', 'self', 'window']

  Object.keys(window).filter(function (key) { // don't check standard keys (disclaimer: BlockAdblock, if you start hiding there and breaking functionality, it takes two lines for us and lots of rep for you)
    return !~approved.indexOf(key)
  }).map(function (key) { // check for BlockAdblock signature
    var element = window[key]

    try {
      var thisIsBait = Object.keys(element).filter(function (key) {
        return typeof element[key] === 'function'
      }).filter(function (key) {
        var method = element[key]
        return ~method.toString().indexOf('aW5zLmFkc2J5Z29vZ2xl')
      }).length

      if (thisIsBait) {
        window[key] = null
      }
    } catch (bait) {
      // it was probably undefined or null. Anyway, carry on.
    }
  })
}, 500)

It scans any non-default properties of window for a specific function signature, which is ins.adsbygoogle base64-encoded. If it finds it, it removes the element from window, which neuters BlockAdblock's blocking screen.

I've tested it in Chrome 52 with Tampermonkey and Firefox 48 with Greasemonkey on Linux and found no errors. This is of course not exhaustive, but it shouldn't depend on browsers as I've not used any ES6 features. The approved list is the result of the Object.keys(window) call in Chrome 52, but it's mainly for performance reasons, elements that are not included on the list are still only erased if they contain BlockAdBlock code.

For me, the beta appears on https://blockadblock.com/configure-beta-40b.php, version 4.0 can be recognized from the JSFuck code at its end.

All 11 comments

Ok, my replacing window.eval() stopped working as well... I will take a look.

Update: setInterval can be quite heavy on slower devices, I will look for a more efficient solution.
BTW, JSFuck can be quite easily decompiled: http://codegolf.stackexchange.com/questions/28714/convert-jsfuck-to-normal-js (result: In the middle: null At the end: eval(x))`

Update2: Yes, replacing window.eval() so it look for keywords suck as "BlockAdblock" and refuse to execute strings with keywords still works, but their website have the block screen in the HTML, and will fade in if their script didn't go off. All we need is to remove the element with id babasbmsgx, this should be specific to blockadblock.com itself.

So here is the solution for a generic 4.0b killer:

// ==UserScript==
// @name         New Userscript
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @include      http://*/*
// @include      https://*/*
// @run-at       document-start
// @grant        unsafeWindow
// ==/UserScript==

(function() {
    'use strict';
    const original = unsafeWindow.eval;
    unsafeWindow.eval = function (a) {
        if (!(/BlockAdblock/i).test(a.toString())) {
            return original(a);
        }
    };
})();

For blockadblock.com you also need to remove element with id babasbmsgx.

Actually, it only needs to run once, the interval can be cleared after BlockAdblock is successfully blocked (if (thisIsBait) was triggered) or 30 seconds have passed, which is its maximum interval. Their obfuscated blob gives no flexibility for those who are not willing (and able) to hack it.

Also, JSFuck is quite easy to neuter, too, this one line does it:

Array.prototype.filter.constructor = undefined

Since their entire code depends on that now, it should also be a quick and simple solution.

Array.prototype.filter.constructor = undefined
Not a good idea, as this messes with all scripts on the page.

Gurus / Developers / masters on this thread

Good day

Sorry for the intrusion, but probably I can help testing, so jumping in here

as of 11 / Aug / 2016 I'm struggling with the ADB block / nag screen on various pages like http://timesofindia.indiatimes.com/Rio-2016-olympics/liveblog/53571982.cms or http://timesofindia.indiatimes.com/world/pakistan/Loud-explosion-near-Al-Khair-hospital-in-Quetta-six-injured/articleshow/53647381.cms (only 2 samples given, nag found on multiple recent news posts of this site)

I use Firefox 48 (Screen shot enclosed)
screenshot - 11_08_2016 09_39_05

I've downloaded & installed the latest dev. build of Adblock plus from here https://adblockplus.org/en/development-builds

I've updated the filters few minutes before this post ..screen shot of filters enclosed
screenshot - 11_08_2016 09_47_33

As of now I do NOT have any custom filters
screenshot - 11_08_2016 09_48_38

I do NOT use greasemonkey or similar software (at least I haven't installed them myself). I'm ready to install what is needed , add custom filers etc,

any help would be gratefully acknowledged

thanks in advance
Best regards
subu

I've tested setting Array.prototype.filter.constructor in Chrome, it does not mess up anything but JSFuck, the filter method still works. It works because it's adding a new property called constructor to Array.prototype.filter (which is a Function instance) instead of overwriting the existing one which is set at the prototype. Setting Function.prototype.constructor could be worse, but the Function constructor is just a form of eval anyway, I doubt anyone else uses it. (Also, it seems to work even with its constructor cleared.)

I doubt anyone else uses it.

Don't get into that mindset. Function prototypes are sacred. If it exists in vanilla Javascript, people use it, and we should make our best effort not to break pages. Especially when writing scripts that affect multiple pages.

Also, breaking jsfuck will affect all webpages that use it for purposes other than anti-adblock.

@Giwayume Yea, good point. For generic solution we can't break any system functions, but we can replace them with a filter like what I did. The problem is some people can just remove the keyword "blockadblock"...

I hate to post here a question, but I always look at this issue page and since weeks this site appearing in disorder. Is reek still active or just vacations?

@koboltzz I think Aak is still active.

@koboltzz Dunno. If I were him I'd take a long break now and then. This can be tedious work. If you really want him to pay attention to the project your best bet would be donating.

@Giwayume Yea, the work is intensive. I have like 30 websites in my script and it's already getting hard.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

graciecat picture graciecat  路  3Comments

NessunoIM picture NessunoIM  路  3Comments

YamiryuuZero picture YamiryuuZero  路  4Comments

Draithen picture Draithen  路  4Comments

rayman89 picture rayman89  路  4Comments