前言
本来曾研究过QQ的快速登陆协议,现在查看,本地端口检测好像是增加了HTTPS的检验,造成了软件内因为证书不符无法查询到当前机器所登陆的QQ号码。
既然QQ的快速登陆搞不了了,那么只能退而求其次,来研究一下QQ的扫码登陆协议。
其实这种协议只需要一步一步的跟着请求走即可,不难,是可以追踪出来的,有一个ptqrtoken
值的加密,到时候会详细的说一下。
因为我对VB使用较为擅长,所以本文中的一此代码采用VB语言方式进行的,改为易语言还是非常简单的。
最后本文原创,但首发自了某爱,精易我也发一下,供各位学习分享。
首次请求
[GET方式]https://xui.ptlogin2.qq.com/cgi-bin/xlogin?pt_disable_pwd=1&appid=1006102&daid=1&style=23&hide_border=1&proxy_url=https://id.qq.com%2Flogin%2Fproxy.html&s_url=https://id.qq.com/index.html
GET方式请求之后在Response Headers
中,可以得到以下的内容。
咱们需要获取到Set-Cookie
中的内容,如以下的代码。
Headers = .getAllResponseHeaders
全局变量_pt_local_token = Split(Split(Headers, "pt_local_token=")(1), ";")(0)
pt_local_token
这个第一次请求必须得记住下来,不然后续的二维码循环状态判断是进行不了的,需要用到这个关键的参数。
保存下来,以便下方请求再次调用。
楼下朋友反馈,说第一步可不需获取,循环判断验证码时,为空即可。也可以成功,我这里测试也是可以,看个人需求了,我习惯带入,跟着腾讯的协议走。
获取验证码图片
[GET]https://ssl.ptlogin2.qq.com/ptqrshow?appid=1006102&e=2&l=M&s=3&d=72&v=4&t=0.5518777591223158&daid=1&pt_3rd_aid=0
请求此处时需要带入Cookie
,至于Cookie第一次请求时保存的全局变量Cookie
全部带入即可,当然你也可以测试需要哪些关键Cookie
带入,我为了保险起见所以全部带入了。
返回的二进制内容保存为图片,这个就是第一次的验证码了。
在此处需要将Response Headers
中的qrsig
保存记录下来,以便加密ptqrtoken
所调用。
加密ptqrtoken
上面的首次的验证码获取了,那么需要将ptqrtoken
进行加密,进行调用,首先得找到加密的JS函数。
根据关键字:ptqrtoken
来寻找网页下的所有的JS文件。
寻找到了加密函数在下方JS文件中。
https://cdn-go.cn/qq-web/any.ptlogin2.qq.com/c7d607f7//ptlogin/ver/19112817/js/c_login_2.js?max_age=604800&ptui_identifier=000D5DCD859A2975B85AC600ED1CBC0DFA6DE534A0CA38EEB6A809B4
将JS格式化,寻找关键的代码。
由此可见,hash33
函数将Cookie
中的qrsig
进行了加密。那么咱们再转入hash33
函数。
此处便是加密的函数了,先测试一下。
<!DOCTYPE html>
<html>
<body>
<h2>JavaScript 函数</h2>
<p id="demo"></p>
<script>
function myFunction(t) {
for (var e = 0,
i = 0,
n = t.length; i < n; ++i) e += (e << 5) + t.charCodeAt(i);
return 2147483647 & e
}
document.getElementById("demo").innerHTML = myFunction("MyHMXxC*28xC-*5FufceoErr8glQhYFrx1pelIHOQf7l8cuGYDB3KPYluy-7sEjR");
</script>
</body>
</html>
可以看到,生成的加密数据与请求中所请求的数据一致,可以确定此加密函数正确。
最后编写JS的运行过程,以便于软件调用,此为VB语言转换,其它语言请自行转换。
Function 计算ptqrtoken(ByVal qrsig$)
Dim obj As Object
Dim code As String
Dim g_tk As String
code = "function getqrsig(t) {for (var e = 0,i = 0,n = t.length; i < n; ++i) e += (e << 5) + t.charCodeAt(i);return 2147483647 & e}getqrsig(""" & qrsig & """)"
Set obj = CreateObject("MSScriptControl.ScriptControl")
obj.AllowUI = True
obj.Language = "JavaScript"
计算ptqrtoken = obj.Eval(code)
End Function
刷新二维码
[GET]https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https%3A%2F%2Fid.qq.com%2Findex.html&ptqrtoken=197505426&ptredirect=1&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1576722506346&js_ver=19112817&js_type=1&login_sig=zuaDBTRNV4tA6ss6G7su84T6gfLQAsP7TTeeZ5HBcswhRIdsl6d3T4nVUjbIYwo8&pt_uistyle=40&aid=1006102&daid=1&
`login_sig`为第一次请求中的`pt_local_token`带入进去。
注:如果第一次不请求,不获取Cookie中的`pt_login_sig`的话,此处可为空,但建议还是跟着腾讯的走,避免出错。
连接中`ptqrtoken`参数后面的`197505426`为`qrsig`加密`ptqrtoken`值,需要带入。
携带请求头
Cookie: qrsig= 全局变量_qrsig
刷新验证码请求中的qrsig
必须带入,不然显示不出来。
其它的全局变量在第一次请求时均已获取到,还有一个全局变量_qrsig
这个是在获取验证码图片中所得到的,可以看上文。
返回的数据
ptuiCB('66','0','','0','二维码未失效。(2467319964)', '')
扫码成功登陆之后返回的数据将会显示为
ptuiCB('0','0','https://ptlogin2.id.qq.com/check_sig?pttype=1&uin=QQ号&service=ptqrlogin&nodirect=0&ptsigx=0c47c15cba96b0b0034eaa3b52a652e17df2f34fb49c92344b144e71c7f95aefeef302b0299f6d514e40a83d7c26d064666e2d9332a5d8a4ea8c86f4xxxxxxxx&s_url=https%3A%2F%2Fid.qq.com%2Findex.html&f_url=&ptlang=2052&ptredirect=101&aid=1006102&daid=1&j_later=0&low_login_hour=0®master=0&pt_login_type=3&pt_aid=0&pt_aaid=16&pt_light=0&pt_3rd_aid=0','1','登录成功!', 'Blue')
我习惯将返回的数据转为JSON数据,JSON数据data[2]
的数据为地址消息(从0开始计算),那么再请求这个地址就可以完成最终的登陆了。
最后登陆取p_skey
首先Cookie中的p_skey
值非常必要,但有一些QQ的操作在上一步取到了uin
以及skey
可能实现,但是更多的还需要另外一个值做配合,那么就是p_skey
。只有获取了p_skey
才算是最终的登陆。
因为大部分的操作都必须配合着p_skey
值来进行的。
请求
https://ptlogin2.id.qq.com/check_sig?pttype=1&uin=QQ号&service=ptqrlogin&nodirect=0&ptsigx=0c47c15cba96b0b0034eaa3b52a652e17df2f34fb49c92344b144e71c7f95aefeef302b0299f6d514e40a83d7c26d064666e2d9332a5d8a4ea8c86f4xxxxxxxx&s_url=https%3A%2F%2Fid.qq.com%2Findex.html&f_url=&ptlang=2052&ptredirect=101&aid=1006102&daid=1&j_later=0&low_login_hour=0®master=0&pt_login_type=3&pt_aid=0&pt_aaid=16&pt_light=0&pt_3rd_aid=0
请求地址为上一步返回数据中的地址。
经楼下提醒可不必携带请求头,直接请求取跳转响应头中的Cookie即可。
请求发出后,会是一个302
页面的跳转,如果跳转的话会获取不到Cookie中p_skey值的,所以在程序中需要获取302页面的p_skey。
我这里说一下VB中获取302
页面的,供学习VB的朋友参考。
首先用Winhttp
请求,设置为Winhttp.Option(6) = False
,这个如果不明白的话可以百度一下就清楚了。
这就可以获取到302
页面中的响应头了。
获取成功
获取成功之后那么就可以通过所保存的uin
、skey
、p_skey
等参数做一些登陆之后的操作了。
最后啦不发源码了,VB语言发到这里也没有意义,各位可以根据这个东西一步一步进行GET请求就可以了,还是很简单的。