AdguardTeam / Scriptlets

AdGuard scriptlets library
GNU General Public License v3.0
148 stars 29 forks source link

Add new scriptlet — 'trusted-replace-outbound-text' #410

Closed Yuki2718 closed 3 months ago

Yuki2718 commented 7 months ago

Add a new scriptlet to intercept atob() call and prune its text output

Background: YT checks if anti-adblock warning (auxiliaryUi.messageRenderers.bkaEnforcementMessageViewModel) is removed by blocker by checking playerResponse.responseContext.mainAppWebResponseContext.trackingParam which includes encoded info about the warning if it is sent. If we remove this encoded info together with the warning, we can safely remove the warning. This is currently done with $replace rules removing parts of trackingParam but this approach is risky. The encoded info is finally decoded with atob, and if we prune the info from the output of atob, we can safely remove the info. If you want to check by yourself, search for 282054944_a in /desktop_polymer.vflset script in the debugger and put a break point before this, and follow the processing step by step. Here's the moment decoding was done when anti-adb is not sent. If sent, the output will be longer and include \n|\nGauxiliaryUi.messageRenderers.bkaEnforcementMessageViewModel.displayType\x121ENFORCEMENT_MESSAGE_VIEW_MODEL_DISPLAY_TYPE_POPUP\nM\nEauxiliaryUi.messageRenderers.bkaEnforcementMessageViewModel.isVisible\x12\x04true.

Screenshot 1 ![mea](https://github.com/AdguardTeam/Scriptlets/assets/58900598/4b310b75-a0f9-4280-8790-5c1c67f0bc7a)

Actual rules working on Chrome as of writing:

www.youtube.com#%#(()=>{const wrapper=(target,thisArg,args)=>{let result = Reflect.apply(target,thisArg,args);console.debug('Result atob:',result);if(result.includes('bkaEnforcementMessage')){const modifiedContent=result.replace('\n|\nGauxiliaryUi.messageRenderers.bkaEnforcementMessageViewModel.displayType\x121ENFORCEMENT_MESSAGE_VIEW_MODEL_DISPLAY_TYPE_POPUP\nM\nEauxiliaryUi.messageRenderers.bkaEnforcementMessageViewModel.isVisible\x12\x04true','');console.debug('Modified atob:',modifiedContent);return modifiedContent;}return result;};const handler={apply:wrapper};window.atob=new Proxy(window.atob,handler);})();
www.youtube.com#%#//scriptlet('set-constant', 'ytInitialPlayerResponse.auxiliaryUi.messageRenderers.bkaEnforcementMessageViewModel', 'undefined')
www.youtube.com#@%#//scriptlet('trusted-replace-fetch-response', '/("trackingParam":"kx_fmPxhoPZR)[-_0-9A-Za-z]{150}[-_0-9A-Za-z]+?([-_0-9A-Za-z]{55}lLKPQ-SS"\})/', '$1$2', 'player?')
www.youtube.com#@%#//scriptlet('trusted-replace-fetch-response', '/("trackingParam":"k5DfmPxhoXpR)[-_0-9A-Za-z]{150}[-_0-9A-Za-z]+?([-_0-9A-Za-z]{151}lLKPQGiS"\})/', '$1$2', 'player?')
www.youtube.com#%#//scriptlet('json-prune', 'playerResponse.adPlacements playerResponse.playerAds playerResponse.adSlots adPlacements playerAds adSlots')
Screenshot 2 ![atob](https://github.com/AdguardTeam/Scriptlets/assets/58900598/8622b5fa-d7de-4463-bdbc-4ec7913d162f)

The first line is what should be the new scriptlet. The next line overwrites auxiliaryUi.messageRenderers.bkaEnforcementMessageViewModel on Chromium at the first load of yt video. The third and forth rules disable the current rules doing the same on raw trackingParam, as we want to see the test rule works by itself. The last rule is to intentionally trigger the warning if the pruning failed.

May possibly be more generic scriptlet like trusted-prune-text-output with target function as an argument (in this case atob), 0-based position of tareget argument in the function, condition for the pruning to happen (e.g. input/output includes specified string or regex), and stack trace.

Yuki2718 commented 5 months ago

Now yt no longer uses atob or any other global function if yt.config_.EXPERIMENT_FLAGS.ab_sig_bit_dea is true. Probably we have to intercept base64-encoded intermediate representation of trackingParam, decode it, replace its text, encode again, and return. Here two possible filters working for the original case of auxiliaryUi.messageRenderers.bkaEnforcementMessageViewModel warning (not the ssap issue we're currently facing):

www.youtube.com#%#(()=>{const wrapper=(target,thisArg,args)=>{let result=Reflect.apply(target,thisArg,args);console.debug('Result Array join:',result);try{const decoded=atob(result);console.debug('Decoded:',decoded);if(decoded.includes('bkaEnforcementMessage')){const modifiedContent=result.replace(/\n.\n.auxiliaryUi\.messageRenderers\.bkaEnforcementMessageViewModel\.displayType.\dENFORCEMENT_MESSAGE_VIEW_MODEL_DISPLAY_TYPE_[A-Z]+\n.\n.auxiliaryUi\.messageRenderers\.bkaEnforcementMessageViewModel\.isVisible.{2}(?:tru|fals)e/,'');console.debug('Modified content:',modifiedContent);const encodeToBase64=btoa(modifiedContent);return encodeToBase64}}catch(e){} return result};const handler={apply:wrapper};window.Array.prototype.join=new Proxy(window.Array.prototype.join,handler)})()
www.youtube.com#%#(()=>{const wrapper=(target,argumentsList,newTarget)=>{const result=Reflect.construct(target,argumentsList,newTarget);try{const decoded=new TextDecoder().decode(result);console.debug('Decoded:',decoded);if(decoded.includes('bkaEnforcementMessage')){const modifiedContent=decoded.replace(/\n.\n.auxiliaryUi\.messageRenderers\.bkaEnforcementMessageViewModel\.displayType.\dENFORCEMENT_MESSAGE_VIEW_MODEL_DISPLAY_TYPE_[A-Z]+\n.\n.auxiliaryUi\.messageRenderers\.bkaEnforcementMessageViewModel\.isVisible.{2}(?:tru|fals)e/,'');const modifiedUint8Array=new TextEncoder().encode(modifiedContent);return modifiedUint8Array}}catch(e){} return result};const handler={construct:wrapper,};window.Uint8Array=new Proxy(Uint8Array,handler)})()

The first rule targets Array.prototype.join and the second Uint8Array. I propose adding an option to decode/encode input and output, otherwise the scriptlet here can trivially be circumvented like this.