webqq加密js参数分析

以下是分析实例:
今天来说说WEBQQ登陆过程的分析,抛砖引玉而已


第一步:使用HttpWatch 软件抓取webQQ页面从打开至登陆成功到所有数据包。我们所有到操作均在这里面查找。

等待抓包中.....  这里为了方便 我已经登陆成功一个号码并且抓包成功。 抓包方法很简单  打开IE  打开HttpWatch 点击记录后 开始一系列的登陆操作直到登陆成功后。停止抓

第二步:我们重新打开一个webqq登陆页面。来分析网页源代码。(这里建议大家使用 Chrome 谷歌浏览器。比较方便。它本身带有一个 WEB前端助手 很好)这个前端助手自行安装

1 <input autocomplete="on" name="u" id="u" type="text" style="ime-mode:disabled" class="input01" tabindex="1" value="QQ号码或Email帐号">
2 <input name="p" id="p" maxlength="16" type="password" class="input01" tabindex="2">
3 <input type="submit" class="signin-btn signin2" value="" tabindex="6" id="login_button">

4 <form id="loginform" autocomplete="off" name="loginform" action="http://ptlogin2.qq.com/login" method="post" target="_self" style="margin:0px;">
依次使用 审查元素 查看用户名输入框 密码输入框 和 登陆按钮。这里就要知道HTML的基本概念里  <form></form>这个范围内就是一个表单。提交到是这个范围内到内容。所以 我们要在源代码里找找<form
得到上述结果
第一个用户名框  我们关注一点  name="u"   表示QQ号是从这个框里获取。名字就是 u
第二个是密码输入框  同理  name="p"    表示密码框就是 P
第三个是登陆按钮  type为 submit 表示这是一个提交按钮。点这个就让这个表单提交
第四个就是这个表单的基础信息。我们关注一点    onsubmin 事件表示 该表单被提交。这里就表示 当用户提交表单(点击登陆按钮)后。执行onFormSubmit这个过程。关键1

第三步
我们就需要开始查找这个过程到底进行里什么。
在我们到第一步HttpWatch抓包结果里搜索。 搜索的要求就是 function  这是定义一个函数的意思。表示这个就是此函数的具体过程。
function onFormSubmit(form)
{
        if (form.remember_uin.checked){    ‘这里判断我们提交到表单内 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);   ’所以这个函数其实是执行到这里。 调用了  ptui_onLogin过程
        }
}
这里找到里  onFormSubmit
<input type="hidden" name="remember_uin" value="1" id="remember_uin" /> ‘一个隐藏的控件 选中状态默认为 假  hidden 表示是隐藏到控件。我们在网页上看不见。其实是可见的。通常会用这种来传递一些不需要用户操作的数据。


第四步
在我们到第一步HttpWatch抓包结果里搜索。ptui_onLogin   在这个文件里 https://ui.ptlogin2.qq.com/js/10047/comm.js 经过分析后 以后的所有操作都在这个文件内。
找到里  好大一堆。我们用代码整理软件来整理下。 这里使用谷歌浏览器到WEB前端助手 太乱了。现在是不是好看多了 我们再来搜索  
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)
}
这里简单说下 JS的 try  catch 
 try…catch这种结构最常见,它的执行过程是:当没有例外发生执行完毕try块语句后或者发生例外执行完catch块语句后,控制将转移到整个try…catch结构后面的语句。
所以上面那个函数 最终的执行是   return ptui_checkValidate(A) 返回 ptui_checkValidate 过程的结果。

第五步:
在我们到第一步HttpWatch抓包结果里搜索。ptui_checkValidate
依然是这个文件https://ui.ptlogin2.qq.com/js/10047/comm.js  
这里我稍稍具体的分析了这个函数过程

function ptui_checkValidate(B) {
    var A = B.u;  ‘把QQ号输入框对象赋值给A 
    var D = B.p;        把QQ密码框对象赋值给D
    var E = B.verifycode; 把验证码框到值赋值给E
    if (A.value == "" || str_uintip == A.value) {   判断 如果QQ输入框到内容为空 或者 同 str_uintip一样   则输出错误消息 QQ号码输入框获取焦点 返回失败
        pt.show_err(str_no_uin);  在第一步抓包到内容里搜索 str_uintip可以知道内容  var str_uintip = "QQ号码/手机/邮箱";
        A.focus();
        return false
    }
    A.value = A.value.trim(); 如果输入框不为空。则把框里到内容首位空格去掉赋值给 输入框
    if (!pt.chkUin(A.value)) {         这里又调用里一个函数判断是否是QQ号码。 如果失败 同样提示输入QQ号,进行输入判断
        pt.show_err(str_inv_uin);
        A.focus();
        A.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);  显示错误  同样可以搜索 var str_no_vcode = "您还没有输入验证码!";
        try {
            E.focus() 
        } catch (C) {}   又是一个 try catch语言   跳到下一句
        if (!g_loadcheck) {
            ptui_reportAttr(78028)
        } else {
            ptui_reportAttr(78029)
        }
        return false
    }   这个过程主要是判断验证码
    if (E.value.length < 4) {  如果验证码长度小于4  表示验证码错误
        pt.show_err(str_inv_vcode);
        E.focus();
        E.select();
        return false
    }
    if (isLoadVC && !(/^[a-zA-Z0-9]+$/.test(E.value))) {  这里判断 需要载入验证码 且 验证码内容不为 字母和数字组合
        pt.show_err(str_correct_vcode);
        E.focus();
        E.select();
        return false   显示错误信息 并且返回等待重新输入
    }
    D.setAttribute("maxlength", "32");   设置密码输入框的  最大输入长度属性为 32  也就是说 密码框可以输入32个字符
    ajax_Submit();    这里调用里一个过程  submit  感觉是提交。我们看看这个过程是不是我们需要的。
    ptui_reportNum(g_changeNum);
    g_changeNum = 0;
    return true
}

第六步
在我们到第一步HttpWatch抓包结果里搜索。ajax_Submit
依然是comm.js
function ajax_Submit() {
    var A = getSubmitUrl("login");   又调用里一个过程getSubmitUrl  字面意思是 得到(get)提交(submit)链接(url)  我们找出来看看
    pt.winName.set("login_param", encodeURIComponent(login_param));
    pt.loadScript(A);
    return
}

第七步
在我们到第一步HttpWatch抓包结果里搜索。getSubmitUrl  
依然是这个文件 comm.js
这个就不仔细讲解里 其实就是 我们登陆那个 GET链接各个参数的赋值过程。
function getSubmitUrl(K) {
    var E = true;
    var C = document.forms[0];  取表单对象 这里其实就是我们登陆那个表单了。
    var A = (pt.isHttps ? "https://ssl." : "http://") + "ptlogin2." + g_domain + "/" + K + "?";  开始构建提交链接 A
    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) {  这里是赋值一个u=qq号 这个不需要知道 反正构成提交路径我们是直接赋值
            A += pt.needAt + "&";
            continue
        }
        if (C[J].name == "p") {   这里其实就是关键的密码加密处理过程了。  前面我们已经知道 p就是密码输入框的名字。  这里判断 如果控件名字=p 就是 如果目前处理的是密码输入框内容。
            var M = C.p.value;   把密码框内容赋值给 M
            var I = hexchar2bin(md5(M));     MD5 加密密码  在进行 hexchar2bin编码 赋值给 I
            var H = md5(I + pt.uin);  把I的值同 UIN的值链接(这里两个都是文本。文本链接就是 “aa”+"bb"=“aabb” 这样没问题把) 把结果再次MD5 赋值给H  
            var G = md5(H + C.verifycode.value.toUpperCase());    把H 同 验证码的大写形式进行连接 。 结果再MD5加密。 得到G
            A += G   好吧 我们的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
}


第七步

1.上一句又几个地方   pt.uin 这个值是怎么来到呢?  我们通过搜索得到
function checkTimeout() {
    var A = $("u").value.trim();  ‘u QQ号码输入框    这里就是把 QQ号码输入框内容删除首尾空格后 赋值给A
    if (pt.chkAccount.isQQ(A)) {  判断这个QQ号是否正确 如果正确
        pt.uin = uin2hex(A);  把我们的QQ号码进行  uin2hex 编码后 赋值给pt.uin
        $("verifycode").value = "";
        loadVC(true)
    }
    ptui_reportAttr2(216082)
}
pt.uin = uin2hex(A);  
function uin2hex(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
}
一个独立的过程。我们直接用脚本组件运行一下就能得到值


2 密码加密用里很多 MD5   这个好像就是加密关键。我们去提取

调用里  hex_md5,binl2hex,core_md5,str2binl,chrsz......... 我们抽丝剥茧。一个一个到把需要到复制出来 。
这里我们就需要构建一下加密脚本。 增加一个 qqhash函数 传递3个文本参数 依次是 QQ号 密码  验证码 然后返回加密后的密码代码。
至此 完成。 把以下代码加入e语言常量。 然后通过精易模块到 脚本组件模块进行调用。

QQ加密过程查询分析完成
function qqhash(qqnum,password,verifycode){

            var I = hexchar2bin(md5(password));
            var H = md5(I + uin2hex(qqnum)); 
            var G = md5(H + verifycode.toUpperCase());    
           return G
}

var hexcase = 1;
var b64pad = "";
var chrsz = 8;
var mode = 32;

function md5(A) {
    return hex_md5(A)
}
function hex_md5(A) {
    return binl2hex(core_md5(str2binl(A), A.length * chrsz))
}

function str_md5(A) {
    return binl2str(core_md5(str2binl(A), A.length * chrsz))
}
function hex_hmac_md5(A, B) {
    return binl2hex(core_hmac_md5(A, B))
}
function b64_hmac_md5(A, B) {
    return binl2b64(core_hmac_md5(A, B))
}
function str_hmac_md5(A, B) {
    return binl2str(core_hmac_md5(A, B))
}
function core_md5(K, F) {
    K[F >> 5] |= 128 << ((F) % 32);
    K[(((F + 64) >>> 9) << 4) + 14] = F;
    var J = 1732584193;
    var I = -271733879;
    var H = -1732584194;
    var G = 271733878;
    for (var C = 0; C < K.length; C += 16) {
        var E = J;
        var D = I;
        var B = H;
        var A = G;
        J = md5_ff(J, I, H, G, K[C + 0], 7, -680876936);
        G = md5_ff(G, J, I, H, K[C + 1], 12, -389564586);
        H = md5_ff(H, G, J, I, K[C + 2], 17, 606105819);
        I = md5_ff(I, H, G, J, K[C + 3], 22, -1044525330);
        J = md5_ff(J, I, H, G, K[C + 4], 7, -176418897);
        G = md5_ff(G, J, I, H, K[C + 5], 12, 1200080426);
        H = md5_ff(H, G, J, I, K[C + 6], 17, -1473231341);
        I = md5_ff(I, H, G, J, K[C + 7], 22, -45705983);
        J = md5_ff(J, I, H, G, K[C + 8], 7, 1770035416);
        G = md5_ff(G, J, I, H, K[C + 9], 12, -1958414417);
        H = md5_ff(H, G, J, I, K[C + 10], 17, -42063);
        I = md5_ff(I, H, G, J, K[C + 11], 22, -1990404162);
        J = md5_ff(J, I, H, G, K[C + 12], 7, 1804603682);
        G = md5_ff(G, J, I, H, K[C + 13], 12, -40341101);
        H = md5_ff(H, G, J, I, K[C + 14], 17, -1502002290);
        I = md5_ff(I, H, G, J, K[C + 15], 22, 1236535329);
        J = md5_gg(J, I, H, G, K[C + 1], 5, -165796510);
        G = md5_gg(G, J, I, H, K[C + 6], 9, -1069501632);
        H = md5_gg(H, G, J, I, K[C + 11], 14, 643717713);
        I = md5_gg(I, H, G, J, K[C + 0], 20, -373897302);
        J = md5_gg(J, I, H, G, K[C + 5], 5, -701558691);
        G = md5_gg(G, J, I, H, K[C + 10], 9, 38016083);
        H = md5_gg(H, G, J, I, K[C + 15], 14, -660478335);
        I = md5_gg(I, H, G, J, K[C + 4], 20, -405537848);
        J = md5_gg(J, I, H, G, K[C + 9], 5, 568446438);
        G = md5_gg(G, J, I, H, K[C + 14], 9, -1019803690);
        H = md5_gg(H, G, J, I, K[C + 3], 14, -187363961);
        I = md5_gg(I, H, G, J, K[C + 8], 20, 1163531501);
        J = md5_gg(J, I, H, G, K[C + 13], 5, -1444681467);
        G = md5_gg(G, J, I, H, K[C + 2], 9, -51403784);
        H = md5_gg(H, G, J, I, K[C + 7], 14, 1735328473);
        I = md5_gg(I, H, G, J, K[C + 12], 20, -1926607734);
        J = md5_hh(J, I, H, G, K[C + 5], 4, -378558);
        G = md5_hh(G, J, I, H, K[C + 8], 11, -2022574463);
        H = md5_hh(H, G, J, I, K[C + 11], 16, 1839030562);
        I = md5_hh(I, H, G, J, K[C + 14], 23, -35309556);
        J = md5_hh(J, I, H, G, K[C + 1], 4, -1530992060);
        G = md5_hh(G, J, I, H, K[C + 4], 11, 1272893353);
        H = md5_hh(H, G, J, I, K[C + 7], 16, -155497632);
        I = md5_hh(I, H, G, J, K[C + 10], 23, -1094730640);
        J = md5_hh(J, I, H, G, K[C + 13], 4, 681279174);
        G = md5_hh(G, J, I, H, K[C + 0], 11, -358537222);
        H = md5_hh(H, G, J, I, K[C + 3], 16, -722521979);
        I = md5_hh(I, H, G, J, K[C + 6], 23, 76029189);
        J = md5_hh(J, I, H, G, K[C + 9], 4, -640364487);
        G = md5_hh(G, J, I, H, K[C + 12], 11, -421815835);
        H = md5_hh(H, G, J, I, K[C + 15], 16, 530742520);
        I = md5_hh(I, H, G, J, K[C + 2], 23, -995338651);
        J = md5_ii(J, I, H, G, K[C + 0], 6, -198630844);
        G = md5_ii(G, J, I, H, K[C + 7], 10, 1126891415);
        H = md5_ii(H, G, J, I, K[C + 14], 15, -1416354905);
        I = md5_ii(I, H, G, J, K[C + 5], 21, -57434055);
        J = md5_ii(J, I, H, G, K[C + 12], 6, 1700485571);
        G = md5_ii(G, J, I, H, K[C + 3], 10, -1894986606);
        H = md5_ii(H, G, J, I, K[C + 10], 15, -1051523);
        I = md5_ii(I, H, G, J, K[C + 1], 21, -2054922799);
        J = md5_ii(J, I, H, G, K[C + 8], 6, 1873313359);
        G = md5_ii(G, J, I, H, K[C + 15], 10, -30611744);
        H = md5_ii(H, G, J, I, K[C + 6], 15, -1560198380);
        I = md5_ii(I, H, G, J, K[C + 13], 21, 1309151649);
        J = md5_ii(J, I, H, G, K[C + 4], 6, -145523070);
        G = md5_ii(G, J, I, H, K[C + 11], 10, -1120210379);
        H = md5_ii(H, G, J, I, K[C + 2], 15, 718787259);
        I = md5_ii(I, H, G, J, K[C + 9], 21, -343485551);
        J = safe_add(J, E);
        I = safe_add(I, D);
        H = safe_add(H, B);
        G = safe_add(G, A)
    }
    if (mode == 16) {
        return Array(I, H)
    } else {
        return Array(J, I, H, G)
    }
}
function md5_cmn(F, C, B, A, E, D) {
    return safe_add(bit_rol(safe_add(safe_add(C, F), safe_add(A, D)), E), B)
}
function md5_ff(C, B, G, F, A, E, D) {
    return md5_cmn((B & G) | ((~B) & F), C, B, A, E, D)
}
function md5_gg(C, B, G, F, A, E, D) {
    return md5_cmn((B & F) | (G & (~F)), C, B, A, E, D)
}
function md5_hh(C, B, G, F, A, E, D) {
    return md5_cmn(B ^ G ^ F, C, B, A, E, D)
}
function md5_ii(C, B, G, F, A, E, D) {
    return md5_cmn(G ^ (B | (~F)), C, B, A, E, D)
}
function core_hmac_md5(C, F) {
    var E = str2binl(C);
    if (E.length > 16) {
        E = core_md5(E, C.length * chrsz)
    }
    var A = Array(16),
        D = Array(16);
    for (var B = 0; B < 16; B++) {
        A[B] = E[B] ^ 909522486;
        D[B] = E[B] ^ 1549556828
    }
    var G = core_md5(A.concat(str2binl(F)), 512 + F.length * chrsz);
    return core_md5(D.concat(G), 512 + 128)
}
function safe_add(A, D) {
    var C = (A & 65535) + (D & 65535);
    var B = (A >> 16) + (D >> 16) + (C >> 16);
    return (B << 16) | (C & 65535)
}
function bit_rol(A, B) {
    return (A << B) | (A >>> (32 - B))
}
function str2binl(D) {
    var C = Array();
    var A = (1 << chrsz) - 1;
    for (var B = 0; B < D.length * chrsz; B += chrsz) {
        C[B >> 5] |= (D.charCodeAt(B / chrsz) & A) << (B % 32)
    }
    return C
}
function binl2str(C) {
    var D = "";
    var A = (1 << chrsz) - 1;
    for (var B = 0; B < C.length * 32; B += chrsz) {
        D += String.fromCharCode((C[B >> 5] >>> (B % 32)) & A)
    }
    return D
}
function binl2hex(C) {
    var B = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
    var D = "";
    for (var A = 0; A < C.length * 4; A++) {
        D += B.charAt((C[A >> 2] >> ((A % 4) * 8 + 4)) & 15) + B.charAt((C[A >> 2] >> ((A % 4) * 8)) & 15)
    }
    return D
}
function binl2b64(D) {
    var C = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    var F = "";
    for (var B = 0; B < D.length * 4; B += 3) {
        var E = (((D[B >> 2] >> 8 * (B % 4)) & 255) << 16) | (((D[B + 1 >> 2] >> 8 * ((B + 1) % 4)) & 255) << 8) | ((D[
            B + 2 >> 2] >> 8 * ((B + 2) % 4)) & 255);
        for (var A = 0; A < 4; A++) {
            if (B * 8 + A * 6 > D.length * 32) {
                F += b64pad
            } else {
                F += C.charAt((E >> 6 * (3 - A)) & 63)
            }
        }
    }
    return F
}
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 uin2hex(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
}

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。