前言
因为最近要写的项目里,刚好有一个是QQ扫码登陆的功能,本来曾研究过QQ的扫码登陆协议,但是发现,在这款APP上有h5sig和一个sign的加密标识,特此记录
首次请求
[GET方式]https://openmobile.qq.com/oauth2.0/m_authorize?cancel_display=1&sdkp=a&display=mobile&format=json&sign=aaa2f79fe600597ba0f63f90f79d6cae
&sdkv=3.5.11.lite&response_type=token&status_os=11&client_id=1105200115&switch=1&status_version=30&show_download_ui=true&pf=openmobile_android&scope=all&compat_v=1&status_machine=MEIZU+18+Pro&style=qr&time=1669700584&redirect_uri=auth%3A%2F%2Ftauth.qq.com%2F
在请求中,我们可以看到,这里面有个 sign=aaa2f79fe600597ba0f63f90f79d6cae
,就很好奇,从哪里来的,抓包分析半天也没见,后面想着会不会是从app里计算的
public static String b(Context context, String str) {
String str2 = "";
SLog.v("openSDK_LOG.SystemUtils", "OpenUi, getSignValidString");
try {
String packageName = context.getPackageName();
Signature[] signatureArr = context.getPackageManager().getPackageInfo(packageName, 64).signatures;
MessageDigest messageDigest = MessageDigest.getInstance(MessageDigestAlgorithms.MD5);
messageDigest.update(signatureArr[0].toByteArray());
String a2 = m.a(messageDigest.digest());
messageDigest.reset();
SLog.v("openSDK_LOG.SystemUtils", "-->sign: " + a2);
messageDigest.update(m.j(packageName + "_" + a2 + "_" + str + ""));
str2 = m.a(messageDigest.digest());
messageDigest.reset();
StringBuilder sb = new StringBuilder();
sb.append("-->signEncryped: ");
sb.append(str2);
SLog.v("openSDK_LOG.SystemUtils", sb.toString());
return str2;
} catch (Exception e) {
SLog.e("openSDK_LOG.SystemUtils", "OpenUi, getSignValidString error", e);
return str2;
}
}
果然,在Java里,找到了计算方法,从中我们可以知道,sign的加密过程是,app的packageName+"_"+signatures(MD5十六进制文本)+"_"+十位时间戳 最后计算md5值即可
GET方式请求之后在 Body 中,可以得到以下的内容
从中我们可以看到,他会访问 src 的地址,我们解码下,可以得到地址
[GET方式]https://xui.ptlogin2.qq.com/cgi-bin/xlogin?pt_enable_pwd=1&appid=716027609&pt_3rd_aid=1105200115&daid=381&pt_skey_valid=0&style=35&force_qr=1&autorefresh=1&s_url=http%3A%2F%2Fconnect.qq.com&refer_cgi=m_authorize&ucheck=1&fall_to_wv=1&status_os=11&redirect_uri=auth%3A%2F%2Ftauth.qq.com%2F&client_id=1105200115&pf=openmobile_android&response_type=token&scope=all&sdkp=a&sdkv=3.5.11.lite&sign=aaa2f79fe600597ba0f63f90f79d6cae&status_machine=MEIZU+18+Pro&switch=1&time=1669700584&show_download_ui=true&h5sig=F9Zpl6MYUBiuX8TG0UdxDSfRfYkWwl80OQThRCyR2ZE&loginty=6
GET方式请求之后在 Response Headers
中,可以得到以下的内容
其中,我们需要把set-cookie全部取出来,之后有用,下面我称之为 全局变量_Cookie
获取二验证码图片
从 xlogin
接口中,我们可以知道,二维码图片的一个链接
[GET请求]https://xui.ptlogin2.qq.com/ssl/ptqrshow?s=8&e=0&appid=716027609&type=0&t=0.11138907652141294&daid=381&pt_3rd_aid=1105200115
请求此处时需要带入 Cookie
,至于Cookie,保存的 全局变量_Cookie
全部带入即可,当然你也可以测试需要哪些关键 Cookie
带入,我为了保险起见所以全部带入了。
返回的二进制内容保存为图片,这个就是第一次的验证码了。在此处需要将 Response Headers
中的 qrsig
保存记录下来,下面称为 全局变量_qrsig
,以便加密 ptqrtoken
所调用。
加密ptqrtoken
上面的二维码码获取了,那么需要将 ptqrtoken
进行加密,进行调用,首先得找到加密的JS函数。
根据关键字:ptqrtoken
来寻找网页下的所有的JS文件。
寻找到了加密函数在下方JS文件中。
https://qq-web-legacy.cdn-go.cn/any.ptlogin2.qq.com/v1.36.0/ptlogin/js/login_10.js
将JS格式化,寻找关键的代码。发现,str.hash33
是关键方法
可以看到,生成的加密数据与请求中所请求的数据一致,可以确定此加密函数正确。最后编写JS的运行过程,以便于软件调用,此为易语言转换,其它语言请自行转换。
刷新二维码
[GET请求]https://xui.ptlogin2.qq.com/ssl/ptqrlogin?u1=http%3A%2F%2Fconnect.qq.com&from_ui=1&type=1&ptlang=2052&ptqrtoken=2099797035&daid=381&aid=716027609&pt_3rd_aid=1105200115&pt_openlogin_data=pt_enable_pwd%3D1%26appid%3D716027609%26pt_3rd_aid%3D1105200115%26daid%3D381%26pt_skey_valid%3D0%26style%3D35%26force_qr%3D1%26autorefresh%3D1%26s_url%3Dhttp%253A%252F%252Fconnect.qq.com%26refer_cgi%3Dm_authorize%26ucheck%3D1%26fall_to_wv%3D1%26status_os%3D11%26redirect_uri%3Dauth%253A%252F%252Ftauth.qq.com%252F%26client_id%3D1105200115%26pf%3Dopenmobile_android%26response_type%3Dtoken%26scope%3Dall%26sdkp%3Da%26sdkv%3D3.5.11.lite%26sign%3Daaa2f79fe600597ba0f63f90f79d6cae%26status_machine%3DMEIZU%2B18%2BPro%26switch%3D1%26time%3D1669700584%26show_download_ui%3Dtrue%26h5sig%3DF9Zpl6MYUBiuX8TG0UdxDSfRfYkWwl80OQThRCyR2ZE%26loginty%3D6%26pt_flex%3D1%26loginfrom%3D%26h5sig%3DF9Zpl6MYUBiuX8TG0UdxDSfRfYkWwl80OQThRCyR2ZE%26loginty%3D6%26&device=2&ptopt=1&pt_uistyle=35&jsver=v1.36.0&r=0.5454414205246301
注:链接中 ptqrtoken
参数后面的 2099797035
为 qrsig
加密 ptqrtoken
值,需要带入。其中还有一个pt_openlogin_data参数 pt_enable_pwd%3D1%26appid%3D716027609%26pt_3rd_aid%3D1105200115%26daid%3D381%26pt_skey_valid%3D0%26style%3D35%26force_qr%3D1%26autorefresh%3D1%26s_url%3Dhttp%253A%252F%252Fconnect.qq.com%26refer_cgi%3Dm_authorize%26ucheck%3D1%26fall_to_wv%3D1%26status_os%3D11%26redirect_uri%3Dauth%253A%252F%252Ftauth.qq.com%252F%26client_id%3D1105200115%26pf%3Dopenmobile_android%26response_type%3Dtoken%26scope%3Dall%26sdkp%3Da%26sdkv%3D3.5.11.lite%26sign%3Daaa2f79fe600597ba0f63f90f79d6cae%26status_machine%3DMEIZU%2B18%2BPro%26switch%3D1%26time%3D1669700584%26show_download_ui%3Dtrue%26h5sig%3DF9Zpl6MYUBiuX8TG0UdxDSfRfYkWwl80OQThRCyR2ZE%26loginty%3D6%26pt_flex%3D1%26loginfrom%3D%26h5sig%3DF9Zpl6MYUBiuX8TG0UdxDSfRfYkWwl80OQThRCyR2ZE%26loginty%3D6%26
这段值也很好看出,是 xlogin
接口中所发的请求数据,用易语言写出如下
携带请求头
Cookie: 全局变量_Cookie; qrsig=全局变量_qrsig;
刷新验证码请求中的 qrsig
必须带入,不然显示不出来。
其它的全局变量在第一次请求时均已获取到,还有一个 全局变量_qrsig
这个是在获取验证码图片中所得到的,可以看上文。
返回的数据
ptuiCB('66', '0', '', '0', '二维码未失效。', '')
扫码成功登陆之后返回的数据将会显示为
ptuiCB('0', '0', 'https://imgcache.qq.com/open/connect/widget/mobile/login/proxy.htm?#&t=1669866495#&openid=********&appid=1105200115&access_token=*****&pay_token=*********&key=*******&serial=&token_key=&browser=0&browser_error=0&status_os=11&sdkv=3.5.11.lite&status_machine=MEIZU+18+Pro&update_auth=&has_auth=&auth_time=1669866495&page_type=0&redirect_uri_key=*******', '0', '登录成功!', 'King丶枫岚')
最后登陆取 openid 和 access_token
模拟过程(特别注意)
在整合过程中,最后发现,从获取二维码
开始,就需要带入 Referer
附加请求头,其值就是 xlogin
接口的链接地址,这在以前研究的时候,是不需要的。
2 条评论
大佬signatures(MD5十六进制文本)这个是怎么来的, 具体怎么去找到这个呢
这个是app的签名,你用mt管理器也能看到