返回列表 发帖

有关过滤script代码的思考

很多情况下,广告使用iframe或script的形式嵌入页面,所以一般过滤掉相应的iframe或script代码即可。
iframe标签有明确的界限,比较容易过滤,但对于script来说却比较麻烦,因为这是比较多变且不易控制的。

网站可以使用<script src="/xxx/yyy/zzz.js"></script>这种中规中矩的手法,虽然这对于他们来说更换广告比较容易,但对于写规则的人来说更容易了,直接将xxx\/yyy\/zzz\.js过滤即可。

但另一些如下面的代码:
  1. <script language="javascript">
  2. <!--
  3. var scriptcode;
  4. //-->
  5. </script>
复制代码
这种情况,过滤就比较麻烦了,不仅需要[\s\S]*?或.*?等,还需要其他的关键字。

其实我们都走入了一个误区,我们何必一定要过滤得干干净净呢?只要这段代码对访客浏览体验无害,那么就可以了。我们可以破坏代码,在不引发IE报错的情况下使之失效即可,譬如滤掉变量、参数、函数,只要让代码失效,我们的工作边完成了,我们的目的就达到了。

且看这一例,这段代码来自17173新年改版之后,万恶的iCast页面播放器的相关代码就在这里。
  1. <script language=javascript>
  2. if(typeof(_iCast_Controller_init_com)!="object"){
  3.     var _iCast_Controller_init_com = {};
  4. }
  5. _iCast_Controller_init_com[959] = function(){
  6.     document.getElementById('shuizhi3pleft').onmouseover = document.getElementById('shuizhi3pright').onmouseover = _doMouseMoveHandle;
  7.     document.getElementById('shuizhi3pleft').onclick = document.getElementById('shuizhi3pright').onclick = _doMouseClickHandle;
  8.     _doMouseClickHandle.d = _iCast_Controller_init;
  9. }
  10. function _doMouseMoveHandle(){
  11.     command = "replay";
  12.     var command_wrap = "on" + command;
  13.     window.iCast2.aa(command, "");
  14.     window.iCast2.dq[_doMouseMoveHandle.p].bF["0"].ao(command_wrap);
  15. }
  16. function _doMouseClickHandle(){
  17.     var d = _doMouseClickHandle.d;
  18.     var img = new Image();
  19.     img.src = d[3]+"?html&site_id="+Math.abs(d[0])+"&mission_id="+d[1]+"&click1=1&"+parseInt(Math.random()*100000);
  20. }
  21. if(typeof(window.iCast2)=="undefined"){
  22.     _doMouseMoveHandle.p=0;
  23. }else{
  24.     _doMouseMoveHandle.p=window.iCast2.dq.length;
  25. }
  26. var icast_channel_ID = 959;
  27. document.write('<scr'+'ipt language=javascript src="'">http://js.icast.cn/a/4/5/7/2/3/959.js"></scr'+'ipt>');
  28. </script><!--SmartCreative Begin:-->
  29. <SCRIPT LANGUAGE="JavaScript">
  30. var sc_203 = new Object(), _203=1,_f_203=1,_sh_203=1,_smid=203;
  31. function FQT_main(o){window.focus();_203=2;sc_203=o;_f_203=2;}
  32. if(_203 == 1)
  33. {
  34. try{AD=new ADM("FQT",1);AddSchedule(AD);}catch(e){}
  35. }
  36. </SCRIPT>
  37. <SCRIPT type="text/javascript" SRC="http://smcreative.allyes.com/smcreative/flash_fx.js"></SCRIPT>
  38. <SCRIPT type="text/javascript" SRC="http://sohusc.allyes.com/main/adfshow?user=sohusc|17173homepage|mercuryzt0924&db=sohusc&border=0&local=yes&js=ie" charset="GBK"></SCRIPT>
  39. <img src="http://secure-cn.imrworldwide.com/cgi-bin/m?ci=cn-allyes&cg=0&si=sohusc_1C6P203/_5h115t413" alt="" style="display:none">
  40. <!--SmartCreative End--><script language=javascript>
  41. var VideoPlay={videoTime:15,adjustTime:60,cookieName:"videoplayed",callParam:"",appendJs:false,setCookie:function(value,second){var nextTime=new Date();nextTime.setTime(nextTime.getTime()+1000*second);var domain_split=document.domain.split(".");var domain_split_length=domain_split.length;var domain=document.domain.substring(domain_split_length+1);document.cookie=this.cookieName+"="+escape(value)+"; expires="+nextTime.toGMTString()+"; path=/; domain="+domain},getCookie:function(Name){var search=Name+"=";if(document.cookie.length>0){offset=document.cookie.indexOf(search);if(offset!=-1){offset+=search.length;end=document.cookie.indexOf(";",offset);if(end==-1)end=document.cookie.length;return unescape(document.cookie.substring(offset,end))}}},watch:function(callMethod){if("enter"==callMethod){this.enterCall(this.callParam)}},enterCall:function(videoEnterCall){if(this.getCookie(this.cookieName)=="playing"){this.callParam=videoEnterCall;setTimeout("VideoPlay.watch(\"enter\")",2000)}else{this.setCookie("playing",this.videoTime+this.adjustTime);videoEnterCall()}},playDone:function(){this.setCookie("playdone",0)}}
  42. VideoPlay.adjustTime = 8;
  43. </script>
  44. <script language=javascript>
  45. var icast_channel_ID = 887;
  46. iCast_Start_Enabled_887 = false;
  47. document.write('<scr'+'ipt language=javascript src="'">http://js.icast.cn/a/4/5/7/3/2/887.js"></scr'+'ipt>');
  48. </script>
  49. <script type="text/javascript">
  50. AD=new ADM("VIDEOPLAY",5);
  51. AddSchedule(AD);
  52. var _VIDEOPLAY_5;
  53. var _iCast_TIMER_5;
  54. function VIDEOPLAY_main(o){
  55. _VIDEOPLAY_5=o;
  56. VideoPlay.enterCall(startPlay);
  57. _iCast_TIMER_5 = setTimeout("_VIDEOPLAY_5.s=2", 15000);
  58. }
  59. function startPlay(){
  60. iCast_Start_Enabled_887 = true;
  61. }
  62. </script>
复制代码
我们可以发现许多关键字,如iCast或更加明显的HTML注释<!--SmartCreative Begin:-->、><!--SmartCreative end -->等关键字或字符串来实现过滤,如:
  1. #exd#*17173.com*#<!--SmartCreative Begin:-->[\s\S]*?<!--SmartCreative end -->###
复制代码

但这些工作量过于庞大且效率低下。我们可以通过破坏代码的方式达到目的,何必一定要拘泥于<script>标签呢?抛弃他们,直接对脚本代码下手吧。

我们可以通过分析和整理,得到有关iCast的一些有趣的事实:
_iCast_
var _iCast_
iCast
iCast_
var iCast_
.iCast2
(TW不区分大小写,这大大降低了我们的工作量)
通过分析可知,有关于iCast的变化有6种;
然后继续整理其他的相关变量,如videoplay,他就有:
var VideoPlay
function VIDEOPLAY_
VideoPlay.
var _VIDEOPLAY_
_VIDEOPLAY_
等5种变化。

所以我们可以使用如下的规则进行一网打尽
  1. (?:var |_|function)?(?videoplay_?|_?iCast_?)
复制代码
为什么我们忽略了var _videoplay_ 这个变化呢?因为我们的目的不是完整过滤脚本,而是破坏脚本使之无效。

这仅是开始,我们有了规则的开始部分,但这还远远不够,因为我们需要规则的结尾部分,这样规则才能正常生效。我们重新返回上面的广告例子,将function、var统统抛到脑后吧,我们只需搜寻videoplay和icast这两个关键字的结尾部分。

javascript脚本代码和C一样,每一句句字节数必须要有分号;,所以分号;是一个非常优良的结束字符。但我们通过分析可知,并不是每一行的最右端都是分号;,但如果使用[\s\S]*?来跨行搜寻分号;则需要牺牲一定的时间(诸如17173这类变态网站其实还有很多,广告超多意味着过滤广告需要一定的时间,效率下降并且让浏览器的假死率增高),所以我们避免在这里使用[\s\S]*?,而是使用[^\n]*?,单行搜索。

通过统计,我们可以得到videoplay和icast但行最后一个字符有【分号;】、【开门大括号{】、【关门大括号}】等,所以我们使用下面的代码可以实现一网打尽:
  1. (?:;|{|})$
复制代码
为了保证分号和大括号是位于那一行的最后,我们在最后放了一个$,表示以此字符为结束者匹配。

于是我们将这两段连起来,得到了这段规则:
  1. (?:var |_|function)?(?:videoplay_?|_?iCast_?)[^\n]*?(?:;|{|})$
复制代码
分析整段广告示例,我们可以得到sc_203、command_wrap、startPlay等关键字,这里需要提醒一点,不可随意寻找关键字,因为你得保证这些关键字只会出现在广告相关的脚本代码里。如果出现在正常的脚本代码里,那么将会严重影响你的正常浏览体验。

最后,我得到了这段规则:
  1. #exd#*17173.com*#(?:function |var |_)?(?:sogou_|sc_203|command_wrap|duilian\d|FQT_main|doMouse|startPlay|videoplay_?|_?iCast_?)[^\n]*?(?:;|'|}|o|{)$###
复制代码
输入TW黑名单,配合通用规则后实现破坏脚本代码的目的,iCast广告不再出现,同时你也能在较快的时间里得到你所要的东西——色彩斑斓的页面。

下面是启用了这句规则过滤之后剩下的“无害残留物”:
  1. <script language=javascript>
  2. if(typeof(
  3.    
  4. }
  5.     document.getElementById('shuizhi3pleft').onmouseover = document.getElementById('shuizhi3pright').onmouseover =
  6.     document.getElementById('shuizhi3pleft').onclick = document.getElementById('shuizhi3pright').onclick =
  7.    
  8. }
  9. function
  10.     command = "replay";
  11.    
  12.     window.
  13.     window.
  14. }
  15. function
  16.     var d =
  17.     var img = new Image();
  18.     img.src = d[3]+"?html&site_id="+Math.abs(d[0])+"&mission_id="+d[1]+"&click1=1&"+parseInt(Math.random()*100000);
  19. }
  20. if(typeof(window.
  21.    
  22. }else{
  23.    
  24. }
  25. document.write('<scr'+'ipt language=javascript src="http://js.
  26. </script><!--SmartCreative Begin:-->
  27. <SCRIPT LANGUAGE="JavaScript">

  28. if(_203 == 1)
  29. {
  30. try{AD=new ADM("FQT",1);AddSchedule(AD);}catch(e){}
  31. }
  32. </SCRIPT>

  33. <img src="http://secure-cn.imrworldwide.com/cgi-bin/m?ci=cn-allyes&cg=0&si=sohusc_1C6P203/_5h115t413" alt="" style="display:none">
  34. <!--SmartCreative End--><script language=javascript>

  35. </script>
  36. <script language=javascript>

  37. document.write('<scr'+'ipt language=javascript src="http://js.
  38. </script>
  39. <script type="text/javascript">
  40. AD=new ADM("
  41. AddSchedule(AD);
  42. var


  43. }

  44. }
  45. </script>
复制代码
所有影响浏览体验的东西都没了,效率比整段过滤快了许多吧?

现在,让我们回过头,看看本文最前面的思考吧:<script src="/xxx/yyy/zzz.js"></script>该如何过滤?现在,我们多了一种办法:破坏,破坏,破坏~
  1. #exd#*17173.com*#(?:zzz)\.js###<!--如有其它相同的需要过滤的js文件,可放在zzz右侧,并用|分割,如(?:zzz|yours)-->
复制代码


尝试一下自己DIY吧,然后将你的规则拿出来分享,让更多的用户知道,TW的过滤规则比MX的先进一代半。

[ 本帖最后由 285900537 于 2008-1-4 21:10 编辑 ]
liuyis[AT]live.com

思考是要顶di, 并且也同意楼上的看法, 这种方式要谨慎。
遇到崩溃假死或者感觉速度慢或者其他问题的朋友可以先试试使用TW3
TheWorld we explore the world.

TOP

曾经有过一段时间用过破坏 js 这种方式.
  因为js太脆弱了. 虽然不是每行都要有分号(;)  但关键的变量, 函数名字. 调用/主体函数过滤之后, 广告就可以完全失效.

个人建议 . 不是非不得已, 还是整段 script过滤掉吧, 其实我也有点洁癖..... .
万一用到破坏的方式, 千万注意不要引发js错误.  霏凡下载地址就是一个例子.
天下无不散之筵席.

世界之窗浏览器开发计划

TOP

我计算了一下

大段过滤的方法,页面主题内容完整显示完毕所需时间为8秒(ctrl+F5)
破坏过滤的方法,页面主题内容完整显示完毕所需时间为5秒(ctrl+F5)

这里是以显示copyright作为完成显示完毕的标准进行的测试。
liuyis[AT]live.com

TOP

实际上应该是感觉不到的。

tw的效率是很高的,这点区别可以忽略不计

TOP

是的。

从效率上来说(尤其是像17173这种变态的广告狂来说),破坏的效率比较高,用户等待的时间会相对少一些。
liuyis[AT]live.com

TOP

从难度上来说,过滤整段代码要比破坏简单的多

TOP

测试规则的时候都是会注意这一点的,如果出现问题那就全体过滤;如果不出现问题,那么破环也无妨。

规则书写者发布的规则都是经测试后无问题的,所以破坏还是可行的,这可以增加加载速度。

当然,并不是所有的脚本都是可以被破坏的,也不是所有的脚本都必须整体过滤的,所以破坏脚本代码这个思想也是可行的。
liuyis[AT]live.com

TOP

不推荐这种作法
相对而言,过滤掉所有的广告代码要比你说的更简单,因为从代码角度来讲找到广告部分的代码要比在代码里再查找简单的多,而且,留下这些不完全的脚本也会造成一些问题。同时,考虑到代码的严谨性和可阅读性,应该选择过滤掉所有的广告代码,而不是破坏。

[ 本帖最后由 elkay 于 2008-1-4 21:25 编辑 ]

TOP

返回列表