抓包
首先进入qq任意一个网页抓一下快捷登录数据
注意:本人尝试了不同网页,所以抓包的数据的appid可能不一致,请忽略
看到了
https://localhost.ptlogin2.qq.com:4303/pt_get_uins?callback=ptui_getuins_CB&r=0.7051911581809474&pt_local_tk=787563823
var var_sso_uin_list=[{"uin":4548212,"face_index":0,"gender":0,"nickname":"无敌暴龙战神李恒道","client_type":65793,"uin_flag":xxx,"account":4548212}]
得到了一个单点登录列表
提交参数有三个,callback应该是固定的
我们主攻r和pt_local_tk
全局搜一下
找到了
N = function N(t, e, n, o, i) {
var r;
k["default"].cookie.get("pt_local_token") || (k["default"].cookie.set("pt_local_token", Math.random(), "ptlogin2." + ft.ptui.domain),
k["default"].cookie.get("pt_local_token")) ? (r = ft.ptui.isHttps ? E : x,
t = "https://localhost.ptlogin2." + ft.ptui.domain + ":[port]/" + t + "&r=" + Math.random() + "&pt_local_tk=" + k["default"].cookie.get("pt_local_token"),
dt(t, r, e, window[n], o, i)) : c.logger.warn("无法设置cookie,无法使用快速登录")
}
可以看出r是一个随机数,pt_local_tk取得是cookies中的pt_local_token
找来找去最后确定了
https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=716027609&daid=383&style=33&login_text=%E7%99%BB%E5%BD%95&hide_title_bar=1&hide_border=1&target=self&s_url=https%3A%2F%2Fgraph.qq.com%2Foauth2.0%2Flogin_jump&pt_3rd_aid=102013353&pt_feedback_link=https%3A%2F%2Fsupport.qq.com%2Fproducts%2F77942%3FcustomInfo%3D.appid102013353&theme=10&verify_theme=
可以得到pt_local_token的返回
关于端口问题可以尝试直接搜4303
可以得到
x = [4300, 4302, 4304, 4306, 4308],
E = [4301, 4303, 4305, 4307, 4309],
根据观察规律以E为主,但是秉承着安全的态度,我们可以视为一共有十个端口
分析点击登录
我们查看dom点击事件可以找到
pt.qlogin.imgClick
z = function z(t) {
var e = parseInt(t.getAttribute("type"), 10)
, n = t.getAttribute("uin");
switch (c.logger.info("点击快速登录头像 uin=".concat(n, " type=").concat(e)),
e) {
case 1:
pt.reportPath(n, 2),
F();
break;
case 2:
R(n),
pt.reportPath(n, 1);
break;
case 4:
Q(n),
pt.reportPath(n, 1);
break;
case g:
V(n, !0),
pt.reportPath(n, 4)
}
}
这里走到了4
也就是
Q(n),
pt.reportPath(n, 1);
看函数应该是Q是主要函数,reportPath看名字是一个重定向函数
所以我们去分析Q吧
Q = function Q(t) {
t && (S["default"].showLoading(),
N("pt_get_st?clientuin=" + t, 8e3, "ptui_getst_CB", function(t) {
c.logger.info("pt_get_st data", t),
o.ptui_getst_CB(t)
}, function() {
S["default"].hideLoading(),
o.ptui_qlogin_CB("-1234", "", "快速登录失败,请检查网络情况或QQ客户端是否打开。")
}),
o.ptui_getst_CB.submitUrl = B({
"uin": t,
"pt_local_tk": "{{hash_clientkey}}"
}))
}
showLoading显示登录
那主要逻辑就是N
看参数来说
参数1,地址'pt_get_st?clientuin=4548212'
参数2,固定参数8e3,调试猜测为超时
别问哪看出来的,qzone主动打出来日志了...
jsonp url=https://localhost.ptlogin2.qq.com:4303/pt_get_st?clientuin=4548212&r=0.8219003701233059&pt_local_tk=-1988371938 timeout=8000
参数3,一个字符串ptui_getst_CB
参数4,疑似成功函数
参数5,疑似失败函数
参数6,通过B函数传入t为4548212(我的qq),生成一串url到o.ptui_getst_CB.submitUrl
https://ssl.ptlogin2.qq.com/jump?clientuin=4548212&keyindex=9&pt_aid=549000912&daid=5&u1=https%3A%2F%2Fqzs.qzone.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_local_tk={{hash_clientkey}}&pt_3rd_aid=0&ptopt=1&style=40&has_onekey=1
再作为参数
这里可能是利用副作用生成一串跳转函数
猜测一下之后继续往里看
N = function N(t, e, n, o, i) {
var r;
k["default"].cookie.get("pt_local_token") || (k["default"].cookie.set("pt_local_token", Math.random(), "ptlogin2." + ft.ptui.domain),
k["default"].cookie.get("pt_local_token")) ? (r = ft.ptui.isHttps ? E : x,
t = "https://localhost.ptlogin2." + ft.ptui.domain + ":[port]/" + t + "&r=" + Math.random() + "&pt_local_tk=" + k["default"].cookie.get("pt_local_token"),
dt(t, r, e, window[n], o, i)) : c.logger.warn("无法设置cookie,无法使用快速登录")
}
这里并没有参数六,所以可能单纯就是利用副作用设置url,然后抛弃了这个参数
第一句功能就是先检测是否有pt_local_token的cookies,没有就随便设一个
k["default"].cookie.get("pt_local_token") || (k["default"].cookie.set("pt_local_token", Math.random(), "ptlogin2." + ft.ptui.domain)
然后尝试调用k["default"].cookie.get("pt_local_token"))读取
最后可以确定基本走到了
(r = ft.ptui.isHttps ? E : x,
t = "https://localhost.ptlogin2." + ft.ptui.domain + ":[port]/" + t + "&r=" + Math.random() + "&pt_local_tk=" + k["default"].cookie.get("pt_local_token"),
dt(t, r, e, window[n], o, i))
r = ft.ptui.isHttps ? E : x是选择端口,判断是否是https,如果是就是
[4301, 4303, 4305, 4307, 4309]
如果不是就是
[4300, 4302, 4304, 4306, 4308]
这里我们知道了E和x的使用,不过出于兼容开发我个人依然倾向于全用
然后拼接出来一个t
t = "https://localhost.ptlogin2." + ft.ptui.domain + ":[port]/" + t + "&r=" + Math.random() + "&pt_local_tk=" + k["default"].cookie.get("pt_local_token")
然后调用dt(t, r, e, window[n], o, i))
继续往里看dt
dt = function dt(t, e, n, o, i, r) {
-1 < t.indexOf("/pt_get_st?") ? ct(t, e, n, i, r) : lt(t, e, n, o, i, r)
}
判断是否是pt_get_st,调用ct或lt,这次我们调用ct
注意,这里忽略了参数o,也就是 window[n]的函数
ct = function ct(t, e, n, o, i) {
return rt.apply(this, arguments)
}
继续往里看,到这里往里就是一系列传参了,我个人来说比较懒得调了
于是直接抓包+刚才的几个函数下断
于是断到了
N("pt_get_st?clientuin=" + t, 8e3, "ptui_getst_CB",xxxxx)
中的
function(t) {
c.logger.info("pt_get_st data", t),
o.ptui_getst_CB(t)
}
传入的t是{uin: 4548212, keyindex: 9}
这个参数是来自于
https://localhost.ptlogin2.qq.com:4303/pt_get_st?clientuin=4548212&r=0.8813633351013919&pt_local_tk=-1988371938&callback=__jp1
这个网址设置了一些cookies,凭感觉重要
Set-Cookie:
clientkey=0001644A9ADA0068911F2DDABS89881BB01D262197CC69F90F250E5A3921264AF159455562A4B03BDD8FB76C371EBEF54945DA9E5EE4A3E32EFC298172F773E7BF75B15F788DB1BFADSW28E9F0EE7F407AD5A4BF48C5044C98AFE920FB4ASX9D777D60007A34D97C6E5F35A362F; path=/; domain=ptlogin2.qq.com; Secure; SameSite=None
可以看出就是端口遍历+N函数传入的地址参数拼接一下
然后调用o.ptui_getst_CB(t)
function p(t) {
var e;
p.called = !0,
t && (r["default"].hideLoading(),
p.submitUrl && (e = p.submitUrl.replace("{{hash_clientkey}}", a["default"].str.hash33(a["default"].cookie.get("clientkey"))),
t.keyindex && (e = e.replace(/keyindex=\d+/, "keyindex=" + t.keyindex),
a["default"].report.monitor(2423538, 1)),
u["default"].reportPCMgr(t.uin, 2),
a["default"].http.loadScript(e)),
a["default"].report.monitor(508159, 1))
}
还记着我们最开始的的副作用函数吗
o.ptui_getst_CB.submitUrl = B({
"uin": t,
"pt_local_tk": "{{hash_clientkey}}"
}))
这里就是做了一个简单的替换,然后加载对应地址
之前是
https://ssl.ptlogin2.qq.com/jump?clientuin=4548212&keyindex=9&pt_aid=549000912&daid=5&u1=https%3A%2F%2Fqzs.qzone.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_local_tk={{hash_clientkey}}&pt_3rd_aid=0&ptopt=1&style=40&has_onekey=1
生成的地址是
https://ssl.ptlogin2.qq.com/jump?clientuin=4548212&keyindex=9&pt_aid=549000912&daid=5&u1=https%3A%2F%2Fqzs.qzone.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_local_tk=687472173&pt_3rd_aid=0&ptopt=1&style=40&has_onekey=1
可以看出替换了个hash_clientkey
是使用a["default"].str.hash33对我们上一个地址获取的clientkey做计算的
直接拆函数
function(t) {
for (var e = 0, n = 0, o = t.length; n < o; ++n)
e += (e << 5) + t.charCodeAt(n);
return 2147483647 & e
}
我们计算出刚才替换的地址后直接访问会得到
ptui_qlogin_CB('0', 'https://ptlogin2.qzone.qq.com/check_sig?pttype=2&uin=4548212&service=xxxxx', '')
直接访问该地址就实现了快捷登录
那么至此,qq快捷登录就算分析完毕了
结语
撒花~