cookie僵尸——evercookie分析(三)【转】

这篇文章来对evercookie的js源码进行分解下,

因为源码太长,这里发2个个人觉得最有意思的方法出来,顺便做了点小解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
BwStore.evercookie_history = function(name, value)
{
    // - is special
    var baseStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=-";
    var baseElems = baseStr.split("");
      
    // sorry google.
    var url = 'http://www.google.com/evercookie/cache/' + this.getHost() + '/' + name;
  
    if (typeof(value) != "undefined")
    {
        // don't reset this if we already have it set once
        // too much data and you can't clear previous values
        if (this.hasVisited(url))
            return;
  
        this.createIframe(url, 'if');
        url = url + '/';
  
        var base = this.encode(value).split("");
        for (var i = 0; i < base.length; i++)
        {
            url = url + base[i];
            this.createIframe(url, 'if' + i);
        }
  
        // - signifies the end of our data
        url = url + '-';
        this.createIframe(url, 'if_');
    }
    else
    {
        // omg you got csspwn3d
        if (this.hasVisited(url))
        {
            url = url + '/';
  
            var letter = "";
            var val = "";
            var found = 1;
            while (letter != '-' && found == 1)
            {
                found = 0;
                for (var i = 0; i < baseElems.length; i++)
                {
                    if (this.hasVisited(url + baseElems[i]))
                    {
                        letter = baseElems[i];
                        if (letter != '-')
                            val = val + letter;
                        url = url + letter;
                        found = 1;
                        break;
                    }
                }
            }
              
            // lolz
            return this.decode(val);
        }
    }
}

这个方法算是evercookie最经典的一个方法了

大家都知道,用户访问过一次页面,就会存储在浏览器浏览历史里面,这个方法就是利用浏览器的这个特性。通过新建一个iframe去访问这个页面。

如默认的url是http://www.google.com/evercookie/cache/

那他发送的路径会是加上了name跟value的。这里的name跟value分别是id跟onedear,如
http://www.google.com/evercookie/cache/id/onedear

发送方法为每个字母递增发送,并在最后加个”-“的结束符号

http://www.google.com/evercookie/cache/i

http://www.google.com/evercookie/cache/id

。。。。

http://www.google.com/evercookie/cache/id/onedea

http://www.google.com/evercookie/cache/id/onedear

http://www.google.com/evercookie/cache/id/onedear-

那要相应的name value他是这样获取的。

默认url加上”ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=-“。其中一个字符,看看是否存在历史记录里面。不存在则循环查找下一个。如果这里查到i是访问过的。http://www.google.com/evercookie/cache/i ,则继续循环,在i的后面循环检查。继而又查到d是访问过的。http://www.google.com/evercookie/cache/id,一直循环知道出现’-‘符号为止。继而解析获取到的字符串,那name value自然也就解析出来。

但这样做的弊端很大。首先,必须要连续发送n个url,用户体验不好。获取的时候要遍历,也影响了浏览器的性能。

所以不推荐。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
BwStore.evercookie_png = function(name, value)
{
    //alert(document.createElement('canvas').getContext);
    if (document.createElement('canvas').getContext)
    {
        if (typeof(value) != "undefined")
        {
            // make sure we have evercookie session defined first
            document.cookie = 'evercookie_png=' + value;
              
            // evercookie_png.php handles the hard part of generating the image
            // based off of the http cookie and returning it cached
            var img = new Image();
            img.style.visibility = 'hidden';
            img.style.position = 'absolute';
            img.src = 'evercookie_png.php?name=' + name;
        }
        else
        {
            _ec.pngData = undefined;
            var context = document.createElement('canvas');
            context.style.visibility = 'hidden';
            context.style.position = 'absolute';
            context.width = 200;
            context.height = 1;
            var ctx = context.getContext('2d');
              
            // interestingly enough, we want to erase our evercookie
            // http cookie so the php will force a cached response
            var origvalue = this.getFromStr('evercookie_png', document.cookie);
            document.cookie = 'evercookie_png=; expires=Mon, 20 Sep 2010 00:00:00 UTC; path=/';
  
            var img = new Image();
            img.style.visibility = 'hidden';
            img.style.position = 'absolute';
            img.src = 'evercookie_png.php?name=' + name;
              
            img.onload = function()
            {
                // put our cookie back
                document.cookie = 'evercookie_png=' + origvalue + '; expires=Tue, 31 Dec 2030 00:00:00 UTC; path=/';
  
                _ec.pngData = '';
                ctx.drawImage(img,0,0);
  
                // get CanvasPixelArray from  given coordinates and dimensions
                var imgd = ctx.getImageData(0, 0, 200, 1);
                var pix = imgd.data;
  
                // loop over each pixel to get the "RGB" values (ignore alpha)
                for (var i = 0, n = pix.length; i < n; i += 4)
                {
                    if (pix[i  ] == 0) break;
                    _ec.pngData += String.fromCharCode(pix[i]);
                    if (pix[i+1] == 0) break;
                    _ec.pngData += String.fromCharCode(pix[i+1]);
                    if (pix[i+2] == 0) break;
                    _ec.pngData += String.fromCharCode(pix[i+2]);
                }
            }
            return _ec.pngData;
        }
    
}

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$x = 200;
$y = 1;
  
$gd = imagecreatetruecolor($x, $y);
  
$data_arr = str_split($_COOKIE["evercookie_png"]);
  
$x = 0;
$y = 0;
for ($i = 0; $i < count($data_arr); $i += 3)
{
    $color = imagecolorallocate($gd, ord($data_arr[$i]), ord($data_arr[$i+1]), ord($data_arr[$i+2]));
    imagesetpixel($gd, $x++, $y, $color);
}
Ever_cookie_png.php

服务器创建一个宽100像素高1像素的黑色空白PNG(每个像素的RGB 颜色可存储3个字节,可存储600字节信息),然后将值拆分并按顺序每3个字母生成一个RGB颜色值并且按顺序设置到图片的像素点中,读取的时候取出并且解析还原出来。还原需要用到'canvas'标签,要求浏览器必须支持html5才能用上此方法。ie8,ie9,ff,chrome,safari都是ok的

posted @ 2011-11-17 18:01  互联网的一块砖  阅读(1082)  评论(0编辑  收藏  举报