二維碼掃碼登陸過程分析


以pay.qq.com查詢QQ賬號Q幣信息為例,了解一下網站的二維碼登陸大致是如何實現的

首先打開騰訊pay.qq.com主頁上的登陸就可以獲取到二維碼了,使用瀏覽器的F12分析請求過程

clip_image002

發現通過打開的https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=11000101&target=self&style=40&s_url=https://pay.qq.com/ipay/login-proxy.html可以獲取到cookies,這個url就先記下來

clip_image004

繼續往下,打開下面的url,響應回來的就是二維碼了

https://ssl.ptlogin2.qq.com/ptqrshow?appid=11000101&e=2&l=M&s=3&d=72&v=4&t=0.6955732471905282&pt_3rd_aid=0

那這些請求的參數是如何得到的呢,多次請求分析發現只有t是隨機變化的,那就給個隨機數吧

參數t的python生成方式(python生成的隨機數多一位)

import random
a=str(random.random())
print(a)
print(a[:-1])

當用手機掃了二維碼之后,會發現一直請求一個地址,而返回的內容就是判定二維碼是否過期的結果。但是請求的url隨二維碼的更新而變化的

clip_image006

獲取是否過期(通過請求的url發現如下規律)

https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://pay.qq.com/ipay/login-proxy.html&ptqrtoken=1300613866&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1514654333018&js_ver=10233&js_type=1&login_sig=pGo5iOnV6O*DY3BgsPM22zAvlWCnVl48PPjrmWIJtQKMHpvYCoWpavmP1JcdWn6g&pt_uistyle=40&aid=11000101&

https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://pay.qq.com/ipay/login-proxy.html&ptqrtoken=1641999182&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1514655242011&js_ver=10233&js_type=1&login_sig=pGo5iOnV6O*DY3BgsPM22zAvlWCnVl48PPjrmWIJtQKMHpvYCoWpavmP1JcdWn6g&pt_uistyle=40&aid=11000101&

https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://pay.qq.com/ipay/login-proxy.html&ptqrtoken=1460309603&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1514656150867&js_ver=10233&js_type=1&login_sig=pGo5iOnV6O*DY3BgsPM22zAvlWCnVl48PPjrmWIJtQKMHpvYCoWpavmP1JcdWn6g&pt_uistyle=40&aid=11000101&

這些url返回結果如下這樣的形式

ptuiCB('66','0','','0','二維碼未失效。(2079330212)', '')

那么,這次的url所附帶的參數更多了,究竟是如何生成的,由於沒有學習過JavaScript,但是猜想這種交互式的網頁一定有js控制的。

打開請求主頁中所有的js鏈接,文件中都沒有相關信息,於是重頭分析請求過程,發現請求了一個url里面返回大量函數,里面有且僅有一個ptqrtoken變量

https://imgcache.qq.com/ptlogin/ver/10233/js/c_login_2.js?max_age=604800&ptui_identifier=000E010D989AA31CE07BA6E98F56BC76012729B221D540BFF0DE375CAC8A

clip_image008

這個url返回的代碼里面找到getSubmitUrl函數如下:

clip_image010

三個參數ptqrtoken、action、login_sig。兩個參數都在函數中說明了,login_sig同樣在這段返回的代碼里面,事實上就是cookies里面的pt_login_sig

clip_image012

 

於是乎可以試着構造一個這樣的url,判斷二維碼是否有效。響應的代碼里面跟三個參數有關的代碼如下

函數的具體實現—ptqrtoken生成

hash33:function(t){
for(var e=0,i=0,n=t.length;i<n;++i)
e+=(e<<5)+t.charCodeAt(i);
return 2147483647&e
}

函數的具體實現—action生成

,pt.plogin={account:"",at_account:"",uin:"",salt:"",checkState:!1,lastCheckAccount:"",needVc:!1,vcFlag:!1,ckNum:{},action:[0,0],passwordErrorNum:1,isIpad:!1,seller_id:703010802
action.join(“-”)+”-”+(new Date-0)

函數的具體實現—login_sig生成(這個是http響應時返回的)

login_sig=pt.ptui.login.sig

 

用javascript測試下實現函數功能的代碼(不懂js所以先試下運行出來是什么結果)

1ptqrtoken

<script type="text/javascript">
document.write(isNaN(123)+ "<br />")
function test(t){
for(var e=0,i=0,n=t.length;i<n;++i)
e+=(e<<5)+t.charCodeAt(i);
return 2147483647&e;
}
document.write(test("l5ReOk*DhvMzPYYjfqWzkYjwSs52j6lzw1Oy6SaMsUNywLorCwuRuP8TbGfzSf*a"))
</script>

2action

document.write(new Date-0);
document.write("<br/>")
var t=new Date()
action=[0,0]
document.write(action.join("-")+"-"+t.getTime())

 

知道了邏輯,用python重寫javascript的函數來實現同樣功能

ptqrtoken的生成

t1="l5ReOk*DhvMzPYYjfqWzkYjwSs52j6lzw1Oy6SaMsUNywLorCwuRuP8TbGfzSf*a"
def test(t):
i=0
e=0
n=len(t)
fori in range(n):
e=e+(e<<5)
e=e+ord(t[i])
print(e)
print(2147483647&e)
test(t1)

action的生成就只是一個時間函數

import time
print(int(time.time()*1000))

 

繼續往下分析連續請求該Url響應用戶的掃碼登陸狀態,發現掃碼成功后,也會返回cookies

帶着cookies請求個人賬戶主頁https://my.pay.qq.com/account/index.shtml?aid=pay.index.header.acct&ADTAG=pay.index.header.acc

發現返回的內容還是沒有Q幣的信息,說明內容還是由javascript動態生成

image

返回的js里面是沒有Q幣信息的

clip_image015

繼續分析下面請求的url

clip_image017

發現了這個 https://my.pay.qq.com/cgi-bin/personal/balance_query_sortflow.cgi?items=qd,qb&_=0.9267836264725212

clip_image019

於是返回的json,qb_balance就是個人賬戶的Q幣

 

import requests
import time
import random
def ptqrtoken_str(qrsig):  #三個函數就是url的三個參數生成
    i=0
    e=0
    n=len(qrsig)
    for i in range(n):
        e=e+(e<<5)
        e=e+ord(qrsig[i])
        e=2147483647&e
    return e

def action_str():
    a=int(time.time()*1000)
    b='0-0-'+str(a)
    return b

def pt_loginsig_str(ckiesget):
    st=ckiesget.headers['Set-Cookie']
    return st[st.find('pt_login_sig=')+13:st.find('pt_login_sig=')+77]
    
url_getcookies="https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=11000101&target=self&style=40&s_url=https://pay.qq.com/ipay/login-proxy.html"
s=requests.session()     #requests的session可以自動管理cookies
ckget=s.get(url_getcookies)

t=str(random.random())
url_getqr="https://ssl.ptlogin2.qq.com/ptqrshow?appid=11000101&e=2&l=M&s=3&d=72&v=4&t="+t[:-1]+"&pt_3rd_aid=0"
qrget=s.get(url_getqr)


f=open('tmp.png','wb') #將二維碼保存為圖片手動打開來掃碼^_^
f.write(qrget.content)
f.close()


for i in range(1,7): #簡單的循環返回二維碼是否失效,循環結束前掃碼就獲得了cookies
    time.sleep(3)
    qrsig=qrget.headers['Set-Cookie'].split(';')[0][6:]
    url_check_timeout="https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://pay.qq.com/ipay/login-proxy.html&ptqrtoken="+str(ptqrtoken_str(qrsig))+"&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action="+action_str()+"&js_ver=10233&js_type=1&login_sig="+pt_loginsig_str(ckget)+"&pt_uistyle=40&aid=11000101&"
    timeoutget=s.get(url_check_timeout)
    print(timeoutget.status_code)
    print('----------------text---------------')
    print(timeoutget.text)
print(timeoutget.headers)

happy3=s.get("https://my.pay.qq.com/cgi-bin/personal/balance_query_sortflow.cgi?items=qd,qb&_="+str(random.random()))
print(happy3.text)

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM