前言
本文的重要部分:
1、抓包获取QQ空间或者邮箱登陆地址,分析参数,用户名,密码,验证码,gtk,随即数。
2、获取每次登陆需要的验证码
3、用户名,密码,验证码加密得到登陆密码
4、Http模拟登陆拿cookie
本文实验的思路也可换另一种方式,抓包获取登陆的js,用代码操作js来计算密码 ,gtk等实现登陆。
抓包
1、我们来访问qq空间的地址http://i.qq.com/,打开网站,我们可以看到登陆的对话框,首先我们输入一个错误的账号和密码,抓起提交的地址。
2、输入用户名和密码之后我们用抓包工具看到有2个后台请求的地址,如下图
我们可以根据返回的代码可以看出第二个图的地址是QQ登陆后台get请求的地址,所以我们实现登陆就是像这个地址提交数据。第一张图则是空间登陆每次返回的验证码产生的地址,通过多次输入正确用户名密码,第一张图地址返回类似ptui_checkVC('0','!JWE','\x00\x00\x00\x00\x46\x86\xd2\x36');代码,其中括号内参数与登陆请求地址中verifycode=!JWE每次相同,这个便是登陆的验证码,登陆地址则返回类似ptuiCB('0','0','http://qzs.qq.com/qzone/v5/loginsucc.html?para=izone','0','登录成功!', 'xxx');返回此代码则说明登陆成功。
通过抓包我们提取出来的2个地址:
1、验证码获取地址(输入用户名时返回):
http://check.ptlogin2.qq.com/check?regmaster=&uin={0}&appid=549000912&js_ver=10038&js_type=1&login_sig=46Flu6g0o2A1hcewVAPUpItgSNJncoqujR4vudgX8ZRnruuCSOzMGcbd3CnQhw0y&u1=http%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&r={1}
参数0:QQ账号,参数1:随即数
说明:一般情况下是不会产生手动输入验证码的情况下,若是QQ号码不存在或者错误,此时会出现图片验证码,我们可以用一个处理一下显示在imge中手动输入。
2、登陆提交地址:
http://ptlogin2.qq.com/login?u={0}&p={1}&verifycode={2}&aid=549000912&u1=http%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&h=1&ptredirect=0&ptlang=2052&from_ui=1&dumy=&low_login_enable=0®master=&fp=loginerroralert&action=11-52-1375668422981&mibao_css=&t=1&g=1&js_ver=10038&js_type=1&login_sig=46Flu6g0o2A1hcewVAPUpItgSNJncoqujR4vudgX8ZRnruuCSOzMGcbd3CnQhw0y
参数0:QQ号码,参数1:加密以后的密码,参数2:返回的验证码
本人文字功底实在太差,说不太清楚,抓包需要我多次试验,多次分析,才可取得正确的地址。登陆的最重要目的是获取请求页面的cookie。
代码部分
1、http请求帮助代码
1 public class HttpHelper 2 { 3 /// <summary> 4 /// 获取字符流 5 /// </summary> 6 /// <param name="url"></param> 7 /// <param name="cookieContainer"></param> 8 /// <returns></returns> 9 public static Stream GetStream(string url, CookieContainer cookieContainer) 10 { 11 HttpWebRequest httpWebRequest = null; 12 HttpWebResponse httpWebResponse = null; 13 14 try 15 { 16 httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); 17 httpWebRequest.CookieContainer = cookieContainer; 18 httpWebRequest.ContentType = contentType; 19 httpWebRequest.Referer = referer; 20 httpWebRequest.Accept = accept; 21 httpWebRequest.UserAgent = userAgent; 22 httpWebRequest.Method = "GET"; 23 httpWebRequest.ServicePoint.ConnectionLimit = int.MaxValue; 24 25 httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); 26 Stream responseStream = httpWebResponse.GetResponseStream(); 27 28 return responseStream; 29 } 30 catch (Exception) 31 { 32 return null; 33 } 34 35 } 36 37 /// <summary> 38 /// 获取HTML 39 /// </summary> 40 /// <param name="url"></param> 41 /// <param name="cookieContainer"></param> 42 /// <returns></returns> 43 public static string GetHtml(string url, CookieContainer cookieContainer) 44 { 45 Thread.Sleep(1000); 46 HttpWebRequest httpWebRequest = null; 47 HttpWebResponse httpWebResponse = null; 48 try 49 { 50 httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); 51 httpWebRequest.CookieContainer = cookieContainer; 52 httpWebRequest.ContentType = contentType; 53 httpWebRequest.Referer = referer; 54 httpWebRequest.Accept = accept; 55 httpWebRequest.UserAgent = userAgent; 56 httpWebRequest.Method = "GET"; 57 httpWebRequest.ServicePoint.ConnectionLimit = int.MaxValue; 58 59 httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); 60 Stream responseStream = httpWebResponse.GetResponseStream(); 61 StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8); 62 string html = streamReader.ReadToEnd(); 63 64 streamReader.Close(); 65 responseStream.Close(); 66 67 httpWebRequest.Abort(); 68 httpWebResponse.Close(); 69 70 return html; 71 } 72 catch (Exception) 73 { 74 return string.Empty; 75 } 76 77 } 78 }
2、获取验证码
//取验证码 public static string GetVerfiyCode(string qqnum,CookieContainer cookie) { Random rand = new Random(); double r = rand.NextDouble(); string checkcodeurl = string.Format(@"http://check.ptlogin2.qq.com/check?uin={0}&appid=1006102&r={1}", qqnum, r); Stream stream = HttpHelper.GetStream(checkcodeurl, cookie); StreamReader streamReader = new StreamReader(stream, Encoding.UTF8); return streamReader.ReadToEnd(); } //取图片验证码,可将验证码直接输出在image中 public static Stream GetVerfycodeImage(CookieContainer cookie, string qqnum) { Random rand = new Random(); double r = rand.NextDouble(); string codeimageurl = string.Format("http://captcha.qq.com/getimage?aid=1006102&r={0}&uin={1}", r, qqnum); return HttpHelper.GetStream(codeimageurl, cookie); }
通过GetVerfiyCode()的返回 值判断,是否需要手动输入验证码
//得验证吗 if (retString.Contains("ptui_checkVC('0','")) {
//不需要手动输入 this.txtverfiycode.Text = retString.Replace("ptui_checkVC('0','", "").Replace("'", "").Replace(")", "").Replace(";", "").Substring(0, 4); } else if (retString.Contains("ptui_checkVC('1',")) {
//需要手动输入,将验证码输出在image中 this.vefycodpicbox.Image = Image.FromStream(GetVerfycodeImage(retString, this.txtUseraccount.Text)); }
3、计算密码,密码的计算方法可以通过js计算,或者直接使用如下c#版的,总的来说腾讯的密码加密比较麻烦,需要QQ号码,密码,验证码三个参数,有兴趣的可自己研究下。
代码如下:
1 public static class PasswordHelper 2 { 3 /// <summary> 4 /// 根据QQ号码和验证码加密密码 5 /// </summary> 6 /// <param name="qqNum">QQ号码</param> 7 /// <param name="password">QQ密码</param> 8 /// <param name="verifycode">验证码</param> 9 /// <returns>密码密文</returns> 10 public static string GetPassword(string qqNum, string password, string verifycode) 11 { 12 //uin为QQ号码转换为16位的16进制 13 int qq; 14 int.TryParse(qqNum, out qq); 15 16 qqNum = qq.ToString("x"); 17 qqNum = qqNum.PadLeft(16, '0'); 18 19 String P = hexchar2bin(md5(password)); 20 String U = md5(P + hexchar2bin(qqNum)).ToUpper(); 21 String V = md5(U + verifycode.ToUpper()).ToUpper(); 22 return V; 23 } 24 25 public static string md5(string input) 26 { 27 byte[] buffer = MD5.Create().ComputeHash(Encoding.GetEncoding("ISO-8859-1").GetBytes(input)); 28 return binl2hex(buffer); 29 } 30 31 public static string binl2hex(byte[] buffer) 32 { 33 StringBuilder builder = new StringBuilder(); 34 for (int i = 0; i < buffer.Length; i++) 35 { 36 builder.Append(buffer[i].ToString("x2")); 37 } 38 return builder.ToString(); 39 } 40 41 public static string hexchar2bin(string passWord) 42 { 43 StringBuilder builder = new StringBuilder(); 44 for (int i = 0; i < passWord.Length; i = i + 2) 45 { 46 builder.Append(Convert.ToChar(Convert.ToInt32(passWord.Substring(i, 2), 16))); 47 } 48 return builder.ToString(); 49 } 50 }
到此为止,登陆需要的参数已经全了,下面就是实现登陆拿cookie。
4、登陆的方法与获取验证码一样
//登录方法 public static bool IsLogin(string qqnum,string code,string passwords,CookieContainer cookie) { string password = PasswordHelper.GetPassword(qqnum, passwords, code); string loginUrlstring = @"http://ptlogin2.qq.com/login?u=" + qqnum + "&p=" + password + "&verifycode=" + code + "&aid=1006102&u1=http%3A%2F%2Fid.qq.com%2Findex.html&h=1&ptredirect=1&ptlang=2052&from_ui=1&dumy=&fp=loginerroralert&action=8-29-82478035&mibao_css=&t=1&g=1"; Stream stream = HttpHelper.GetStream(loginUrlstring, cookie); StreamReader streamReader = new StreamReader(stream, Encoding.UTF8); string retString = streamReader.ReadToEnd();// retString "ptuiCB('0','0','http://id.qq.com/index.html','1','登录成功!', 'xxx');\r\n" string return retString.Contains("ptuiCB('0',") ? true : false; }
我们可以直接调用此方法验证是否登陆成功,同时将cookie保存在一个全局变量中供以后使用。
到此为止,QQ用http模拟登陆已经成功,完成了获取群列表的第一步。下面一篇就到获取群列表,群成员。
临时写的代码,时间仓促,比较杂乱,有什么出错的地方欢迎指出。若资料有用,帮忙顶一下。