SmartQQ是騰訊新出的一個WebQQ,登錄地址是:http://w.qq.com/,目前之前的WebQQ可以繼續使用,登錄地址:http://web2.qq.com/webqq.html,SmartQQ相比之前的WebQQ要簡單清爽很多,而且手機端可以直接訪問,應該是騰訊為了在移動端做的一個調整,今天我把SmartQQ的登錄過程給大家分析下。
對於Http協議,如果大家還不熟悉的,可以去找相關資料學習下,現在我們直奔主題。
對於Http數據包的抓取和分析,我用的是firebug自帶的,當然其他的類似工具(fiddler,httpwatch,http analyzer)等都可以,看自己的喜好了。
首先截個完整的登錄成功的http協議的圖:

通過觀察分析,整個登錄過程大致如下:
1.當用戶在下圖中的用戶名中輸入QQ號或者郵箱地址的時候,會觸發一個異步請求:https://ssl.ptlogin2.qq.com/check?uin=34310374&appid=501004106&js_ver=10046&js_type=0
&login_sig=IV9iX*D7tkypySsivwFDX-9K7DpgiKofym0JShvCrXYmXsScMK6bHuJ-UddPD3Th
&u1=http%3A%2F%2Fw.qq.com%2Fproxy.html&r=0.6170404219718775

這個請求的意思是檢測當前輸入的賬號是否需要用驗證碼來登錄,其中u這個參數是用戶名,上面鏈接中的34310374是我的qq號碼,login_sig是登錄要用到的簽名,每次登錄的簽名都不一樣的,這個值稍候會說到如何提取到,這些參數是必要的動態參數,其余的參數目前發現是不變的,當然那些參數也可以提取到,為了防止這些參數以后會變,我都是通過動態提取的,做到萬無一失。
檢測是否需要驗證碼的參數提取
先看看載入http://w.qq.com的時候會做哪些事情,查看源代碼,里面最有用的一句是:
<iframe noscroll style="position:absolute;width:100%;height:100%;border:0;" src="https://ui.ptlogin2.qq.com/cgi-bin/login?daid=164&target=self&style=16&mibao_css=m_webqq&appid=501004106&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fw.qq.com/proxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20130723001"></iframe>
iframe的src是具體的登錄地址,通過iframe的src,我們可以獲取到appid(騰訊的每個web產品都有唯一的appid),login_state是登錄狀態,10表示在線,默認是在線。
繼續看看src地址的源代碼,發現在源代碼里面有一段這樣的腳本:
//參數只能為數字的
var g_version=encodeURIComponent("201309220930");
var g_pt_version=encodeURIComponent("10047");//發布版本號
var g_qtarget=encodeURIComponent("-1");
var isLoadVC = false;
var g_appid =encodeURIComponent("501004106");
var g_uin = 0;
var g_domain = encodeURIComponent("qq.com");
var g_target = encodeURIComponent("_self");
var g_https = true;
var g_low_login=encodeURIComponent("0");
var g_login_sig=encodeURIComponent("2mK7RUAmDy6JI3tSvPOs3PkLas*mM6g2bqffMx6dIvs11MiWf8mMDkPhm0UW3htZ"); //安全參數
var g_daid=encodeURIComponent("164");//業務隔離id
var g_regmaster=encodeURIComponent("");//雙登錄態
var g_forget="http://ptlogin2.qq.com/ptui_forgetpwd";
我們可以通過var g_login_sig的值得到login_sig。
這里我們用到了HttpWebRequest來進行http的模擬請求。(具體這個怎么用就不多說了,我自己封裝了一個HttpHelper的請求類,在文章的最后我會把這些代碼附上)
請求的結果如下:
ptui_checkVC('0','!XLF','\x00\x00\x00\x00\x02\x0b\x88\xe6');
返回的值有三個,第一個0表示不需要驗證碼,1表示需要驗證碼。當第一個為0的時候,第二個參數為驗證碼,第三個參數為uin,可以理解為驗證碼標識吧。
如果需要驗證碼,請求返回的是:
ptui_checkVC('1','dbec74e5b7b14c2479b675c7a1b76f5b8fd594067e8fd183','\x00\x00\x00\x00\x00\x34\x3f\xdf');
這時候,第二個值就沒什么用了,驗證碼是需要自己輸入的。
如果需要驗證碼的時候,我們要提取驗證碼圖片:
同樣用到的參數有appid和qq號碼。
第一次登陸
QQ的登陸有兩步,先看下一次登陸的請求地址:
&h=1&ptredirect=0&ptlang=2052&daid=164&from_ui=1&pttype=1&dumy=&fp=loginerroralert&action=0-18-15313
參數解析:
u表示qq號碼或者郵箱地址,p是加密后的密碼,verifycode表示驗證碼,如果前面檢測到需要驗證碼,這個值就是你輸入的驗證碼,否則就是檢測結果的第二個值。login_sig前面我們以前提取到了。
繼續模擬http請求,如果登陸成功,結果如下:
ptuiCB('0','0','http://ptlogin4.web2.qq.com/check_sig?pttype=1&uin=34310374&service=login&nodirect=0
&ptsig=DhJ8N-3qER1eSKmIoHFix*0LcUQN1IqG7XASHP1RzxE_&s_url=
http%3A%2F%2Fw.qq.com%2Fproxy.html%3Flogin2qq
%3D1%26webqq_type%3D10&f_url=&ptlang=2052&ptredirect=100&aid=501004106&daid=164&j_later=0&low_login_hour
=0®master=0',
'0','登錄成功!', '飛無痕落無聲');
返回的結果的第三個值,是需要繼續302的一個地址
繼續請求這個地址,這個地址主要的作用是賦值cookie和跳轉。
請求完畢后,接着進行第二次登陸。
第二次登陸
第二次登陸是一個post請求,請求的參數如下
r= {"ptwebqq":"667ca0404f9256dba6fe58dc9440733cbabcdb813dd5b2b13703b684240447bb","clientid":53999199,"psessionid":"","status":"online"}
其中ptwebqq是從cookie里面提取到的,clientid是自己構造的一個8位隨機9位數字
post的請求的結果如下:
{"retcode":0,"result":{"uin":34310374,"cip":2084660302,"index":1075,"port":47529,"status":"online","vfwebqq"
:"1571c0e077478cad6b3a36c159a1845f391ce90909f155be3022f1
c87
42b60f526354e2513105467",
"psessionid":"83
68046764001d636f6e6e7365727665725f77656271714031302e3133332e34312e383400003d8800001e
a00162020b88e66d
0000000a406771476958665165796d000000281571c0e077478cad6b3a36c159a1845f391ce90909f155be3022f1c8742b60f526354e2513105467"
,
"user_state":0,"f":0}}
retcode為0表是登錄成功了,后面的psessionid等參數再后面獲取qq聯系人和發消息會用到,下篇文章會講到。
至此,SmartQQ登錄完畢,這里面要主要的到時用HttpWebRequest的時候遇到cookie跨域的時候,某些cookie會訪問不到,必須手動修改cookie的域,這個問題折騰了不少時間,騰訊的cookie是好幾個子域的。
點擊下載代碼,歡迎大家交流和期待下面的文章,that'all。