关于eval的劫持操作

  • A+
所属分类:WooYun-Zone

前提:本文讨论在chrome浏览器下的情况,由于早期IE浏览器的实现有所不同,导致与本文所提内容存在差异。其它浏览器也未做测试。

在某些需求环境中,我们需要劫持eval函数,输出所eval的内容。对于常规的场景来说,这一点是非常容易实现的。

var eval=(function(e){

    return function(data){

    console.log(data);

    e(data);

    }

})(eval);

eval("alert(1)");  //我们可以在控制台看到输出 alert(1)

但是在某些特定情况下,上述的代码,就会出现问题,最为典型的,就是eval发生在函数局部,且eval的内容中,含有局部变量时。

我们对比以下代码。

未劫持情况下,弹出 “local”

var a="global";

function myfunc(){

  var a="local";

  eval("alert(a)");

}

myfunc();

加入劫持代码后,弹出”global”

var eval=(function(e){

    return function(data){

    console.log(data);

    e(data);

    }

})(eval);

var a="global";

function myfunc(){

  var a="local";

  eval("alert(a)");

}

myfunc();

也就是说,我们的劫持,改变了原本代码应有的逻辑,这样显然是不完美的。

查阅了相关资料,eval 有 “直接调用”与“间接调用”的区别。 只有直接调用的eval才能够区分所eval内容里的变量是“全局”或“局部”,而间接调用,则都是当作全局变量来对待。

而目前并没有一个很有效的办法,在劫持eval函数的同时,保证这个eval是一个“直接调用”。因为哪怕是下面的代码操作,都会导致eval变为一个“间接调用”。

window.eval("xxxx"); //间接调用

var eval2=eval;

eval2("xxxx");  //间接调用

eval.call(this, '...')  //间接调用

(1, eval)('...') //间接调用

有些方法则属于是直接调用:

eval('...')

  (eval)('...')

  (((eval)))('...')

  (function() { return eval('...') })()

  eval('eval("...")')

  (function(eval) { return eval('...'); })(eval)

  with({ eval: eval }) eval('...')

  with(window) eval('...')

但是属于直接调用的任何形式,都无法满足我们劫持eval内容的需求。

各位看官,有何高见。 来讨论讨论。

其它要求: 劫持函数需定义于函数体外部。 定义在内部没意义。

  1. 1#

    cnrstar (Be My Personal Best!) | 2012-12-28 20:09

    沙发,二哥出品,必属精品

  2. 2#

    gainover | 2012-12-28 20:11

    @cnrstar 这是个问题。。不是个内容。。你丫不看帖,就抢沙发。

  3. 3#

    dyun (shall we begin?) | 2012-12-28 20:11

    下断,跟下浏览器看下eval底层调用的是什么~~~

  4. 5#

    心伤的瘦子 (‮data;) | 2012-12-28 23:59

    @xsser = = 弄个FF的源码修改下,估计就成了 Dominator了。。

  5. 6#

    心伤的瘦子 (‮data;) | 2012-12-29 00:00

    @gainover 可能没直接的解决办法。

  6. 7#

    px1624 (aaaaaaaaa) | 2012-12-29 01:16

    楼上回答好亮。。。

  7. 8#

    /fd (Http://prompt.ml) | 2012-12-29 18:30

    eval太涉及內部操作,一般的方法都模擬不了,只能看下引擎有沒私有屬性/方法能訪問Execution context、Variable/Activation Object…等等。
    這裡有一個方法能簡單判斷是否為Direct Call(ES5):
    function isDC(){'use strict';return this!==window}
    在ES5的嚴格模式限制了物件前綴undefined/null->window的轉換,亦即能分辦出window.eval與eval的調用,但eval的操作更接近關鍵字,像大牛舉的多數例子就分辦不了。
    參考:http://es5.github.com/#x15.1.2.1
    略懂皮毛可能有錯不吝指教

  8. 9#

    /fd (Http://prompt.ml) | 2012-12-29 18:36

    補充:即便能分辦出直接與間接調用也無法模擬出函数的上下文

  9. 10#

    xsjswt | 2012-12-29 20:10

    把this的变量都浅复制过来可行么

  10. 11#

    /fd (Http://prompt.ml) | 2012-12-29 21:13

    @xsjswt 跟this無關係

  11. 12#

    心伤的瘦子 (‮data;) | 2013-01-17 14:16

    .. ‮data;

  12. 13#

    /fd (Http://prompt.ml) | 2013-01-17 14:31

    @心伤的瘦子 目測是\u202e

  13. 14#

    LaiX ([][(![]+[])[+[[+[]]]]+([][[]]+[])[+[[!+[]+!+[]+!+[]+!+[]+!+[]]]]+(![]+[])[+[[!+[]+!+[]]]]+(!![]+[])[+[[+[]]]]+(!![]+[])[+[[!+[]+!+[]+!+[]]]]+(!![]+[])[+[[+!+[]]]]][([][(![]+[])[+[[+[]]]]+([][[]]+[])[+[[!+[]+!+[]+!+[]+!+[]+!+[]]]]+(![]+[])[+[[!+[]+!+[]]]]+) | 2013-09-16 19:33

    学习了.. 多谢二哥

  14. 15#

    Skull ((‮data;)) | 2013-09-16 19:53

    @gainover thanks

  15. 16#

    yangff | 2013-09-16 21:44

    https://code.google.com/p/v8/codesearch#v8/trunk/src/d8.cc&sq=package:v8&dr=C&l=386

    and then…

  16. 17#

    Coner ([马甲?]) | 2014-12-06 17:41

    貌似二哥是在写一个底层劫持的神器,不知道写完了没有呢?