当前位置:编程学习 > C#/ASP.NET >>

深入浅出阿里巴巴新版企业搜索

阿里巴巴做得很大,直接导致市面上针对其企业库的采集软件琳琅满目。此类采集软件的原理一般为:根据条件生成URL,再"GET"获取URL源代码,再分析出企业登录ID及网址等。

然而此次改版之后一夜间几乎所有软件都不能正常工作,一旦采集"beginPage=2"时便跳出“安全验证”。

闲暇之余深入研究了一下新版机制,发现一些有用的东西。

总体来说,此次改版改变原有的纯"GET"为"POST":
    PARAMETER NAME:token、ua
    token来自原文内固定字符串
    ua来自js函数生成

其中ua又由JS文件"http://acjs.aliyun.com/actionlog/js/ua.js"(点此下载)内函数生成。

研究ua.js发现,首先是加密方法组、方法名,例如以"ho2c"代替"window",采用方括号方式调用方法、参数(例如:window["document"]["body"]["scrollLeft"])。

方法名、参数名均需采用ua.js内函数"um(is,x,hw)"解密。

下面探讨ua的产生:

执行ua.js发现,ua.js给浏览器添加了很多监听事件。每次移动鼠标、单击等操作均产生特殊字符串,并以"|"隔开追加到ua后。生成"FORM":id="company-pageNav-form" method="POST",生成隐藏字段:

注意:所有js代码中均以"ho2c"代替"window"。


zf["init"] = function() {
                for (var gv = (0); gv < (3); gv++) {
                    if (gv == (0)) {
                        this['inited'] = true;
                    } else if (gv == (2)) {
                        this['all_data'] = new ho2c["Array"]();
                    }
                    if (gv == (1)) {
                        this["buffer"] = new ho2c["Array"]();
                    }
                    var sp = (5);
                    if (sp == (3)) {
                        eventIndex = 2;
                    }
                }
                if (typeof gf["SendInterval"] == "number" && gf["SendInterval"] > 0) {
                    if (! (0)) {
                        var b = (0);
                    } else {
                        b = (1);
                    }
                    if (!b) {
                        var uw = (2);
                    }
                    if (uw) {
                        this['SendInterval'] = gf['SendInterval'];
                    } else {
                        opt.t0s = UA_Opt.Token;
                    }
                } else {
                    this["SendInterval"] = 1;
                }
                var w3 = (1);
                while (! (w3 - (1))) {
                    if (w3 + (0)) {
                        this["img_url"] = gf["ImgUrl"];
                        w3 = w3 - (1);
                        continue;
                    }
                    opt.tj = 0;
                }
                if ((gf["SendMethod"] & 1) > 0) {
                    var rt2u = ho2c["document"]["getElementById"]("UA_InputId");
                    if (!rt2u) {
                        if (! (0)) {
                            var eh = (0);
                        } else {
                            eh = (1);
                        }
                        if (!eh) {
                            var kg = (2);
                        }
                        if (kg) {
                            var n = ho2c["document"]["getElementById"](gf["FormId"]);
                        } else {
                            opt.l0gt = [];
                        }
                        if (n) {
                            rt2u = ho2c["document"]["createElement"]("input");
                            rt2u["type"] = "hidden";
                            rt2u["name"] = "ua";
                            rt2u["id"] = 'UA_InputId';
                            var lbh = (0);
                            while (!lbh) {
                                if (lbh + (1)) {
                                    n["insertBefore"](rt2u, n["firstChild"]);
                                    lbh = lbh + (1);
                                    continue;
                                }
                                itLen += 2;
                            }
                        }
                    } else {
                        rt2u["value"] = '';
                    }
                }
                if ((gf["SendMethod"] & 8) > 0) {
                    if (gf["LogVal"]) {
                        var r9 = (1);
                        while (! (r9 - (1))) {
                            if (r9 + (0)) {
                                ho2c["eval"](gf["LogVal"] + '="";');
                                r9 = r9 - (1);
                                continue;
                            }
                            UAInput.nm = "uxa";
                        }
                    }
                }
            };


<input id="UA_InputId" type="hidden" name="ua" value="155rTEdMTA7Ozk4MDg5MTczN6Q=|rTIdrRCBn7qTkJa/EB0xOx0QoZ+UkZawuBCkpA==|rTAdrTUzHTMdMTsyMB04OTA5HTE7OzMdNTMzHTE7OzMdNzozpKQ=|rTEyHRAxmjmTOZExMps7kTM1kzGTmpqbmJuaMZsyOJExmzKTOTEwOzs5ODA4OTk6MDoQpA==|rTEwHa0QoZ+UkZawuBE4EB0QoY6FETExHTAdMDMzHTI6NxCkpA==|rTEzHRCtMDU5MTkdphAxMDs7OzE7ODM6ODA3tzMcNTMzOzk6OjsxOzs6Nzg6MaYQHTGkEKQ=|rTgdrRAQHTMdNzo7NaSk">
<input id="company_pagenav_token" type="hidden" name="token" value="1c5e5d12a4d09e1eccabac1a27d1a2e51344573755636">


并且添加监听SOCKET FLASH到隐藏DIV

<div style="height: 0px; width: 0px; overflow: hidden;">
<object id="JSocket" width="0" height="0" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" style="height:0;width:0;overflow:hidden;">
<param value="always" name="allowScriptAccess">
<param value="http://acjs.aliyun.com/actionlog/flash/JSocket.swf" name="movie">
<embed width="0" height="0" pluginspage="http://www.adobe.com/go/getflashplayer_cn" type="application/x-shockwave-flash" allowscriptaccess="always" name="JSocket" src="http://acjs.aliyun.com/actionlog/flash/JSocket.swf">
</object>
</div>


也就是说每一次你移动鼠标、单击等操作,都产生一个加密字符串,追加到ua后,并且发送到阿里巴巴的服务器端。"POST"的时候服务端会比对本地"POST"的ua/token值,若不对则要求安全验证。

下面是解密后的字符串加密函数:

tv = function(sk2p) {
                var hu = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
                var clvj,
                ef,
                kk = 0,
                gzy = '';
                while (sk2p["length"] >= kk + 3) {
                    var th = (0);
                    for (var f7 = (0); f7 <= (7); th = ++f7 + f7+++f7) {
                        if (f7 == th) {
                            clvj = (sk2p["charCodeAt"](kk++) & 255) << 16 | (sk2p["charCodeAt"](kk++) & (255)) << 8 | sk2p["charCodeAt"](kk++) & 255;
                            continue;
                        }
                        if (2 * f7 == th - (5)) {
                            gzy += hu["charAt"]((clvj & (4032)) >> 6);
                            break;
                        }
                        if (2 * f7 == th - 2) {
                            gzy += hu["charAt"]((clvj & 258048) >> 12);
                            f7++;
                        }
                        if ((3) * f7 == th + 2) {
                            gzy += hu["charAt"]((clvj & 16515072) >> 18);
                        }
                    }
                    gzy += hu["charAt"]((clvj & 63));
                }
                if (sk2p["length"] - kk > (0) && sk2p["length"] - kk < 3) {
                    ef = ho2c["Boolean"](sk2p["length"] - kk - 1);
                    clvj = ((sk2p["charCodeAt"](kk++) & 255) << 16) | (ef ? (sk2p["charCodeAt"](kk) & 255) << 8: 0);
                    gzy += hu["charAt"]((clvj & 16515072) >> 18);
                    gzy += hu["charAt"]((clvj & 258048) >> (12));
                    var cw = (1);
                    var qg = (0);
                    switch ((++qg - cw--) * cw) {
                    case(0):
                        gzy += (ef ? hu["charAt"]((clvj & (4032)) >> (6)) : '=');
                    case(1):
                        gzy += '=';
                        break;
                    case (2):
                        pd = ax.ciraw();
                    }
                }
                return gzy;
            };


原理摸清了,下面探讨在winform下怎样采集新版阿里巴巴企业库。

方法一:.net webbrower(已验证)

思路:
1、加载"beginPage=1"页面;
2、页面加载完毕后等待1秒左右,模拟鼠标单击操作(Left click down/up,左键点下、释放);
代码如下:

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
 
        private void mclick()
        {
            Random r = new Random();
            int x = r.Next(400); 
            int y = r.Next(800);
            IntPtr handle = webBrowser1.Handle;
            StringBuilder className = new StringBuilder(100);
            while (className.ToString() != "Internet Explorer_Server") 
            {
                handle = GetWindow(handle, 5);
                GetClassName(handle, className, className.Capacity);
            }

            IntPtr lParam = (IntPtr)((y << 16) | x);
            IntPtr wParam = IntPtr.Zero; 
            const uint downCode = 0x201; 
            const uint upCode = 0x202; 
            SendMessage(handle, downCode, wParam, lParam);
            SendMessage(handle, upCode, wParam, lParam); 
        }

3、模拟执行点击页面页数链接,让页面自己"POST"(webBrowser1.Document.All[i].InvokeMember("click"););

说明:整个过程中鼠标没有任何操作,一切靠软件模拟。模拟结果能成功获取企业库,每次"POST"的间隔最好大于500毫秒,否则容易被“安全验证”。

方法二:serverXMLHTTP或者winHttp(未验证)

思路:(未验证)
全面破解ua.js的鼠标移动、单击等操作,并抓包分析Jsocket.swf的工作原理。
后台随机构造鼠标点击字符串并发送到阿里服务端。

此方法如果得以实现,将继续可以采用高效率的serverXMLHTTP或者winHttp来采集。留待后续分析。 --------------------编程问答-------------------- 虽然不懂js 但是看懂了大概意思 不错 顶顶 --------------------编程问答-------------------- 楼主研究的比较透彻啊 学习了 --------------------编程问答-------------------- 楼主厉害,收藏之 --------------------编程问答-------------------- 看上去很牛逼的样子
--------------------编程问答-------------------- 好东西,一定要认真学习 --------------------编程问答-------------------- 嗯,看上去和牛X的样子。 --------------------编程问答-------------------- 用第一种方法,模拟发送End键路过,有没有高人用第二种方法的 --------------------编程问答-------------------- 模拟发送End按键路过,等待有没有高人验证第二种方法的 --------------------编程问答-------------------- 楼主很厉害啊。学习。 --------------------编程问答-------------------- 楼主很厉害,学习下, --------------------编程问答-------------------- 唉,多发了一条。不能删除自己的 就是不好。。 --------------------编程问答-------------------- SELECT top 300  id,Command_Send.MeterId,RevCommand,ExDate,Fn,zb,pointid FROM         Command_Send   left join  (select MonitorInfo.addr1,MonitorInfo.addr2,zb,MeterId,pointid from MonitorInfo inner join MonitorUserList on MonitorUserList.addr1=MonitorInfo.addr1 and MonitorUserList.addr2=MonitorInfo.addr2  where zb=1) as t on t.addr1=Command_Send.addr1 and t.addr2=Command_Send.addr2 and t.MeterId=Command_Send.MeterId where SendType in(1,2,5,6) and  RevFlag=1 --------------------编程问答-------------------- 我也是卡在这里 --------------------编程问答-------------------- 楼主看上去很牛逼啊 --------------------编程问答-------------------- 在webbrowers中模拟鼠标点击,
用node.InvokeMember("click")引发click事件,在click中继续调用 mclick()和node.InvokeMember("click")引发click事件,如此循环
但是却在打开第二页的时候 还是需求验证码 ,疑惑,求解。 --------------------编程问答-------------------- 不懂阿里,看上去很靠谱 --------------------编程问答-------------------- 。。放爬虫 防到这种地步了啊。。。 --------------------编程问答-------------------- ua.js好像还过一段时间变一次,这个变好像是文字上的改变,不知道加密函数有没有变。 --------------------编程问答-------------------- 新手学习下,LZ是否愿意分享下UA.JS的源码,ohku@qq.com 谢谢 --------------------编程问答-------------------- 新手学习下   看下有什么有用的
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,