webqq登入協議分析
通過webqq介面,可以實現發送、接收qq訊息。
1。首先調用:http://ptlogin2.qq.com/check?appid=1002101&uin=qq號碼&js_ver=10034&js_type=0&login_sig=g3W6wI0s*Da9mp6xHYdgm7iP-D7LBMId01umPiT0WTQQShsmCdWxgBD8vtI6Gltq&u1=http%3A%2F%2Fweb.qq.com%2Fmain.shtml%3Fdirect_13_13&r=
擷取該qq號碼驗證碼之類的資訊。看返回結果決定是不是要輸入驗證碼登陸。
如果返回:ptui_checkVC('1','95ab7db15e5ab17f50f25d33598259e83ccc098c4af2f8a4');需要輸入驗證碼,這裡需要記住這個長字串(擷取驗證碼圖片用)以及cookie
如果返回:ptui_checkVC('0','!MPG');不需要輸入驗證碼,驗證碼值用!MPG代替。可能為其他字串,但是以驚嘆號開頭
如果需要輸入驗證碼:則調用:
http://captcha.qq.com/getimage?aid=1002101&&uin=qq號碼&r=隨機數
擷取驗證碼圖片。。。
2。開始登陸,在登陸之前,需要將密碼進行hash,hash方法很複雜,但是研究其登入js檔案,發現:
function getSubmitUrl(K) { var E = true; var C = document.forms[0]; var A = (pt.isHttps ? "https://ssl.": "http://") + "ptlogin2." + g_domain + "/" + K + "?"; var B = document.getElementById("login2qq"); if (pt.regmaster == 2) { A = "http://ptlogin2.function.qq.com/" + K + "?regmaster=2&" } else { if (pt.regmaster == 3) { A = "http://ptlogin2.crm2.qq.com/" + K + "?regmaster=3&" } } for (var J = 0; J < C.length; J++) { if (K == "ptqrlogin" && (C[J].name == "u" || C[J].name == "p" || C[J].name == "verifycode" || C[J].name == "h")) { continue } if (C[J].name == "ipFlag" && !C[J].checked) { A += C[J].name + "=-1&"; continue } if (C[J].name == "fp" || C[J].type == "submit") { continue } if (C[J].name == "ptredirect") { g_ptredirect = C[J].value } if (C[J].name == "low_login_enable" && (!C[J].checked)) { E = false; continue } if (C[J].name == "low_login_hour" && (!E)) { continue } if (C[J].name == "webqq_type" && !B && (!C[J].checked)) { continue } A += C[J].name; A += "="; if (C[J].name == "u" && pt.needAt) { A += pt.needAt + "&"; continue } if (C[J].name == "p") { var M = C.p.value; var I = hexchar2bin(md5(M)); var H = md5(I + pt.uin); var G = md5(H + C.verifycode.value.toUpperCase()); A += G } else { if (C[J].name == "u1" || C[J].name == "ep") { var D = C[J].value; var L = ""; if (g_appid == "1003903" && B) { L = /\?/g.test(D) ? "&": "?"; var F = document.getElementById("webqq_type").value; L += "login2qq=" + B.value + "&webqq_type=" + F } A += encodeURIComponent(D + L) } else { A += C[J].value } } A += "&" } A += "fp=loginerroralert&action=" + pt.action.join("-") + "-" + (new Date() - g_begTime) + "&mibao_css=" + pt.mibao_css + "&t=" + pt.submitN[pt.uin] + "&g=1"; A += "&js_type=" + pt.js_type + "&js_ver=" + window.g_pt_version + "&login_sig=" + window.g_login_sig; return A}
其中的:
if (C[J].name == "p") { var M = C.p.value; var I = hexchar2bin(md5(M)); var H = md5(I + pt.uin); var G = md5(H + C.verifycode.value.toUpperCase()); A += G
便是其hash方法,研究發現其md5與python md5是一致的(對於c#貌似兩者計算的md5有區別)
對於hexchar2bin函數,可以使用參考其js代碼寫出相應的python版本:
def hexchar2bin(self,str):arr = []for i in range(0, len(str) , 2):arr.append("\\x" + str[i:i+2])arr="".join(arr)exec("temp = '" + arr + "'");return temp
3、正式登入:
url = self.scheme + "ptlogin2.qq.com/login?u=" + self.qq + "&p=" + p + "&verifycode=" + VERIFYCODE + "&webqq_type=1&remember_uin=1&aid=1002101&u1=http%3A%2F%2Fweb.qq.com%2Fmain.shtml%3Fdirect_13_13&h=1&ptredirect=1&ptlang=2052&from_ui=1&pttype=1&dumy=&fp=loginerroralert&action=7-31-419619&mibao_css=&t=2&g=1&js_type=0&js_ver=10034"
登陸成功後,要記住返回的cookie值(其中的ptwebqq在之後需要使用)
正式登入web QQ:
url = 'http://d.web2.qq.com/channel/login2'header={'Referer':'http://d.web2.qq.com/proxy.html?v=20110331002&callback=1&id=2'}
POST的data包含:ptwebqq,clientid等參數
如果成功:
會返回一個json資料結構:
{"retcode":0,"result":{"uin":qq號 碼,"mode":"master","index":1055,"port":38138,"status":"online","vfwebqq":"f72a8722c988252aef4e0268f1d26a3d647f06f6ff353a5c6cdaaa49abb2fcdf0cee2d8d64373ac2","psessionid":"8368046764001D636F6E6E7365727665725F77656271714031302E3133332E332E3234300000235100000B79026E040043F60C166D0000000A404746365677767041316D00000028F72A8722C988252AEF4E0268F1D26A3D647F06F6FF353A5C6CDAAA49ABB2FCDF0CEE2D8D64373AC2"}}
記住其中的psessionid以及vfwebqq,後面在發送訊息和擷取qq訊息都需要這2個參數。