php模擬登錄QQ空間3.0 2014-11-23

        本人不太喜歡玩qq空間的,最近加了一個QQ好友,看頭像貌似一個大叔。錯了,是他加的我,他諮詢我微信自動打招呼不能使用的問題,本來上班就挺閒的,於是就和他聊開了。他問了我一句話,我頓時汗顏,感覺愧對自己這一兩年。什麼話呢?他說“最羨慕我們這羣在網絡上賺錢的了,你在網上轉了幾十萬了吧?”。由此我內疚啊,幾十萬角還是幾十萬元,勒個。這些都是引言,他給我啓發,我能否寫一個網頁工具,讓用戶導出他自己的QQ羣好友呢,導出QQ成員郵箱呢?現在電子商務那麼發達,有好些人都藉助QQ羣做營銷,QQ號碼的作用也就可想而知了 。上週五的 時候我找了個軟件,自動提取QQ羣成員的軟件,能是能用,罵了隔壁的要收費。不說這些了,言歸正傳。

首先我找到QQ空間的登錄界面i.qq.com,抓一下包 這裏是想嘗試找到他的登錄鏈接,以及上傳的參數信息。爲了調試簡便,直接找他的登錄表單,地址是:http://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=http%3A//qzs.qq.com/qzone/v6/portal/proxy.html&daid=5&pt_qzone_sig=1&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&appid=549000912&style=22&target=self&s_url=http%3A//qzs.qq.com/qzone/v5/loginsucc.html?para=izone&pt_qr_app=%E6%89%8B%E6%9C%BAQQ%E7%A9%BA%E9%97%B4&pt_qr_link=http%3A//z.qzone.com/download.html&self_regurl=http%3A//qzs.qq.com/qzone/v6/reg/index.html&pt_qr_help_link=http%3A//z.qzone.com/download.html,這麼長一串,看着頭都暈了吧,這個地址不用管它,是寫死的。



請求這個頁面,會返回一個重要的參數,查看這個頁面的源碼,裏面有個login_sig的玩意,登錄的簽名標識,這個參數在檢查登錄是否需要驗證碼的時候會用到


開啓網絡監聽可以發現,在輸入完QQ號碼的時候,也就是QQ號碼輸入框失去焦點的時候,瀏覽器會發一個請求到騰訊服務器,檢查此次登錄是否需要輸入驗證碼。請求地址:http://check.ptlogin2.qq.com/check?regmaster=&uin=qq號碼&appid=549000912&js_ver=10100&js_type=1&login_sig=-C312hp6B8CxoeIKpP*g2HaPLthAwHxTGa5u5WRgaDwrDi*3DrpjYwh38eh8-nyu&u1=http%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&r=0.22668678383342922,login_sig是上面得到的安全登錄簽名標識,其它參數可以不變,這個請求會返回一個字符串,ptui_checkVC('0','!GGG','\x00\x00\x00\x00\x23\xe8\xf1\xd0','ffa99a5e8b464c05ab1666287089353996556b1c4964173e52ac0d76716f2d5676c8b41555aa551e5ad33146945d2041');

這裏有四個參數,第一個參數爲是否需要驗證碼,1是,0否。如果第一個參數是0,那麼第二個參數直接就是驗證碼,如果第,一個參數是1,第二個參數則是獲取驗證碼的密文,第三個參數不用管它,第四個參數爲登錄的時候需要的 pt_verifysession_v1參數,除了第三個參數外,這幾個都是很重要的參數。注意,如果此次登錄需要驗證碼,那麼第四個參數是空的,那麼登錄是需要的pt_verifysession_v1參數怎麼得到呢


如果登錄需要驗證碼,瀏覽器會發一個請求獲取驗證圖片,地址是:http://captcha.qq.com/getimage?uin=$qq&aid=549000912&cap_cd=$p2&0.7444603350013494 ,

這裏我們只需要注意一下cap_cd這個參數,這個參數是上面講的第二個參數。這個請求回返回一個cookies值,這個值是保持當前驗證碼和登錄一直的重要參數,抓包的時候查看cookies可以看到verifysession。

以上都是登錄前的參數收集,現在我們來看一下登錄地址:http://ptlogin2.qq.com/login?u=qq號&verifycode=驗證碼&pt_vcode_v1=0&pt_verifysession_v1=驗證碼返回的verifysession&p=加密的密碼&pt_rsa=0&u1=http%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=2-10-1416737142521&js_ver=10100&js_type=1&login_sig=安全登錄標識符&pt_uistyle=32&aid=549000912&daid=5&pt_qzone_sig=1&

經過之前的收集 ,我們發現這裏只有一個參數我們未知。那就是p參數,那麼是怎麼加密的呢,我們查看源碼,會發現這樣一個js文件


加密的算法都在裏面了,經過查看源碼,我們可以看到它的加密方式,先將密碼md5加密,再講加了密的密碼轉換爲二進制碼,然後再和QQ號首尾相連進行md5加密,結果在和驗證碼首尾相連md5加密,挺複雜的。加密獲取p參數  var p = $.Encryption.getEncryption(password,$.str.uin2hex(qq), verifycode);

$.Encryption = function() {
    var hexcase = 1;
    var b64pad = "";
    var chrsz = 8;
    var mode = 32;
    function md5(s) {
        return hex_md5(s)
    }
    function hex_md5(s) {
        return binl2hex(core_md5(str2binl(s), s.length * chrsz))
    }
    function str_md5(s) {
        return binl2str(core_md5(str2binl(s), s.length * chrsz))
    }
    function hex_hmac_md5(key, data) {
        return binl2hex(core_hmac_md5(key, data))
    }
    function b64_hmac_md5(key, data) {
        return binl2b64(core_hmac_md5(key, data))
    }
    function str_hmac_md5(key, data) {
        return binl2str(core_hmac_md5(key, data))
    }
    function core_md5(x, len) {
        x[len >> 5] |= 128 << ((len) % 32);
        x[(((len + 64) >>> 9) << 4) + 14] = len;
        var a = 1732584193;
        var b = -271733879;
        var c = -1732584194;
        var d = 271733878;
        for (var i = 0; i < x.length; i += 16) {
            var olda = a;
            var oldb = b;
            var oldc = c;
            var oldd = d;
            a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
            d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
            c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
            b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
            a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
            d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
            c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
            b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
            a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
            d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
            c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
            b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
            a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
            d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
            c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
            b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
            a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
            d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
            c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
            b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
            a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
            d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
            c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
            b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
            a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
            d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
            c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
            b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
            a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
            d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
            c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
            b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
            a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
            d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
            c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
            b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
            a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
            d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
            c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
            b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
            a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
            d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
            c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
            b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
            a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
            d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
            c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
            b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
            a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
            d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
            c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
            b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
            a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
            d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
            c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
            b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
            a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
            d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
            c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
            b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
            a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
            d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
            c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
            b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
            a = safe_add(a, olda);
            b = safe_add(b, oldb);
            c = safe_add(c, oldc);
            d = safe_add(d, oldd)
        }
        if (mode == 16) {
            return Array(b, c)
        } else {
            return Array(a, b, c, d)
        }
    }
    function md5_cmn(q, a, b, x, s, t) {
        return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b)
    }
    function md5_ff(a, b, c, d, x, s, t) {
        return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t)
    }
    function md5_gg(a, b, c, d, x, s, t) {
        return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t)
    }
    function md5_hh(a, b, c, d, x, s, t) {
        return md5_cmn(b ^ c ^ d, a, b, x, s, t)
    }
    function md5_ii(a, b, c, d, x, s, t) {
        return md5_cmn(c ^ (b | (~d)), a, b, x, s, t)
    }
    function core_hmac_md5(key, data) {
        var bkey = str2binl(key);
        if (bkey.length > 16) {
            bkey = core_md5(bkey, key.length * chrsz)
        }
        var ipad = Array(16),
        opad = Array(16);
        for (var i = 0; i < 16; i++) {
            ipad[i] = bkey[i] ^ 909522486;
            opad[i] = bkey[i] ^ 1549556828
        }
        var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
        return core_md5(opad.concat(hash), 512 + 128)
    }
    function safe_add(x, y) {
        var lsw = (x & 65535) + (y & 65535);
        var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
        return (msw << 16) | (lsw & 65535)
    }
    function bit_rol(num, cnt) {
        return (num << cnt) | (num >>> (32 - cnt))
    }
    function str2binl(str) {
        var bin = Array();
        var mask = (1 << chrsz) - 1;
        for (var i = 0; i < str.length * chrsz; i += chrsz) {
            bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32)
        }
        return bin
    }
    function binl2str(bin) {
        var str = "";
        var mask = (1 << chrsz) - 1;
        for (var i = 0; i < bin.length * 32; i += chrsz) {
            str += String.fromCharCode((bin[i >> 5] >>> (i % 32)) & mask)
        }
        return str
    }
    function binl2hex(binarray) {
        var hex_tab = hexcase ? "0123456789ABCDEF": "0123456789abcdef";
        var str = "";
        for (var i = 0; i < binarray.length * 4; i++) {
            str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 15) + hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 15)
        }
        return str
    }
    function binl2b64(binarray) {
        var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        var str = "";
        for (var i = 0; i < binarray.length * 4; i += 3) {
            var triplet = (((binarray[i >> 2] >> 8 * (i % 4)) & 255) << 16) | (((binarray[i + 1 >> 2] >> 8 * ((i + 1) % 4)) & 255) << 8) | ((binarray[i + 2 >> 2] >> 8 * ((i + 2) % 4)) & 255);
            for (var j = 0; j < 4; j++) {
                if (i * 8 + j * 6 > binarray.length * 32) {
                    str += b64pad
                } else {
                    str += tab.charAt((triplet >> 6 * (3 - j)) & 63)
                }
            }
        }
        return str
    }
    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
    }
    function getEncryption(password, uin, vcode, isMd5) {
        var str1 = hexchar2bin(isMd5 ? password: md5(password));
        var str2 = md5(str1 + uin);
        var str3 = md5(str2 + vcode.toUpperCase());
        return str3
    }
    function getRSAEncryption(password, vcode, isMd5) {
        var str1 = isMd5 ? password: md5(password);
        var str2 = str1 + vcode.toUpperCase();
        var str3 = $.RSA.rsa_encrypt(str2);
        return str3
    }
    return {
        getEncryption: getEncryption,
        getRSAEncryption: getRSAEncryption,
        md5: md5
    }
} ();

$.str = (function() {
    var htmlDecodeDict = {
        quot: '"',
        lt: "<",
        gt: ">",
        amp: "&",
        nbsp: " ",
        "#34": '"',
        "#60": "<",
        "#62": ">",
        "#38": "&",
        "#160": " "
    };
    var htmlEncodeDict = {
        '"': "#34",
        "<": "#60",
        ">": "#62",
        "&": "#38",
        " ": "#160"
    };
    return {
        decodeHtml: function(s) {
            s += "";
            return s.replace(/&(quot|lt|gt|amp|nbsp);/ig,
            function(all, key) {
                return htmlDecodeDict[key]
            }).replace(/&#u([a-f\d]{4});/ig,
            function(all, hex) {
                return String.fromCharCode(parseInt("0x" + hex))
            }).replace(/&#(\d+);/ig,
            function(all, number) {
                return String.fromCharCode( + number)
            })
        },
        encodeHtml: function(s) {
            s += "";
            return s.replace(/["<>& ]/g,
            function(all) {
                return "&" + htmlEncodeDict[all] + ";"
            })
        },
        trim: function(str) {
            str += "";
            var str = str.replace(/^\s+/, ""),
            ws = /\s/,
            end = str.length;
            while (ws.test(str.charAt(--end))) {}
            return str.slice(0, end + 1)
        },
        uin2hex: function(str) {
            var maxLength = 16;
            str = parseInt(str);
            var hex = str.toString(16);
            var len = hex.length;
            for (var i = len; i < maxLength; i++) {
                hex = "0" + hex
            }
            var arr = [];
            for (var j = 0; j < maxLength; j += 2) {
                arr.push("\\x" + hex.substr(j, 2))
            }
            var result = arr.join("");
            eval('result="' + result + '"');
            return result
        },
        bin2String: function(a) {
            var arr = [];
            for (var i = 0,
            len = a.length; i < len; i++) {
                var temp = a.charCodeAt(i).toString(16);
                if (temp.length == 1) {
                    temp = "0" + temp
                }
                arr.push(temp)
            }
            arr = "0x" + arr.join("");
            arr = parseInt(arr, 16);
            return arr
        },
        utf8ToUincode: function(s) {
            var result = "";
            try {
                var length = s.length;
                var arr = [];
                for (i = 0; i < length; i += 2) {
                    arr.push("%" + s.substr(i, 2))
                }
                result = decodeURIComponent(arr.join(""));
                result = $.str.decodeHtml(result)
            } catch(e) {
                result = ""
            }
            return result
        },
        json2str: function(obj) {
            var result = "";
            if (typeof JSON != "undefined") {
                result = JSON.stringify(obj)
            } else {
                var arr = [];
                for (var i in obj) {
                    arr.push("'" + i + "':'" + obj[i] + "'")
                }
                result = "{" + arr.join(",") + "}"
            }
            return result
        },
        time33: function(str) {
            var hash = 0;
            for (var i = 0,
            length = str.length; i < length; i++) {
                hash = hash * 33 + str.charCodeAt(i)
            }
            return hash % 4294967296
        }
    }
})();


好了 ,參數都收集齊了,可以去登錄了

登陸返回數據包

58
ptuiCB('0','0','http://web.qq.com/loginproxy.html?login2qq=1&webqq_type=10','0','登錄成功!','dzzzzzzzz');

0

QQ登陸錯誤數據包
ptuiCB('7','0','','0','很遺憾,網絡連接出現異常,請您稍後再試。(2772435371)', '624475210');
ptuiCB('3','0','','0','您輸入的帳號或密碼不正確,請重新輸入。', '624475210');
ptuiCB('4','3','','0','登錄失敗,請重試。*', '624475210');
ptuiCB('4','2','','0','頁面過期,請重試。(1485832416)', '602468816');


最後總結一下php模擬登錄的幾個步驟:

1、訪問登錄頁面,獲取login_sig參數,php中通過stream_get_contents函數獲取網頁內容,通過preg_match正則匹配可獲得login_sig

2、檢查本次登錄是否需要驗證碼,獲取驗證碼,verifysession參數.

3、如果需要驗證碼,則獲取驗證碼圖片和返回的verifysession,

function _getVImg($url = "", $filename = "") { 

$cookie_file = dirname(__FILE__).'/cookie.txt';

if(is_dir(basename($filename))) { 

echo "The Dir was not exits"; 

Return false; 

//去除URL連接上面可能的引號 

$url = preg_replace( '/(?:^[\'"]+|[\'"\/]+$)/', '', $url ); 

$hander = curl_init(); 

$fp = fopen($filename,'wb'); 

curl_setopt($hander,CURLOPT_URL,$url); 

curl_setopt($hander,CURLOPT_FILE,$fp); 

curl_setopt($hander,CURLOPT_HEADER,0); 

//curl_setopt($hander,CURLOPT_FOLLOWLOCATION,1); 

curl_setopt($hander, CURLOPT_COOKIEJAR,  $cookie_file); //存儲cookies

//curl_setopt($hander,CURLOPT_RETURNTRANSFER,false);//以數據流的方式返回數據,當爲false是直接顯示出來 

curl_setopt($hander,CURLOPT_TIMEOUT,60); 


$content=curl_exec($hander); 

curl_close($hander); 

$fp2 = fopen($cookie_file,'r');

$ses='';

while(!feof($fp2))

{

$ses.=fgets($fp2);

}

$nodle='verifysession ';

$sw= strstr($ses,$nodle);

$result = trim(str_replace($nodle,'',$sw));



fclose($fp); 

fclose($fp2); 

Return $result; 

4、對密碼進行加密,得到需要的p參數

var p = $.Encryption.getEncryption(password,$.str.uin2hex(qq), verifycode);

5、構建登錄地址:http://ptlogin2.qq.com/login?u=qq號&verifycode=驗證碼&pt_vcode_v1=0&pt_verifysession_v1=驗證碼返回的verifysession&p=加密的密碼&pt_rsa=0&u1=http%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=2-10-1416737142521&js_ver=10100&js_type=1&login_sig=安全登錄標識符&pt_uistyle=32&aid=549000912&daid=5&pt_qzone_sig=1&   把參數放進去就行了。接下來你知道該怎麼做了吧

大功告成!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章