编程日志:webQQ的登录【已更新】

1。首先获取验证码VeriCode
抓包:
GET  http://check.ptlogin2.qq.com/check?uin=【QQNo】&appid=1003903  HTTP/1.1
(添加粗体字符,以适应2012.5.25后腾讯的变更)
说明:这个地址是用来判断您的用户名是否是正常状态,以及是否有效用户名,正常时,请求这个地址,会获得类似ptui_checkVC(‘0′,’!TDU’,’\x00\x00\x00\x00\x1d\x44\xac\x91′);
这样的返回值,这其中0是代表正常状态,不采用图片验证。
而后面的!TDU是四位,则是我们需要获得的验证码,它是由腾讯服务器随机生成的一个令牌的原始密钥。当我们正确的获得这样的四位码时,就已经完成了第一次的验证!
其后,有一点需要注意的是:腾讯的令牌是存储在cookies中的,所以请注意每次操作都必须要保存好服务器返回来的cookies。
如果返回值,类似这样:ptui_checkVC(‘1’,’ae2ae85f6ce5b416257182bf3f0bf3554e5a60ca0bdca4c1’…);
那么就要恭喜您了,那表明需要进行图片验证码验证。您获得也是令牌的原始密钥,只不过不同的是,您获得是图片验证码的原始密钥而已。
此外,0和1以外,还有可能有其他的返回数值,用来标明诸如帐号不存在,帐号状态不正确,帐号已锁定等等的。
经验:这一步的关键,就是如何避免非0的返回值?
有人说,如果短时间内这个帐号多次在不同的ip登录,那么返回值就有可能是非0值–其实不然。我在IE上,换了不同的IP,照样可得到0值,不需要图片验证。与此同时,新装的浏览器safari上,敲了n遍,还是得到1,需要图片验证。等我用safari登陆一次web.qq.com后,其后得到的返回值就是0了…这说明什么?
说明QQ服务器没有存放你的IP地址,但是在你的机器里存放cookies(而不同的浏览器或客户端,其cookies不同),然后根据cookies来判断你是否初来咋到的…
正因为是这样,对于你常用的QQ号码,成功登陆后,要把cookies存起来,以后你每次请求,都能得到0的返回值,不需要图片验证。

 

C++ (with libcurl)源程序
【抓包GET】http://check.ptlogin2.qq.com/check?uin=XXXXXXXX&appid=1003903 HTTP/1.1

Referer: http://ui.ptlogin2.qq.com/cgi-bin/login?target=self&style=5&mibao_css=m_webqq&appid=1003903&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fweb.qq.com%2Floginproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20120619001
【源代码】
string WebQQ_check(string QQno)
{
string buffer;
string get_url = “http://check.ptlogin2.qq.com/check?uin=” + QQno + “&appid=1003903”;
string Ref_url = “http://ui.ptlogin2.qq.com/cgi-bin/login?target=self&style=5&mibao_css=m_webqq&appid=1003903″;
Ref_url   = Ref_url+”&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fweb.qq.com%2Floginproxy.html&f_url=loginerroralert&strong_login=1&login_state=10”;//
// 初始化libcurl
CURLcode return_code;
return_code = curl_global_init(CURL_GLOBAL_WIN32);
if (CURLE_OK != return_code) return “”;
// 获取easy handle
CURL *easy_handle = curl_easy_init();
if (NULL == easy_handle)
{
curl_global_cleanup();
return “”;
}
// 设置easy handle属性
curl_easy_setopt(easy_handle, CURLOPT_URL, get_url.c_str());
curl_easy_setopt(easy_handle, CURLOPT_REFERER, Ref_url.c_str());
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, &buffer);
//提交第一步保存的cookie
curl_easy_setopt(easy_handle, CURLOPT_COOKIEFILE,”D:\\SparkHo\\cookie_login.txt”);
//把服务器发过来的cookie保存到cookie_open.txt
curl_easy_setopt(easy_handle, CURLOPT_COOKIEJAR, “D:\\SparkHo\\cookie_open.txt”);
// 执行数据请求
curl_easy_perform(easy_handle);
// 释放资源
curl_easy_cleanup(easy_handle);
curl_global_cleanup();

//返还QQ验证数据
return buffer;
}

返回的格式:

ptui_checkVC(‘0′,’!TDU’,’\x00\x00\x00\x00\x1d\x44\xac\x91′);

 

这包括了一组“四位验证码”,还有一组8位的UIN数字(其实就是你的QQ号转化为16进制数字)。

何用之有?用于腾讯密码的变态加密…
因为其后的登陆中,会要求你输入一个由32个字符组成的字符串,其实就是你的UIN数字,加上密码和验证码,按照某种算法得到的md5码。
腾讯已经更新了算法,具体的算法请参考源代码。

 

C++ (with OpenSSL)源程序
#include <openssl/md5.h>

string newQQMD5(string pass,string VeriCode,string UIN)
{
unsigned char md[16],hexuin[8],plus[24],md2[16],md3[16];
int i;
char tmp[3]={‘\0’};
char buf[33]={‘\0’};
char buf2[33]={‘\0’};

MD5((unsigned char *)pass.c_str(),pass.length(),md);
Hexchar2bin(UIN,hexuin);
for (i = 0; i < 16; i++)
plus[i]=md[i];
for (i = 0; i < 8; i++)
plus[16+i]=hexuin[i];

MD5(plus,24,md2);
for (i = 0; i < 16; i++)
{
sprintf(tmp,”%2.2X”,md2[i]);
strcat(buf,tmp);
}

string bufAdd = (string)buf+VeriCode;
MD5((unsigned char *)bufAdd.c_str(),bufAdd.length(),md3);
for (i = 0; i < 16; i++)
{
sprintf(tmp,”%2.2X”,md3[i]);
strcat(buf2,tmp);
}
string final=(string)buf2;
return final;
}

附:基于OpenSSL的md5算法,可参考:
http://hi.baidu.com/sparkho/blog/item/88fc9061ec6f90c58cb10dd5.html

 

2。以QQ号、PassCode、VeriCode,登录web.qq.com网页,完成验证。
【抓包GET】
http://ptlogin2.qq.com/login?u=【QQno】&p=【PassCode】&verifycode=【VeriCode】&webqq_type=10&remember_uin=1&login2qq=1&aid=1003903&u1=http%3A%2F%2Fweb.qq.com%2Floginproxy.html%3Flogin2qq%3D1%26webqq_type%3D10&h=1&ptredirect=0&ptlang=2052&from_ui=1&pttype=1&dumy=&fp=loginerroralert&action=2-6-6757&mibao_css=m_webqq&t=1&g=1HTTP/1.1
【Referer】 http://ui.ptlogin2.qq.com/cgi-bin/login?target=self&style=5&mibao_css=m_webqq&appid=1003903&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fweb.qq.com%2Floginproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20120619001

登录成功后,将返回ptuiCB(‘0′,’0′,’http://web.qq.com/loginproxy.html?login2qq=1&webqq_type=10′,’0′,’登录成功!’, ‘雨顺’);
同时将会返回一些cookies值,如其中ptwebqq,skey等,libcurl可设定存放在指定的Cookies文件中。
注:如果我们直接用IE,输入上述网址,登录不会成功,原因是不能提交第一步保存的cookies…
结果将返回:ptuiCB(‘7′,’0′,”,’0′,’很遗憾,网络连接出现异常,请您稍后再试。(1138754159)’);

 

C++ (with libcurl)源程序

string WebQQ_login(string QQno,string PassCode,string VeriCode)
{
string get_url = “http://ptlogin2.qq.com/login?u=” + QQno + “&p=” + PassCode + “&verifycode=” + VeriCode;
get_url   = get_url + “&webqq_type=10&remember_uin=1&login2qq=1&aid=1003903&u1=http%3A%2F%2Fweb.qq.com%2Floginproxy.html”;
get_url   = get_url + “%3Flogin2qq%3D1%26webqq_type%3D10&h=1&ptredirect=0&ptlang=2052&from_ui=1&pttype=1&dumy=&fp=loginerroralert&mibao_css=m_webqq&t=1&g=1”;
string Ref_url = “http://ui.ptlogin2.qq.com/cgi-bin/login?target=self&style=5&mibao_css=m_webqq&appid=1003903&enable_qlogin=0″;
Ref_url   = Ref_url+”&no_verifyimg=1&s_url=http%3A%2F%2Fweb.qq.com%2Floginproxy.html&f_url=loginerroralert&strong_login=1&login_state=10”;//&t=20120619001

string buffer;
// 初始化libcurl
CURLcode return_code;
return_code = curl_global_init(CURL_GLOBAL_WIN32);
if (CURLE_OK != return_code) return “”;
// 获取easy handle
CURL *easy_handle = curl_easy_init();
if (NULL == easy_handle)
{
curl_global_cleanup();
return “”;
}
// 设置easy handle属性
curl_easy_setopt(easy_handle, CURLOPT_URL, get_url.c_str());
curl_easy_setopt(easy_handle, CURLOPT_REFERER, Ref_url.c_str());
//curl_easy_setopt(easy_handle, CURLOPT_HEADER,1);
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, &buffer);
//提交第一步保存的cookie
curl_easy_setopt(easy_handle, CURLOPT_COOKIEFILE,”D:\\SparkHo\\cookie_open.txt”);
//保存登陆后的cookie
curl_easy_setopt(easy_handle, CURLOPT_COOKIEJAR,”D:\\SparkHo\\cookie_login.txt”);

// 执行数据请求
curl_easy_perform(easy_handle);
// 释放资源
curl_easy_cleanup(easy_handle);
curl_global_cleanup();
filestatus=0;

return buffer;
}

登录成功,将返回:

ptuiCB(‘0′,’0′,’http://web.qq.com/loginproxy.html?login2qq=1&webqq_type=10′,’0′,’登录成功!’, ‘雨顺’);

这个时候,如果我们只是要发微博,调用发微博的程序即可。无需进行下面的登录。

3。登录QQ客户端。
上一步的登陆,算是登录webqq.com网页;而这次登陆,才算真正登陆webQQ客户端,成功后会把你原先登陆的QQ踢下线(如果你原先已经登陆QQ)。
抓包:
POSThttp://d.web2.qq.com/channel/login2HTTP/1.1
Referer:http://d.web2.qq.com/proxy.html
POST数据:一个json数据结构:
r={“status”:””,”ptwebqq”:”【ptwebqq】”,”passwd_sig”:””,”clientid”:”【clientid】”}

需要的参数:
1)【ptwebqq】是在第2步成功登陆后,cookie返回的,我们可在libcurl存档的Cookies文件中读取;
2)【clientid】是用户识别码,每次登录前随机产生的,但我们需要保存该用户识别码,因为以后很多的操作需要引用此唯一的用户识别码,直到再次重新登录才会更新。
如果成功,会返回一个json数据结构:
{“retcode”:0,”result”:{“uin”:QQNo,”cip”:3682615122,”index”:1073,”port”:49410,”status”:”online”,”vfwebqq”:”……..”,”psessionid”:”……..”,”user_state”:0,”f”:0}}
如果我们用buffer获取返回的信息,那么我们可以从中提取出的vfwebqqpsessionid,存放于QQLogin.txt。以后的webQQ操作,需要用到这些参数。

C++ (with libcurl)源程序
string WebQQ_login2()
{
size_t found,found2;
char buf[1024];
// 在libcurl存档的Cookies文件中,读取:ptwebqq
string ptwebqq;
ifstream QQCookiesfile(“D:\\SparkHo\\cookie_login.txt”);
if(!QQCookiesfile)
{
QQCookiesfile.close();
ptwebqq = “”;
}
else
{
QQCookiesfile.read(buf,1024);
string QQCookies = (string) buf;
QQCookiesfile.close();
found   = QQCookies.find(“ptwebqq”);
found2  = QQCookies.find(“\n”,found+8,1);
ptwebqq = QQCookies.substr(found+8,found2-found-8);
}
// clientid,在每次登陆时,自行随机产生…
int iClient;
srand ( time(NULL) );    /* initialize random seed: */
iClient = rand() % 100000000;  /* generate secret number: */
sprintf(buf, “%d”, iClient);
string clientid = (string)buf;
// 初始化libcurl
CURLcode return_code;
return_code = curl_global_init(CURL_GLOBAL_WIN32);
if (CURLE_OK != return_code) return NULL;
// 获取easy handle
CURL *easy_handle = curl_easy_init();
if (NULL == easy_handle)
{
curl_global_cleanup();
return NULL;
}
string buffer;
string post_url = “http://d.web2.qq.com/channel/login2”;
string referer_url = “http://d.web2.qq.com/proxy.html”;
string base = “{\”status\”:\”\”,\”ptwebqq\”:\””+ptwebqq+”\”,\”passwd_sig\”:\”\”,\”clientid\”:\””+clientid+”\”}”;
string urlencode = curl_easy_escape(easy_handle,base.c_str(),0);
string fields = “r=”+urlencode;
// 设置easy handle属性
curl_easy_setopt(easy_handle, CURLOPT_URL, post_url.c_str());
curl_easy_setopt(easy_handle, CURLOPT_REFERER, referer_url.c_str());
curl_easy_setopt(easy_handle, CURLOPT_POST, 1);
curl_easy_setopt(easy_handle, CURLOPT_POSTFIELDS, fields.c_str());
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, &buffer);
//提交第一步保存的cookie
curl_easy_setopt(easy_handle, CURLOPT_COOKIEFILE,”D:\\SparkHo\\cookie_login.txt”);
//保存登陆后的cookie
curl_easy_setopt(easy_handle, CURLOPT_COOKIEJAR,”D:\\SparkHo\\cookie_login.txt”);
// 执行数据请求
curl_easy_perform(easy_handle);
// 释放资源
curl_easy_cleanup(easy_handle);
curl_global_cleanup();
//从buffer中,提取vfwebqq、psessionid
found  = buffer.find(“vfwebqq”);
found2 = buffer.find(“\””,found+10,1);
string vfwebqq = buffer.substr(found+10,found2-found-10);
found  = buffer.find(“psessionid”);
found2 = buffer.find(“\””,found+13,1);
string psessionid = buffer.substr(found+13,found2-found-13);
//记录QQ登录信息,存放在指定的txt文件中:
fstream QQLoginfile(“D:\\SparkHo\\QQLogin.txt”,ios::out|ios::trunc);
QQLoginfile<<“ClientID:”<<clientid.c_str()<<“;”;
QQLoginfile<<“vfwebqq:”<<vfwebqq.c_str()<<“;”;
QQLoginfile<<“psessionid:”<<psessionid.c_str()<<“;”;
QQLoginfile.close();

return buffer;
}


4。断线重连。
Login2成功登陆后,我们得到一个Cookies文件:内含ptwebqq;还有一个存放QQ登录信息的txt文件:内含clientId和psessionid。
当网络中断、QQ离线或被踢下线,需要重新登录的时候,可以使用上述信息进行重新连接。
抓包:
POSThttp://d.web2.qq.com/channel/login2HTTP/1.1
Referer:http://d.web2.qq.com/proxy.html
POST数据:一个json数据结构:
r={“status”:”online”,”ptwebqq”:”【ptwebqq】”,”passwd_sig”:””,”clientid”:”【clientid】”,”psessionid”:”【psessionid】”}
&clientid=【clientid】&psessionid=【psessionid】
需要的参数:
1)【ptwebqq】在libcurl存档的Cookies文件中读取;
2)【clientid】是上次Login2登录的用户识别码;【psessionid】是上次Login2登录返回的;都可以从以前保存的登录信息文件QQLogin.txt里读出。

C++ (with libcurl)源程序
string WebQQ_login2_r()
{
size_t found,found2;
char buf[1024];
// 在Cookies文件中,读取:ptwebqq
string ptwebqq;
ifstream QQCookiesfile(“D:\\SparkHo\\cookie_login.txt”);
if(!QQCookiesfile)
{
QQCookiesfile.close();
ptwebqq = “”;
}
else
{
QQCookiesfile.read(buf,1024);
string QQCookies = (string) buf;
QQCookiesfile.close();
found  = QQCookies.find(“ptwebqq”);
found2 = QQCookies.find(“\n”,found+8,1);
ptwebqq = QQCookies.substr(found+8,found2-found-8);
}
// 提取QQ登录信息:
string clientid,psessionid;
ifstream QQLoginfile(“D:\\SparkHo\\QQLogin.txt”);
if(!QQLoginfile)
{
QQLoginfile.close();
clientid = “”;
psessionid = “”;
}
else
{
QQLoginfile.read(buf,1024);
string QQLogin = (string) buf;
QQLoginfile.close();
found  = QQLogin.find(“ClientID”);
found2 = QQLogin.find(“;”,found+9,1);
clientid = QQLogin.substr(found+9,found2-found-9);
found  = QQLogin.find(“psessionid”);
found2 = QQLogin.find(“;”,found+11,1);
psessionid = QQLogin.substr(found+11,found2-found-11);
}
// 初始化libcurl
CURLcode return_code;
return_code = curl_global_init(CURL_GLOBAL_WIN32);
if (CURLE_OK != return_code) return NULL;
// 获取easy handle
CURL *easy_handle = curl_easy_init();
if (NULL == easy_handle)
{
curl_global_cleanup();
return NULL;
}
string buffer;
string post_url = “http://d.web2.qq.com/channel/login2”;
string referer_url = http://d.web2.qq.com/proxy.html;
string base = “{\”status\”:\”online\”,\”ptwebqq\”:\””+ptwebqq+”\”,\”passwd_sig\”:\”\”,\”clientid\”:\””+clientid+”\”,\”psessionid\”:\””+psessionid+”\”}”;
string urlencode = curl_easy_escape(easy_handle,base.c_str(),0);
string fields = “r=”+urlencode+”&clientid=”+clientid+”&psessionid=”+psessionid;
// 设置easy handle属性
curl_easy_setopt(easy_handle, CURLOPT_URL, post_url.c_str());
curl_easy_setopt(easy_handle, CURLOPT_REFERER, referer_url.c_str());
curl_easy_setopt(easy_handle, CURLOPT_POST, 1);
curl_easy_setopt(easy_handle, CURLOPT_POSTFIELDS, fields.c_str());
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, &buffer);
//提交保存的cookie
curl_easy_setopt(easy_handle, CURLOPT_COOKIEFILE,”D:\\SparkHo\\cookie_login.txt”);
//保存登陆后的cookie
curl_easy_setopt(easy_handle, CURLOPT_COOKIEJAR,”D:\\SparkHo\\cookie_login.txt”);
// 执行数据请求
curl_easy_perform(easy_handle);
// 释放资源
curl_easy_cleanup(easy_handle);
curl_global_cleanup();
//从buffer中,提取vfwebqq、psessionid
found  = buffer.find(“vfwebqq”);
found2 = buffer.find(“\””,found+10,1);
string vfwebqq = buffer.substr(found+10,found2-found-10);
found  = buffer.find(“psessionid”);
found2 = buffer.find(“\””,found+13,1);
psessionid = buffer.substr(found+13,found2-found-13);
// 更新QQ登录信息:
fstream QQLoginwrite(“D:\\SparkHo\\QQLogin.txt”,ios::out|ios::trunc);
QQLoginwrite<<“ClientID:”<<clientid.c_str()<<“;”;
QQLoginwrite<<“vfwebqq:”<<vfwebqq.c_str()<<“;”;
QQLoginwrite<<“psessionid:”<<psessionid.c_str()<<“;”;
QQLoginwrite.close();

return buffer;

 

庆六一新版QQ登录加密算法java版

/**
* 加密WEBqq 传输时的密码
* @author weirhp@gmail.com
* http://weibo.com/weirhp
*/
public class EncodeQQPass {

public static void main(String[] args) {
System.out.println(encodePass(“yourpass”, “!CEY”,
“\\x00\\x00\\x00\\x00\\x35\\x33\\x5f\\x58”));
}

public static String encodePass(String password, String vcode, String uin) {
String[] us = uin.split(“\\\\x”);
byte[] uinByte = new byte[us.length – 1];
if (us.length == 9) {
for (int i = 1; i < us.length; i++) {
uinByte[i – 1] = getByte(Integer.parseInt(us[i], 16));
}
}
return md5(md5(getByte(hexchar2bin(md5(password)), uinByte))
+ vcode.toUpperCase());
}

public static String md5(byte[] source) {
String s = null;
char hexDigits[] = { ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’,
‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’ };
try {
java.security.MessageDigest md = java.security.MessageDigest
.getInstance(“MD5”);
md.update(source);
byte tmp[] = md.digest();
char str[] = new char[16 * 2];
int k = 0;
for (int i = 0; i < 16; i++) {
byte byte0 = tmp[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
s = new String(str);
} catch (Exception e) {
e.printStackTrace();
}
return s.toUpperCase();
}

public static String md5(String str) {
return md5(str.getBytes()).toUpperCase();
}

public static byte[] hexchar2bin(String str) {
byte[] bytes = new byte[str.length() / 2];
int j = 0;
for (int i = 0; i < str.length(); i = i + 2) {
int iv = Integer.parseInt(str.substring(i, i + 2), 16);
bytes[j++] = getByte(iv);
}
return bytes;
}

public static byte getByte(int intValue) {
int byteValue = 0;
int temp = intValue % 256;
if (intValue < 0) {
byteValue = temp < -128 ? 256 + temp : temp;
} else {
byteValue = temp > 127 ? temp – 256 : temp;
}
return (byte) byteValue;
}

public static byte[] getByte(byte[] b1, byte[] b2) {
byte[] bs = new byte[b1.length + b2.length];
int i = 0;
for (i = 0; i < b1.length; i++) {
bs[i] = b1[i];
}
for (int j = 0; j < b2.length; j++) {
bs[i + j] = b2[j];
}
return bs;
}
}

使用Java实现登陆WebQQ(带源码)

 使用Java中的URL 和 HttpURLConnection 就可以实现模拟网页登陆!
分析登陆的协议,可以使用HttpWatcher,蛮好用的!
目前就两种网页请求方式
Get和Post
我们可以自己先写好这两个方法,以便之后调用
这个就是Get请求方式了,参数就是URL地址

Java代码  收藏代码
  1. public static String get(String url) {
  2.     System.out.println(“get>>>” + url);
  3.     URL serverUrl;
  4.     HttpURLConnection conn;
  5.     StringBuffer res = new StringBuffer();
  6.     try {
  7.         serverUrl = new URL(url);
  8.         conn = (HttpURLConnection) serverUrl.openConnection();
  9.         conn.setRequestMethod(“GET”);// “POST” ,”GET”
  10.         conn.addRequestProperty(“Cookie”, cookie);
  11.         conn.addRequestProperty(“Accept-Charset”, “UTF-8;”);// GB2312,
  12.         conn.addRequestProperty(“User-Agent”,
  13.                 “Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Firefox/3.6.8”);
  14.         conn.connect();
  15.         if (conn.getHeaderFields().get(“Set-Cookie”) != null) {
  16.             for (String s : conn.getHeaderFields().get(“Set-Cookie”)) {
  17.                 cookie += s;
  18.             }
  19.         }
  20.         InputStream ins = conn.getInputStream();
  21.         String charset = “UTF-8”;
  22.         InputStreamReader inr = new InputStreamReader(ins, charset);
  23.         BufferedReader bfr = new BufferedReader(inr);
  24.         String line = “”;
  25.         do {
  26.             res.append(line);
  27.             line = bfr.readLine();
  28.             // System.out.println(line);
  29.         } while (line != null);
  30.         System.out.println(“Value>>” + res);
  31.     } catch (MalformedURLException e) {
  32.         // TODO Auto-generated catch block
  33.         e.printStackTrace();
  34.     } catch (IOException e) {
  35.     }
  36.     return res.toString();
  37. }

1.登陆前,我们需要判断此次登陆是否需要手动输入验证码。
地址(GET):http://ptlogin2.qq.com/check?uin=********(QQ号码)&appid=1003903(固定)&r=0.2664082343145449(随机18位  简单的说   0.后面+随机16位数)

返回值有两种
第一种:
ptui_checkVC(‘1′,’8a6143167c8ca486696cf01c3ea088d658b913d64b11289b’)
这种情况下,我们需要获得验证码图片并手动输入验证码。
此时我们可以将图片保存下来,然后使用SWING显示并输入,就可以得到验证码了。
第二种:
“ptui_checkVC(‘0′,’!OMD’);
这种情况下,!OMD就是我们需要的验证码了。

2.第一次登陆
得到验证码之后就可以进行第一次登陆,为什么是第一次?你试验下就知道了,当你此次登陆成功后,发现登陆的QQ并没有提示掉线或者别处登陆的,这是因为我们还需要后续的第二次登陆。

庆六一新版QQ登录加密算法java版


呵呵~verifycode我们第一步就得到了。QQ号我们也知道。就是参数p啦~
就是使用密码和验证码经过加密得到的啦。
想研究加密过程的同学可以百度下,很多的!
此段加密算法是在一个js脚本里,我们可以下下来这个脚本,然后直接调用。

Java代码  收藏代码
  1. public static String mdP(String p, String code){
  2.         Object t = null ;
  3.         try {
  4.             ScriptEngineManager m = new ScriptEngineManager();
  5.             ScriptEngine se = m.getEngineByName(“javascript”);
  6.             se.eval(new FileReader(new File(“comm.js”)));
  7.             t = se.eval(“md5(md5_3(\””+p+”\”)+\””+code.toUpperCase()+”\”);”);
  8.             return t.toString();
  9.         }catch (Exception e) {
  10.             e.printStackTrace();
  11.         }
  12.         return t.toString();
  13.     }

第一登陆后,TX会返回Cookie,我们需要保持,在之后的第二次登陆中使用。

3.第二次登陆
需要使用Post方法:http://d.web2.qq.com/channel/login2
POST数据:
r=%7B%22status%22%3A%22online%22%2C%22ptwebqq%22%3A%22” + ptwebqq + “%22%2C%22passwd_sig%22%3A%22%22%2C%22clientid%22%3A%22” + clientid + “%22%2C%22psessionid%22%3Anull%7D&clientid=” + clientid + “&psessionid=null
ptwebqq 就是我们在第一次登陆后获得的Cookie里的值,clientid是随机的的值,可以直接使用抓取到的值。
登陆成功后,会返回数据
{“retcode”:0,”result”:{“uin”:********(QQ号码),”cip”:3071582136,”index”:1078,”port”:53985,”status”:”hidden”,”vfwebqq”:”5ab2ce0743496ffa257aa4119f35e44324171aa08d3e14a4c506b7e392ca80b73e34551cef71a248″,”psessionid”:”8368046764001e636f6e6e7365727665725f7765627171403137322e32372e3138312e3835000062450000079e03620524ef666d0000000a406e4e53734a517a33556d000000285ab2ce0743496ffa257aa4119f35e44324171aa08d3e14a4c506b7e392ca80b73e34551cef71a248″}}

vfwebqq和psessionid在之后和获取好友,群信息,以及发送消息都要使用。

目前做到发送消息,不过老是返回{“retcode”:122,”errmsg”:”wrong web client3″}
Post数据也没有问题,不知道到底是为啥~
目前写的类也有点乱,打算使用HttpClient重新写~

附上源代码,谁要是解决了发消息的问题
给我说声啊~

QQ空间登陆密码加密算法(C#)

前几天写了个QQ空间转载、分享的小工具,说到转载和分享,自然就少不了登陆,尝试过登陆QQ空间的朋友应该知道,登陆的密码是经过加密后传递的,听前辈说以前貌似是MD5 3次,现在却不一样了,现在采用的是动态加密,加密结果和验证码有密切关系,换句话说,是密码+算法+验证码在一起,好了,废话不说,上加密算法。

public static string smethod_0(string s)
{
MD5 mD = MD5.Create();
byte[] bytes = Encoding.ASCII.GetBytes(s);
byte[] array = mD.ComputeHash(bytes);
StringBuilder stringBuilder = new StringBuilder();
byte[] array2 = array;
for (int i = 0; i < array2.Length; i++)
{
byte b = array2[i];
stringBuilder.Append(b.ToString(“x”).PadLeft(2, ‘0’));
}
return stringBuilder.ToString().ToUpper();
}
public static byte[] EncyptMD5Bytes(string s)
{
MD5 mD = MD5.Create();
byte[] bytes = Encoding.ASCII.GetBytes(s);
return mD.ComputeHash(bytes);
}
public static string smethod_1(byte[] s)
{
MD5 mD = MD5.Create();
byte[] array = mD.ComputeHash(s);
StringBuilder stringBuilder = new StringBuilder();
byte[] array2 = array;
for (int i = 0; i < array2.Length; i++)
{
byte b = array2[i];
stringBuilder.Append(b.ToString(“x”).PadLeft(2, ‘0’));
}
return stringBuilder.ToString().ToUpper();
}
public static string EncryptQQWebMd5(string s)
{
MD5 mD = MD5.Create();
byte[] bytes = Encoding.ASCII.GetBytes(s);
byte[] array = mD.ComputeHash(bytes);
StringBuilder stringBuilder = new StringBuilder();
byte[] array2 = array;
for (int i = 0; i < array2.Length; i++)
{
byte b = array2[i];
stringBuilder.Append(“\\x“);
stringBuilder.Append(b.ToString(“x2”));
}
return stringBuilder.ToString();
}
public static string EncryptOld(string password, string verifyCode)
{
return smethod_0(EncyptMD5_3_16(password) + verifyCode.ToUpper());
}
public static string Encrypt(string qq, string password, string verifyCode)
{
return Encrypt((long)Convert.ToDouble(qq), password, verifyCode);
}
public class ByteBuffer
{
private byte[] byte_0;
public Stream BaseStream;
public ByteBuffer()
{
                this.BaseStream = new MemoryStream();
this.byte_0 = new byte[16];
}
public virtual long Seek(int offset, SeekOrigin origin)
{
return this.BaseStream.Seek((long)offset, origin);
}
public bool Peek()
{
return this.BaseStream.Position < this.BaseStream.Length;
}
public byte[] ToByteArray()
{
//long position = this.BaseStream.Position;
//this.BaseStream.Position = 0L;
//byte[] array = new byte[(int)((object)((IntPtr)this.BaseStream.Length))];
//this.BaseStream.Read(array, 0, array.Length);
//this.BaseStream.Position = position;
//return array;
                long position = this.BaseStream.Position;
this.BaseStream.Position = 0L;
byte[] buffer = new byte[this.BaseStream.Length];
this.BaseStream.Read(buffer, 0, buffer.Length);
this.BaseStream.Position = position;
return buffer;
            }
public void Put(bool value)
{
this.byte_0[0] = value ? ((byte)1) : ((byte)0);
this.BaseStream.Write(this.byte_0, 0, 1);
            }
public void Put(byte value)
{
this.BaseStream.WriteByte(value);
}
public void Put(byte[] value)
{
if (value == null)
{
throw new ArgumentNullException(“value”);
}
this.BaseStream.Write(value, 0, value.Length);
}
public void PutInt(int value)
{
this.PutInt((uint)value);
}
public void PutInt(uint value)
{
this.byte_0[0] = (byte)(value >> 24);
this.byte_0[1] = (byte)(value >> 16);
this.byte_0[2] = (byte)(value >> 8);
this.byte_0[3] = (byte)value;
this.BaseStream.Write(this.byte_0, 0, 4);
}
public void PutInt(int index, uint value)
{
int offset = (int)this.BaseStream.Position;
this.Seek(index, SeekOrigin.Begin);
this.PutInt(value);
this.Seek(offset, SeekOrigin.Begin);
}
public byte Get()
{
return (byte)this.BaseStream.ReadByte();
}
}
public static string Encrypt(long qq, string password, string verifyCode)
{
ByteBuffer byteBuffer = new ByteBuffer();
byteBuffer.Put(EncyptMD5Bytes(password));
byteBuffer.PutInt(0);
byteBuffer.PutInt((uint)qq);
EncryptQQWebMd5(password);
byte[] s = byteBuffer.ToByteArray();
string str = smethod_1(s);
return smethod_0(str + verifyCode.ToUpper());
}
上面的加密算法,调用方法是:string str = Encrypt(QQ号, QQ密码, 验证码);
加密后的密码会返回到str中,然后使用返回的密码进行登录就是了
顺便说一句,QQ空间登录是采用的GET而不是POST哦

QQ宠物自动购买藏宝图碎片外挂之数据包监听 | 抓取QQ宠物数据包

饲养QQ宠物笔者用了QQ辅助工具:宠爱天使。但是它购买碎片的速度太慢了!并且每购买一个都需要用户比较复杂的重复一次操作!因此,笔者萌生了写一个自动购买藏宝图碎片外挂的想法。抓包分析是其基础。这是这篇记录的由来。

抓包使用了:

Process Explorer.

cmd窗口

wireshark

数据的发送测试,使用的啊D

 

首先使用Process Explorer来获取宠爱天使的进程号,之后再cmd中,使用命令:

netstat -ano 来查看本机建立的网络连接以及端口号。找到宠爱天使的进程号对应的端口。如果因为连接太多不容易找,可以使用命令:

netstat -ano | grep 5788

这样的命令来直接找到进程号5788对应的连接信息。

测试中本地的信息如下:

C:\Documents and Settings\chuan>netstat -ano | grep 5788
File STDIN:
TCP 211.87.235.173:44542 121.14.195.66:8080 CLOSE_WAIT 5788

从而,可知本地端口号为44542。

打开wireshark 指定监听规则为:

 ip.src == 211.87.235.173 and (udp or tcp) and ip.addr == 59.78.209.151

目标地址的ip (ip.addr) 可以通过手动购买1个藏宝图碎片,然后观察在wiresharp中突发的数据包的目标地址。

在定义监听规则之后可以再次购买藏宝图碎片,在wiresharp中出现的就是在交易中发送的数据。

在测试中数据包如下所示:

GET /cgi-bin/treasure_limit_buy?cmd=0&type=0 HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0;)
Host: act.pet.qq.com
Connection: close
Cache-Control: no-cache
Cookie: PET_SIGN_TYPE=SSOSIGN; PET_UIN=290隐藏几位94; PET_SIGN=0001513隐藏几位00705C6AC45E2411FFB83638F689353726AC7F54B415A73B9隐藏几位61E66E65F35FC794241A5隐藏几位8C50764B3EE5E45CBFF935910B8B9DDBEA40C27EF01C7154070453283C793086353033B7EA5FFDEA9B161C226DC374E54C7D603BC9隐藏几位B8275E83142127A21DBC96F2E738BF757704; PET_ID=7233隐藏几位87138674

 

到这里,我们需要的数据已经获取到了,在使用的时候只需要把cookie设置成上述数据包中cookie的内容,同时访问上述数据包的网络地址,就可以完成一次购买过程了。

使用啊D测试结果如下图:

cookie

 

在下一步就是编写一个自动保持cookie和发送购买请求的一个小软件了。