开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 20272|回复: 42
收起左侧

[技术专题] webqq 加密JS分析过程。QQMD5加密不求人

[复制链接]

结帖率:0% (0/1)
发表于 2013-10-8 10:46:25 | 显示全部楼层 |阅读模式   四川省南充市
分享视频教程
教程类型: 无声教程
教程讲师: --
下载地址1: http://pan.baidu.com/s/17m4sS
本帖最后由 宇智波·佐助 于 2013-10-16 22:36 编辑
今天来说说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
}

评分

参与人数 1精币 +2 收起 理由
爱家的小懒虫 + 2 精彩文章希望继续努力

查看全部评分


结帖率:35% (7/20)

签到天数: 7 天

发表于 2022-5-4 11:49:42 | 显示全部楼层   贵州省黔东南苗族侗族自治州
下载已失效??
回复 支持 反对

使用道具 举报

结帖率:86% (12/14)
发表于 2017-6-12 00:07:25 | 显示全部楼层   河南省安阳市
楼主应该是个心细的人,教程一定不错
回复 支持 反对

使用道具 举报

发表于 2016-8-26 14:33:09 | 显示全部楼层   广东省东莞市
受教了。谢谢
回复 支持 反对

使用道具 举报

发表于 2016-2-11 08:07:44 | 显示全部楼层   山东省青岛市
太牛了,很佩服楼主
回复 支持 反对

使用道具 举报

结帖率:100% (1/1)

签到天数: 2 天

发表于 2015-1-30 13:35:04 | 显示全部楼层   上海市上海市
回复 支持 反对

使用道具 举报

结帖率:92% (85/92)

签到天数: 3 天

发表于 2015-1-19 19:28:59 | 显示全部楼层   浙江省宁波市
  第一次看不懂, 回头一看, 超不错的文章
回复 支持 反对

使用道具 举报

发表于 2015-1-10 11:52:07 | 显示全部楼层   河南省洛阳市
收益了,好教程
回复 支持 反对

使用道具 举报

结帖率:38% (5/13)
发表于 2014-12-29 00:38:44 | 显示全部楼层   湖南省永州市
刚好需要这方面的思路,按这思路做下先
回复 支持 反对

使用道具 举报

结帖率:92% (85/92)

签到天数: 3 天

发表于 2014-12-26 17:32:29 | 显示全部楼层   浙江省宁波市
支持一下!!!
回复 支持 反对

使用道具 举报

结帖率:0% (0/2)
发表于 2014-11-12 15:25:34 | 显示全部楼层   江苏省常州市
虽然看不懂还是很感谢你的无私分享
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 793400750,邮箱:wp@125.la
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表