深入浅出阿里巴巴新版企业搜索
阿里巴巴做得很大,直接导致市面上针对其企业库的采集软件琳琅满目。此类采集软件的原理一般为:根据条件生成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#