標籤:notify 升級 roc 適合 imp filename 抓包 即時 細節
最近閑來有事, 分析了一個非常低端(非常低端的意思是說你不應該對她是否能取代你現有的QQ用戶端作任何可能的奢望,她只是一個實驗性的東西)的手機QQ的協議, 是手機QQ3.0,
所用到的TCP/HTTP通訊協定版本是1.4, 也不知道是哪一年release的了, 至少有七八年的曆久了吧, 反正就是: 功能非常弱!
主要的分析原因是想學學網路方面的編程經驗(這是我第2次弄socket編程 :-) ), 以及學學怎麼抓包分析.
主要用到的工具軟體
手機QQ3.0: http://www.ruan8.com/soft_5872.html
kEmulator(Java模擬器):http://gamevina.us/kemulator-vh/
Wireshark(協議分析):http://www.wireshark.org/download.html
Java Decompiler(Java查看(和諧)工具):http://jd.benow.ca/
分析流程簡要介紹1.擷取伺服器資訊
網上分析這個版本手機QQ的使用者不在少數, 我也瞭解到這個版本比較容易分析, 協議簡單, 所以...
首先, 開啟這個網址:http://conf.3g.qq.com/newConf/kjava/aubin2.jsp
(注意使用unicode編碼查看, 否則可能亂碼) 然後你就會看到類似下面的東西:
SERERCONFIG_NUM=5& SERVERCONFIG_TYPE=KQQTCP,KQQTCP,KQQHTTP,KQQHTTP,KQQHTTP& SERVERCONFIG_URL=socket://58.60.12.177:14000,socket: //211.136.236.88:14000,http://tqq.tencent.com:8000,http: //mconn.tencent.com:14000,http: //kconn.tencent.com:21001&UPDATAECONFIG_NUM=1& UPDATECONFIG_VERSION=2.4.2&UPDATECONFIG_MUST=N& UPDATECONFIG_URL=http://mq.3g.qq.com/g/s?aid=mqq& UPDATECONFIG_HELPTXT=請升級到2.4.3版QQ2005(Java 版)&SMSSERVICE_NUM=2&SMSSERVICE_NAME=24小時線上,關注好友& SMSSERVICE_ADDRESS=10661700,1066170056& SMSSERVICE_TEXT=HQ,SQKJ%2c||QQNO||&SMSSERVICE_HELPTXT=不用手機上網,通過簡訊就能登陸QQ,累積線上時間真是方便,讓你QQ等級不停增長!%0a當前操作需要通過簡訊操作完成,選擇取定將發送一條簡訊,請根據收到的簡訊通知完成操作!, 關注此QQ好友,好友一上QQ馬上就會有簡訊通知你手機!隨時隨地和TA在QQ上“偶遇”,資費10元/月。%0a當前操作需要通過簡訊操作完成,選擇確定將發送一條簡訊,請根據收到的簡訊通知完成操作。
其中:
SERERCONFIG_NUM表示目前可以使用的伺服器的個數
SERVERCONFIG_TYPE表示伺服器類型:KQQTCP表示TCP伺服器,KQQHTTP表示HTTP伺服器
SERVERCONFIG_URL:伺服器位址
......(不重要)
注意:各值以逗號分隔; 索引值對間使用&符號串連.
至於手機QQ要使用哪個伺服器, 現在還不知道, 反正是其中一個, 過濾試一下就知道了.
2.過濾通訊協定
先開啟Wireshark進行網路封包過濾: 選擇一張活動網卡, 然後start.
應該馬上就可以看到, wireshark已經顯示了很多資料包... 資料太多, 不便查看, 於是過濾顯示一下,
以QQ的第一個tcp伺服器為例: 在Wireshark的Filter Expression裡面輸入過濾運算式, 並點擊Apply應用:
用kEmulator運行手機QQ並登入:
接下來, 如果QQ使用了第一個伺服器的話, 那麼Wireshark將會顯示以下資訊:
沒錯, 你沒有看錯, 協議可以說全部是明文的, 完全就像是HTTP那樣的...
比如VER=1.4代表版本號碼為1.4, CMD=Login表示命令為登入, UIN=***表示QQ...............
3.協議分析
好了, QQ和伺服器的所有通訊都是基於這種HTTP的索引值對方式, 下面列出一些常見的索引值對:
| VER=1.4 |
表示當前使用的協議版本, 不過伺服器返回的版本可能有所不一致 |
| CON=1 |
這個不知道是什麼意思, 通過查看QQ的代碼可見其貌似是固定值1 |
| CMD=*** |
當前的命令, 有Login, Logout, Query_Stat2等等. |
| SEQ=*** |
當前命令的序號, 以此來標識不同的命令序號, 每下一次發送時, 在上一次的基礎上加1 |
| UIN=*** |
當前登入的QQ號, 不變 |
命令的規定:
每個命令以\r\n結束, 這就意味著命令欄位中不能再出現其它的\r\n, 還有,要把\n換成%0D,\r換成%0D
每條命令都使用UTF-8編碼, 同時命令中出現的逗號,&等要轉換url編碼, 不然要誤解釋命令.
1. 登入命令: VER=1.4&CON=1&CMD=Login&SEQ={seq}&UIN={qq}&PS={ps}&M5=1&LG=0&LC={lc}&GD={gd}&CKE=\r\n
伺服器響應:VER=1.1&CMD=Login&SEQ={seq}&UIN=2933278370&RES=0&RS=0&HI=60&LI=300&SG=***&SSG=207390864\r\n
SEQ序號應該和你發送時一樣, 不然就是錯的.
RES=0代表格服務器成功響應
RS=0代表登入成功,其它均為失敗; 若失敗:則有相應的RA欄位標識錯誤資訊, 比如Password Error!
如果有SID或者COMP欄位, 記得儲存起來, 因為後面的某些搞不懂的命令還要用它們. 其它的比如什麼HI和LI就不知道是什麼東西了.
如果出現了VC欄位, 則說明需要驗證碼資訊, 我測試了很久, 一直沒遇到, 暫時不說這個...
2.取得所有QQ好友及其基本資料
命令:VER=1.4&CON=1&CMD=SimpleInfo2&SEQ={seq}&UIN={qq}&SID={sid}&XP={xp}&UN=0&TO=0\r\n
回複:VER=1.1&CMD=SIMPLEINFO2&SEQ={seq}&&UIN={qq}&RES=0&NP=65535&SN=0&UN=&FC=&NK=\r\n
XP是前面根據login命令計算出來的, 具體可以看我後面的代碼.
RES=0同樣代表格服務器正確響應.
NP=65535表示當前返回了所有的好友資訊, 如不是, 需要多次查詢, 你應該沒有那麼多好友吧?
SN表示當前返回的好友基礎資訊的個數, (注:我全沒有寫出來)
UN表示好友QQ號, 以逗號分隔(我沒列出)
FC表示頭像ID
NK表示暱稱, 以逗號分隔
3.取得好友狀態
命令:VER=1.4&CON=1&CMD=Query_Stat2&SEQ={seq}&UIN={qq}&SID=&XP={xp}&CM=2&UN=0\r\n
回複:VER=1.1&CMD=QUERY_STAT2&SEQ={seq}&UIN={qq}&RES=0&FN=1&SN=2&ST=10,30&UN=..\r\n
FN是不是finish的意思? 不知道.
SN返回資訊的個數
ST狀態:10-線上,20-離線,30-離開,40-隱藏
UN:QQ號, 與狀態一一對應
4.發送訊息給好友
命令:VER=1.4&CON=1&CMD=CLTMSG&SEQ={seq}&UIN={qq}&SID={sid]&XP={xp}&UN={qq2}&MG={mg}\r\n
回複:VER=1.1&CMD=CLTMSG&SEQ={seq}&UIN={qq}&RES=0
UN代表好友的QQ
MG表示訊息, 必須是部分url編碼的
5. .............
還有幾條命令, 比如加好友, 移除朋友, 我就不寫了 , 加上有些也沒做測試.
4.類比登入
1. 可以先用GET方式擷取到伺服器IP資訊
GET /newConf/kjava/aubin2.jsp HTTP/1.1
Accept: text/html, application/xhtml+xml,*/*
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/6.0)
Accept-Encoding: utf8
Host: conf.3g.qq.com
Connection: Keep-Alive
[blankline]
2. 然後建立socket並串連到伺服器
3.向伺服器發送命令
4.處理伺服器返回
5...............
5.效果展示
3.完結
文章裡面只是簡要介紹了一些協議方面的東西, 細節處理, 以及完全的命令列表(我也不全知道)也沒有完全列出來,若
需要參考, 還請查看下面的原始碼.
參考文章:
手機QQ協議分析 (一)登陸
HTTP/1.1 Request - w3school
未完結的原始碼: http://pan.baidu.com/s/1c0iYYDa
作者:女孩不哭
時間:2014年4月6日
聯絡:QQ-191035066
地址:http://www.cnblogs.com/memset
分類: Socket/通訊端標籤: 通訊端, socket, 手機QQ, 協議
參考:
協議簡單調研筆記
破解研究總結
Sync協議
道聽途說,加上上面參考中都是提到使用Sync協議。去年項目中做過參考Microsoft Exchange ActiveSync 協議來最佳化訊息協議的方案,雖經過長時間討論定稿,但由於一些原因最終沒有實現;也從中深知Sync並不是表面上那麼簡單、那麼好用。
Sync 有啥問題呢?
1. SyncKey 產生維護成本
SyncKey 在ActiveSync中為字串,用戶端不需要解析,但服務端實現要用數字自增,需要強一致性,且不能回退。
2. 訊息的訂閱模式 採用類似Zookeeper的One time triggler 還是每條訊息都推送一條通知能
One time trigger能夠避免並發通知時,擷取訊息時重複問題,但增加了互動成本,和用戶端實現複雜性。
3. 自己發的訊息,SyncKey怎麼擷取
尤其要支援多端同步發訊息,保證訊息同步;也只好訊息發完在給自己同步一遍(自己裝置發的可以不帶訊息體)
4. 訊息推送延時加重
Sync 訊息體擷取方式:Notify - Ack - get - Mssage, 也就是至少第四個應用程式套件才能返回訊息,在移動網路下成本很高。文中提到訊息通過單獨https請求,那麼延時更為嚴重了(嗯,實測新版本並非如此)。
手機用戶端不再Sync協議
抓包分析版本:Android 6.0, 抓包分析可參考:android 移動網路即時抓包
在wifi、gprs網路狀況下都相同,用戶端會依次嘗試使用80、8080、443 連接埠串連伺服器;訊息發送、接收都使用長串連進行.
協議格式:
4byte Packet Len(包含4位元組本身)
2byte Head Len(包含2位元組本身) + 2byte Version(1) + 4byte Operation + 4byte SeqId + ….
(Packet Len - Head Len) Body
協議互動方式:
- 用戶端請求(一應一答,通過seqid匹配):
seqid = 1 開始,依次遞增,伺服器回複相同的seqid 作為應答
- 伺服器推播通知(單向):
seqid = 0,Operation = 7a, 用戶端不需要應答
主要業務:
-心跳包:
發起用戶端請求,Operation = 0c,長度為16位元組,算是最小的包
-發訊息:
發起用戶端請求,Operation = ed
單點線上時發完訊息後,應答攜帶SyncKey,不再同步,多點線上時,通過通知同步SyncKey,將隨後文章分析。
-收訊息:
1. 伺服器推送訊息, Operation = 7a, Body 中攜帶訊息內容
抓包分析時,通過改變訊息體大小,可能到接收方第一個包length 也會隨之變化,可確認訊息是push的。
2. 發起用戶端單向請求,即訊息的應答Ack
-加密:
未分析,一般來說像whatsapp那樣,使用 hash(密碼/OTP + 長串連第一個請求擷取RandomCode) 做RC4 的密鑰
總結:
現在版本的訊息推送,並非Sync方式,而是推送+ack方式;
從他們協議設計來看,應該最開始用的是Notify + Sync Req + Sync Rsp 方式,因為協議上是不支援伺服器發起請求的;
現在改成 Sync 訊息+ 單向 Ack Req 的push方式,雖然協議上怪異, 相比Sync 訊息接收會更加及時。從以前看到的文章都是說用的Sync協議,應該是是後期版本做了修改,push方式更為高效、而且通過順序的SyncKey也能夠修複丟失的訊息。
下面一個通知包樣本:
4 byte: 265 PacketLen
2 byte: 16 Head Length
2 byte: 1 Protocol Version
4 byte: 7a Operation
4 byte: 0 SeqId 這是一個通知性訊息
4 byte: unknow header
……. Body
Web用戶端
web用戶端使用比較標準的Sync協議,Sync協議也比較適合web長輪詢模型。
移動用戶端模式下,協議是二進位的而且有加密,很難分析;側重手機端,web端主體協議應該保持與移動端一致,可通過web端推測整體協議實現,json也比較好分析。
接收一條訊息後SyncKey變化:
synckey:1_624161340|2_624162225|3_624162051|11_624161867|201_1420112604|1000_1420104656
synckey:1_624161340|2_624162226|3_624162051|11_624161867|201_1420112631|1000_1420104656
可以看出:
- Synckey 有多個,應該是應對不同業務,其中2為為所有個人訊息、討論群組訊息,其他可能是連絡人、朋友圈、訂閱號等,201 為目前時間戳。
- SyncKey 的值為數字自增,不是從0開始,應該有個固定的初始值。
- 發訊息時,發完需要自己給再自己同步回一下SyncKey。
- 下面是一條訊息增量同步處理結構,一堆要同步欄位+是否修改FlagMask,同步協議變得很簡潔。
{"BaseResponse": {"Ret": 0,"ErrMsg": ""},"AddMsgCount": 1,"AddMsgList": [{"MsgId": 1625734358,"FromUserName": "@sssss","ToUserName": "@ssssssss2","MsgType": 1,"Content": "捶地笑……","Status": 3,"ImgStatus": 1,"CreateTime": 1420109883,"VoiceLength": 0,"PlayLength": 0,"FileName": "","FileSize": "","MediaId": "","Url": "","AppMsgType": 0,"StatusNotifyCode": 0,"StatusNotifyUserName": "","RecommendInfo": {"UserName": "","NickName": "","QQNum": 0,"Province": "","City": "","Content": "","Signature": "","Alias": "","Scene": 0,"VerifyFlag": 0,"AttrStatus": 0,"Sex": 0,"Ticket": "","OpCode": 0},"ForwardFlag": 0,"AppInfo": {"AppID": "","Type": 0},"HasProductId": 0,"Ticket": ""}],"ModContactCount": 0,"ModContactList": [],"DelContactCount": 0,"DelContactList": [],"ModChatRoomMemberCount": 0,"ModChatRoomMemberList": [],"Profile": {"BitFlag": 0,"UserName": {"Buff": ""},"NickName": {"Buff": ""},"BindUin": 0,"BindEmail": {"Buff": ""},"BindMobile": {"Buff": ""},"Status": 0,"Sex": 0,"PersonalCard": 0,"Alias": "","HeadImgUpdateFlag": 0,"HeadImgUrl": "","Signature": ""},"ContinueFlag": 0,"SyncKey": {"Count": 6,"List": [{"Key": 1,"Val": 624161340},{"Key": 2,"Val": 624162166},{"Key": 3,"Val": 624162051},{"Key": 11,"Val": 624161867},{"Key": 201,"Val": 1420109883},{"Key": 1000,"Val": 1420104656}]},"SKey": ""}
最初,QQ通訊協定並沒有加密,而是直接採取明文的方式進行傳輸,到了後來才使用了加密傳輸,密碼編譯演算法一直沒有變過,使用的是blowfish演算法,但是密鑰的交換協議變得比較頻繁。其實TX也是被逼的,現在的互連網使用者比前幾年更加註重隱私安全,這麼大使用者量的通訊軟體,如果使用者與對方之間的聊天資訊可以輕易的被第三方破譯擷取,那麼使用者量肯定會離開她,而去選擇那些能夠更加保護好個人隱私的人通訊軟體。因此,隨著時間的推移和技術的發展,以前設計的協議可能會被研發者發現一些弱點,“圖謀不軌”者加以利用,會對TX造成一些潛在的風險,他不得不對協議進行修改(QQ2011正式版中的金鑰交換中對密碼的MD5計算就加入了salt的概念,這個salt就是對應的QQ號碼,後面會有詳細的描敘)。
QQ協議首選的傳輸層是UDP,如果UDP不可登陸,那麼會再嘗試使用TCP進行傳輸。UDP使用的連接埠是8000,TCP使用的連接埠是443,應用協議基本一樣,只是在通過TCP進行傳輸時,前兩個位元組為協議內容的長度(包括2個位元組)。
QQ協議中每個通訊內容都帶有一個協議頭部,如:
其中標識1一個位元組,版本號碼、命令字和序號都是2個位元組,QQ號碼有4個位元組,接下來是資料部分(已加密),最後是一個尾部標識1個位元組。
在進行協議還原的時候,最關心的就是協議頭部的命令字,需要根據不同的命令字,來進行相應的處理,最終擷取密鑰解密聊天內容。
QQ登陸協議金鑰交換過程,首先我們使用Wireshark抓報文分析,觀察主要用到的命令字(見上一篇Header部分的介紹)。
QQ2011登陸過程分析
| 命令字 |
含義 |
| 1、Touch Information(0×0091) |
根伺服器SAY HELLO,如果對該報文做一些小動作,可以讓QQ認為,TX的伺服器或網路不能訪問… |
| 2、Login Request(0x00ba) |
未知,可以不進行處理。 |
| 3、Login Verify(0x00dd) |
向伺服器發送登陸請求,需要使用密碼進行運算作為密鑰才能機密該報文,解密的報文中包含對第4步的解密密鑰。 |
| 4、Login get Information(0x00e5) |
未知,但是伺服器返回的報文你必須得知道,因為這個報文中包含解密工作階段金鑰報文(第6步)的密鑰。 |
| 5、Login verify E3(0x00e3) |
未知,可以不進行處理。 |
| 6、Login send Information(0×0030) |
用戶端向伺服器發送sessionKey,使用第4步擷取的密鑰進行解密。 |
1、Touch Information(0×0091)
這個報文無需關心,是用戶端向伺服器在SAY HELLO…
2、Login Request(0x00ba)
未知,在此處並不重要。
3、Login Verify(0x00dd)
非常重要!!擷取工作階段金鑰首先得解密該報文。但是要解密該報文,必須得知道該登陸QQ使用者的密碼,而使用者密碼只有使用者和TX知道,第三方是不知道的(也有可能存在“不可思議”的第三方…)。資料轉送過程中使用的密碼編譯演算法是blowfish,這個演算法目前從公開的資料上來說,還沒有發現漏洞。因此,要即時擷取使用者的聊天資訊,除非已經知道密碼了,或者已經暴力破解了密碼(這裡簡單介紹一下怎麼進行暴力破解,這裡的暴力破解,當然不是類比一個QQ用戶端不停的向TX伺服器發送登陸請求,這樣太慢了,而且TX那邊也會有記錄。首先,得分析出這個報文的密鑰產生演算法[不是簡單的直接使用密碼作為密鑰],密碼編譯演算法(這個已知,是blowfish),第二,需要將對方的登陸報文截取儲存到檔案,然後寫一個程式,不停拼接字串、數字、標點符號進行組合,根據第一步分析它密鑰的產生方法產生出密鑰,然後作為blowfish演算法的密鑰,去解密報文,如果解密成功,恭喜你,你暴力破解到了一個QQ密碼。但是這種機率比較小,即使有一些,這些號碼的價值不大,扯遠了…)。
LoginVerify報文的解密密鑰產生方法,在QQ2011版本之前,是MD5(MD5(PWD)),對QQ的密碼做了兩次MD5運算。但是QQ2011版本(包括2011版本)之後,這個演算法做了一點修改,就是:MD5(MD5(PWD+QQ_NUM)),這個修改其實是非常有必要的,為什麼呢?因為隨著硬體技術的發展,以及前些年MD5彩虹表的推出,簡單密碼的MD5值非常容易就能從彩虹表中找出對應MD5值,從而得到原始字串密碼,即使TX做了兩次的MD5運算。在彩虹表的推出或以前(因為我也不知道是在這以前還是以後,呵呵),在執行MD5運算時,就有了加SALT的說法,很形象!加鹽,在這裡,QQ_NUM就是鹽,這樣就加大了使用彩虹表破解的難度。
使用密碼根據以上的演算法得出解密密鑰,解密Login Verify報文後,會得到一個新的密鑰,這個密鑰暫且就叫做verify_key。
Login Verify Reply(0x00dd)
伺服器對用戶端Login Verify報文的響應,這個報文需要verify_key作為密鑰進行解密,得出一個新的密鑰-verify_reply_key。
4、Login get information(0x00e5)
用戶端接收到伺服器的Login Verify Reply報文後,會使用verify_reply_key加密資料發送到伺服器,而這裡面又包含了一個key – get_info_key。
5、Login verify E3(0x00e3)
未知,此處可以不進行處理。
6、Login send Information(0×0030)
使用get_info_key解密該報文,得到會話KEY – session key。
回想一下:密碼是關鍵,有了密碼才能解密Login Verify(0x00dd)報文,解密了Login Verify(0x00dd),才能解密後續的的報文。其步驟是:passwd -> verify_key -> verify_reply_key -> get_info_key -> session_key。
前面兩篇簡單的介紹了QQ登陸協議金鑰交換過程以及所使用的密碼編譯演算法,知道了這兩點,就可以對它的協議進行還原了。
QQDecrypt,通過winpcap抓包,即時對QQ聊天協議進行還原。
除了聊天協議之外,我們還可以對QQ相關的協議進行還原,包括但不限於:
1、QQ檔案傳輸
2、QQ音頻傳輸
3、QQ視頻傳輸
4、QQ密碼驗證程式
5、QQ密碼擷取,是的,你沒有看錯,有一種主動的方法(使用者登入時)就可以獲得QQ的密碼。在網路出口擷取,而不是在用戶端進行HOOK的方式擷取。
協議分析TMP