It is better to teach people to fish than to teach them to fish. Today we will share a process of analyzing qq encryption.
Tool: debugging tool provided by Google's browser (call out by F12 in the browser)
The entire process lasts for four hours.
Call onFormSubmit when submitting
function onFormSubmit(form){ if (form.remember_uin.checked){ return ptui_onLoginEx(form, "qq.com") }else{ var myDate=new Date(); myDate.setFullYear(1971,1,1); pt.cookie.set("ptui_loginuin", "", myDate, '/', 'ui.ptlogin2.qq.com'); return ptui_onLogin(form); }}
If you do not select Save Password to callptui_onLogin
function ptui_onLogin(A) { try { if (parent.ptlogin2_onLogin) { if (!parent.ptlogin2_onLogin()) { return false } } if (parent.ptlogin2_onLoginEx) { var D = A.u.value; var B = A.verifycode.value; if (str_uintip == D) { D = "" } if (!parent.ptlogin2_onLoginEx(D, B)) { return false } } } catch(C) {} return ptui_checkValidate(A)}
Next, callptui_checkValidate(A)
Function ptui_checkValidate (B) {var A = B. u; // obtain the user name var D = B. p; // obtain the password var E = B. verifycode; // obtain the verification code if (. value = "" | str_uintip =. value) {pt. show_err (str_no_uin);. focus (); return false}. value =. value. trim (); if (! Pt. chkUin (. value) {pt. show_err (str_inv_uin);. focus ();. select (); return false} if (D. value = "") {pt. show_err (str_no_pwd); D. focus (); return false} if (E. value = "") {if (! IsLoadVC) {loadVC (true); g_submitting = true; return false} pt. show_err (str_no_vcode); try {E. focus ()} catch (C) {} if (! G_loadcheck) {ptui_reportAttr (78028)} else {ptui_reportAttr (78029)} return false} if (E. value. length & lt; 4) {pt. show_err (str_inv_vcode); E. focus (); E. select (); return false} if (isLoadVC & amp ;! (/^ [A-zA-Z0-9] + $ /. test (E. value) {pt. show_err (str_correct_vcode); E. focus (); E. select (); return false} D. setAttribute ("maxlength", "32"); ajax_Submit (); ptui_reportNum (g_changeNum); g_changeNum = 0; return true}
Then:
function ajax_Submit() { if (pt.checkRet == -1 || pt.checkRet == 3) { pt.show_err(pt.checkErr[window.g_lang]); try { $("p").focus() } catch(B) {} return } var A = getSubmitUrl("login"); pt.winName.set("login_param", encodeURIComponent(login_param)); pt.loadScript(A); return}
Finally, encrypt the Assembly submission address in this function:
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}
The core encryption code is as follows:
If (C [J]. name = "p") {var M = C. p. value; var I = hexchar2bin (md5 (M); var H = md5 (I + pt. uin); // pt. uin is estimated to be the hexadecimal representation of the user's QQ number var G = md5 (H + C. verifycode. value. toUpperCase (); A + = Gvar M = "××××××"; var ver = "! "; Var I = hexchar2bin (md5 (M); var H = md5 (I + pt. uin); var G = md5 (H + ver. toUpperCase ());
The hexchar2bin algorithm is as follows:
function hexchar2bin(str) { var arr = []; for (var i = 0; i < str.length; i = i + 2) { arr.push("\\x" + str.substr(i, 2)) } arr = arr.join(""); eval("var temp = '" + arr + "'"); return temp}
The final encryption process is as follows:
md5(md5(hexchar2bin(md5(pwd))+uin)+verifycode.toUpperCase())#!jsmd5(md5(hexchar2bin(md5("××××××××"))+'\x00\x00\x00\x00\x01\xd3\xff\xf3')+"!EHZ")"918AAFDF8C9481F7AC2FC1C89A4DED7B"
Here pt. uin is changed:
function ptui_checkVC(A, C, B) { clearTimeout(checkClock); pt.checkRet = A; pt.uin = B; if (A == "2") { g_uin = "0"; pt.show_err(str_inv_uin) } if (!pt.submitN[B]) { pt.submitN[B] = 1 } var E = new Date(); g_time.time7 = E; var D = { "12": g_time.time7 - g_time.time6 }; if (!curXui) { ptui_speedReport(D) } g_loadcheck = false; switch (A + "") { case "0": case "2": case "3": $("verifycode").value = C || "abcd"; loadVC(false); break; case "1": $("verifycode").value = pt.needCodeTip ? str_codetip: ""; loadVC(true); break; default: break }}
In fact, it took very little time to find this algorithm, but it was still unable to find the place where ptui_checkVC was called. Later, I suddenly realized that when I verified whether qq needed the image verification code, I returned a call to js. The address is:
https://ssl.ptlogin2.qq.com/chec ... 5Q4YxDJ8Rza4-1ubGMR*aruR6Byct1dQ&u1=http%3A%2F%2Fweb2.qq.com%2Floginproxy.html&r=0.5011255156714469
The returned content is as follows:
ptui_checkVC('0','!BGC','\x00\x00\x00\x00\x01\xd3\xff\xf3');
The third parameter is the QQ number in hexadecimal notation.
This is all done, and the rest is programming. Https access. You can try libcurl or use openssl + socket.