首先列举比较重要的问题在前面。
1.关于QQ密码码的加密:
2.关于登陆是否需要验证码的校验。
3. 发日志的时候g_tk参数的算法。
分析过程。
1.登陆的时候,需要先判断是否需要使用验证码。
string url = String.Format(“http://ptlogin2.qq.com/check?uin={0}&appid={1}&r=0.{2}”, TxtUser.Text.Trim(), “2001601”, Bases.GetGuid(Bases.RandEnum.Numeric, 16));
进行Get请示,如果返回值 是1开头结果的需要验证码,如果是0开头的,是不需要验证码的。
2.有验证码的情况 ,获得验证码图片地址,同时要记录验证码的cookie,在提交的时候需要用到。
string strImageUrl = String.Format(“http://captcha.qq.com/getimage?&uin={0}&vc_type={1}&aid={2}&0.{3}”,TxtUser.Text.Trim(),vcCode, “2001601”, Bases.GetGuid(Bases.RandEnum.Numeric, 16));
3.进行登陆,
注:u:你的QQ号, p:加密过的QQ密码,verifycode:验证码
3.1 :QQ密码的加密代码:C#版的。
public static class qqPwdEncrypt { /// /// 计算网页上QQ登录时密码加密后的结果 /// ///QQ密码 ///验证码 /// public static String Encrypt(string pwd, string verifyCode) { return (md5(md5_3(pwd).ToUpper() + verifyCode.ToUpper())).ToUpper(); } /// /// 计算字符串的三次MD5 /// ////// private static String md5_3(String s) { System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); byte[] bytes = System.Text.Encoding.UTF8.GetBytes(s); bytes = md5.ComputeHash(bytes); bytes = md5.ComputeHash(bytes); bytes = md5.ComputeHash(bytes); md5.Clear(); string ret = ""; for (int i = 0; i < bytes.Length; i++) { ret += Convert.ToString(bytes[i], 16).PadLeft(2, '0'); } return ret.PadLeft(32, '0'); } /// /// 计算字符串的一次MD5 /// ////// private static String md5(String s) { System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); byte[] bytes = System.Text.Encoding.UTF8.GetBytes(s); bytes = md5.ComputeHash(bytes); md5.Clear(); string ret = ""; for (int i = 0; i < bytes.Length; i++) { ret += Convert.ToString(bytes[i], 16).PadLeft(2, '0'); } return ret.PadLeft(32, '0'); } }
3.2 关于js版的加密方法,请直接查看源代码,从QQ的页面上读取。
4.登陆成功后,开始发日志,
发日志地址:http://b.qzone.qq.com/cgi-bin/blognew/blog_add?g_tk=” + gtkValue
1:g_tk的参数如何取:
gtkValue的值是也是经过QQ加密过的
加密原理:对于登陆成功后,会在登陆成功的cookie值中有一个skey的cookie,取该cookie的值,进行循环取单字符的二进制并取左值。
找了一个获得gtkValue的js方法:【期待谁可以翻译成C#版的,因为js的方法,在c#的调用不太方便,还要引用一个dll的控件才可以。】
js方法提供如下:
function getGTK(str){ var hash = 5381; for(var i = 0, len = str.length; i < len; ++i) { hash += (hash << 5) + str.charAt(i).charCodeAt(); } return hash & 0x7fffffff; }
通过调用些方法后,就可以获得发日志的具体地址了、
5.进行post提供要发的日志内容【注:登陆的时候,是get请求,非post请求】
前面都很顺利,到这里把我卡住了,不知道为什么提交后,没有数据返回,相对应也就是没有发布成功,也怪调试不细心。
后来发现提交的时候,会catch到 “关于“服务器提交了协议冲突. Section=ResponseStatusLine”
经常查询问题根源:【网上找的,嘿嘿】
The server committed a protocol violation. Section=ResponseHeader Detail=CR must be followed by LF 微软没有容忍不符合RFC 822中的httpHeader必须以CRLF结束的规定的服务器响应。
通过修改配置文件解决:在app.config(WinForm)或web.config(Web)文件里修改。
WinForm下的app.config默认不存在,手动在Debug文件夹所在的同级目录下新建一个XML配置文件,内容为:
<!--?xml version="1.0" encoding="utf-8" ?-->
编译以后会在Debug下面自动创建一个 程序名.exe.config 的配置文件
加入以上代码就OK了。
本文以记录分析过程,并留以后查看备忘 ,如果对大家无用,请飘了。哈
关于程序文章,或收藏一般同步发到javaeye,cnblogs,
关于其它文章,一般同步发到sina,QQ空间。
发成功了。哈哈。