摘要:關于本教程有任何建議或者疑問,都歡迎郵件與我聯系,或者在上提出教程流程簡介教程將會從如何分析微信協議開始,第一部分將教你如何從零開始獲取并模擬擴展個人微信號所需要的協議。
現在的日常生活已經離不開微信,難免會生出微信有沒有什么API可以使用的想法。
那樣就可以拿自己微信做個消息聚合、開個投票什么的,可以顯然沒有這種東西。
不過還好,有網頁版微信不就等于有了API么,這個項目就是出于這個想法出現的。
目標看完這一系列教程,你就能從頭開始實現自己關于微信以及類似工具的想法,例如一個完善的微信機器人。
當然,如果你只對使用微信的API感興趣,可以直接跳到下一篇教程,直接使用我已經完成的API。
本文為該教程的第一部分,主要講述抓包與偽造,將會以最簡單的方法介紹使用Python模擬登陸抓取數據等內容。
Python與基本的網絡基礎都不困難,所以即使沒有這方面基礎輔助搜索引擎也完全可以學習本教程。
關于本教程有任何建議或者疑問,都歡迎郵件與我聯系,或者在github上提出(i7meavnktqegm1b@qq.com)
教程流程簡介教程將會從如何分析微信協議開始,第一部分將教你如何從零開始獲取并模擬擴展個人微信號所需要的協議。
第二部分將會就這些協議進行利用,以微信機器人為例介紹我給出的項目基本框架與存儲、任務識別等功能。
第三部分就項目基本框架開發插件,以消息聚合等功能為例對框架做進一步介紹與擴展。
簡單成果展示:目前的樣例微信號被擴展為了能夠完成信息上傳下載的機器人,用于展示信息交互功能。
其支持文件、圖片、語音的上傳下載,可以掃碼嘗試使用。
本部分所需環境本文是這一教程的第一部分,需要配置抓包與Python環境。
本教程使用的環境如下:
Windows 8.1
Python 2.7.11 (安裝Image, requests)
Wireshark 2.0.2
微信版本6.3.15
Wireshark配置Wireshark是常見的抓包軟件,這里通過一些配置抓取微信網頁端的流量。
由于微信網頁端使用https,需要特殊的配置才能看到有意義的內容,具體的配置見這里。
配置完成以后開始抓包,載入https://www.baidu.com后若能看到http請求則配置成功。
分析并模擬掃碼,并獲取登錄狀態微信網頁端登陸分為很多步,這里以第一步掃碼為例講解如何從抓包開始完成模擬。
分析過程在抓包以前,我們需要先想清楚這是一個什么樣的過程。
我們都登錄過網頁端微信,沒有的話可以現在做一個嘗試:微信網頁端。
這個過程簡單而言可以分為如下幾步:
向服務器提供一些用于獲取二維碼的數據
服務器返回二維碼
向服務器詢問二維碼掃描狀態
服務器返回掃描狀態
有了這些概念以后就可以開始將這四步和包對應起來。
對應過程與實際的包開啟wireshark抓包后登陸網頁端微信,完成掃碼登陸,然后關閉wireshark抓包。
篩選http請求(就是菜單欄下面輸入的那個http),可以看到這樣的界面。
這里需要講的就是第一列“No.”列的數字就是后文說的幾號包,例如第一行就是30號包。數據包的類型則在Info列中可以看到,是GET,POST或是別的請求。
那么我們可以開始分析抓到的包了,我們先粗略的瀏覽一下數據包。
第325號包引起了我的注意,因為登陸過程當中非常有特征的一個過程是二維碼的獲取,所以我們嘗試打開這一數據包的圖片的內容。
325號包是由292號包的請求獲取的,292號包又是一個普通的get請求,所以我們嘗試直接在瀏覽器中訪問這一網址。(訪問自己抓到的網址)
具體的網址通過雙擊打開292號包即可找到。如需要可以點擊這里看圖。
我們發現直接在瀏覽器中獲取了一張二維碼,所以這很有可能就是上述一、二步的過程了。
那么我們是向服務器提供了哪些數據獲取了二維碼呢?
每次我們登錄的二維碼會變化,且沒有隨二維碼傳回的標識,所以我們肯定提供了每次不同的信息
網址中最后一部分看起來比較像標識:https://login.weixin.qq.com/qrcode/4ZtmDT6OPg==
為了進一步驗證猜想,再次抓包,發現類似292號包的請求url僅最后一部分存在區別
所以我們提供了4ZtmDT6Opg==獲取到了這一二維碼。
那么這一標識是隨機生成的還是服務器獲取的呢?
從最近的包開始分析服務器傳回的數據(Source是服務器地址的數據),發現就在上一行,286號包有我們感興趣的數據。
打開這個包,可以看到其返回的數據為window.QRLogin.code = 200; window.QRLogin.uuid = "4ZtmDT6OPg==";(見下方截圖)
顯然導致服務器返回這一請求的284號包就是我們獲取標識(下稱uuid)所需要偽造的包。
那么284號包需要傳遞給服務器哪些數據?
這是一個get請求,所以我們分析其請求的url:https://login.weixin.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=en_US&_=1453725386008。
可以發現需要給出五個量appid, redirect_uri, fun, lang, _。
其中除了appid其余都顯然是固定的量(_的格式顯然為時間戳)。
然而搜索284號包之前的包也沒有發現這一數值的來源,所以暫且認為其也是固定的量,模擬時如果出現問題再做嘗試。
到了這里,1,2步的過程我們已經能夠對應上相應的包了。
3,4部的最顯著特征是在掃描成功以后會獲取掃描用的微信號的頭像。
我們還是首先大致的瀏覽一下服務器返回的數據包,試圖找到包含圖片的數據包。
從325號包(微信頭像肯定在二維碼之后獲取)開始瀏覽。
我們發現338號包中包含一個base64加密的圖片,解壓后可以看到自己的頭像。
所以這個數據包就是服務器返回的掃描成功的數據包了,而前面那部分window.code=201顯然就是表示狀態的代碼。(見下方截圖)
經過嘗試與再次抓包,我們理解狀態碼的涵義:200:登陸成功 201:掃描成功 408:圖片過期
那么第四部我們已經能夠完全的理解
我們很容易的找到了在登錄過程當中不斷出現的請求,那么要怎么模擬呢?
首先這是一個簡單的get請求,url為:https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=4ZtmDT6OPg==&tip=1&r=-2026440414&_=1453725386009
可以發現需要給出五個量loginicon, uuid, tip, r, _
通過多次抓包發現除了r以外都可以找到簡單的規律,那么r的規律等待模擬時再嘗試處理
至此你應該已經能將四個過程全部與具體的數據包對應。為了避免有遺漏的過程,我們將沒有使用到的與服務器交互的數據包標識出來(右鍵Mark)。經過簡單的瀏覽,認為其中并沒有必須的數據包交互。但值得注意的是,如果之后模擬數據包沒有問題卻無法登陸的話應當再回到這些數據包中搜尋。
這里做一個簡單的小結,這一部分簡單的介紹了分析數據包的基本思路,以及一些小的技巧。當然這些僅供參考,在具體的抓包中完全可以根據具體的交互過程自由發揮。而目前留下來的問題有:第一步時的appid與第三步時的r,留待模擬時在做研究。
使用Python模擬掃碼這一部分我們使用python的requests模塊,可以通過pip install requests安裝。
我們先來簡單的講述一下這個包。
import requests # 新建一個session對象(就像開了一個瀏覽器一樣) session = requests.Session() # 使用get方法獲取https://www.baidu.com/s?wd=python url = "https://www.baidu.com/s" params = { "wd": "python", } r = session.get(url = url, params = params) with open("baidu.htm") as f: f.write(r.content) # 存入文件,可以使用瀏覽器嘗試打開 # 舉例使用post方法 import json url = "https://www.baidu.com" data = { "wd": "python", } r = session.get(url = url, data = json.dumps(data)) with open("baidu.htm") as f: f.write(r.content) # 以上代碼與下面的代碼不連續
如果想要更多的了解這個包,可以瀏覽requests快速入門。
你可以嘗試獲取一個你熟悉的網站來測試使用requests,在測試時可以打開抓包,查看你發送的數據包與想要發送的數據包是否一樣。
那么我們開始模擬第一、二個過程,向服務器提供一些用于獲取二維碼的數據,服務器返回二維碼。
向服務器提交284,292號包
從服務器返回數據中提取出uuid與二維碼圖片
284號包
我們需要模擬的地址為:https://login.weixin.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=en_US&_=1453725386008 ,所以我們模擬的代碼如下:
#coding=utf8 import time, requests session = requests.Session() url = "https://login.weixin.qq.com/jslogin" params = { "appid": "wx782c26e4c19acffb", "redirect_uri": "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage", "fun": "new", "lang": "en_US", "_": int(time.time()), } r = session.get(url, params = params) print("Content: %s"%r.text)
當然,將模擬的地址全部寫在url里面效果完全一樣。
值得一提的是requests會幫我們自動urlencode,如果不需要urlencode(/變為了%2F)可以將所有內容都寫在url里面。
提取出uuid
這里使用re,如果不了解正則表達式的話可以直接拿來用,畢竟和這一個教程并不相關。
# 上接上一段程序 import re regx = r"window.QRLogin.code = (d+); window.QRLogin.uuid = "(S+?)";" # 我們可以看到返回的量是上述的格式,括號內的內容被提取了出來 data = re.search(regx, r.text) if data and data.group(1) == "200": uuid = data.group(2) print("uuid: %s"%uuid)
如果沒能成功獲取到uuid可以嘗試再運行一次。
292號包
我們需要模擬的url為:https://login.weixin.qq.com/qrcode/4ZtmDT6OPg== ,所以我們模擬的代碼如下:
# 上接上一段程序 url = "https://login.weixin.qq.com/qrcode/" + uuid r = session.get(url, stream = True) with open("QRCode.jpg", "wb") as f: f.write(r.content) # 現在你可以在你存儲代碼的位置發現一張存下來的圖片,用下面的代碼打開它 import platform, os, subprocess if platform.system() == "Darwin": subprocess.call(["open", "QRCode.jpg"]) elif platform.system() == "Linux": subprocess.call(["xdg-open", "QRCode.jpg"]) else: os.startfile("QR.jpg")
由于我們需要獲取圖像,所以需要以二進制數據流的形式獲取服務器返回的數據包,所以增加stream = True。
而將二進制數據流寫入也需要在打開文件時設定二進制寫入,即open("QRCode.jpg", "wb")。
當然,如果獲取失敗可以再運行一次。
同理的三、四步也可以按照這個方法寫出,這里就不再贅述,只給出代碼。
而經過測試我們發現,第一步時的appid實際是一個固定的量,第三步時的r甚至不輸入也可以登錄。
# 上接上一段代碼 import time while 1: url = "https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login" # 這里演示一下不使用自帶的urlencode params = "tip=1&uuid=%s&_=%s"%(uuid, int(time.time())) r = session.get(url, params = params) regx = r"window.code=(d+)" data = re.search(regx, r.text) if not data: continue if data.group(1) == "200": # 下面一段是為了之后獲取登錄信息做準備 uriRegex = r"window.redirect_uri="(S+)";" redirectUri = re.search(uriRegex, r.text).group(1) r = session.get(redirectUri, allow_redirects=False) redirectUri = redirectUri[:redirectUri.rfind("/")] baseRequestText = r.text break elif data.group(1) == "201": print("You have scanned the QRCode") time.sleep(1) elif data.group(1) == "408": raise Exception("QRCode should be renewed") print("Login successfully")
當你看到Login successfully時,說明至此我們已經成功從零開始,通過抓包分析,用python成功模擬了python登陸。
不過是不是看上去沒有什么反饋呢?那是因為我們還沒有模擬會產生反饋的包,但其實差的只是研究發文字、發圖片什么的包了。
為了體現我們已經登陸了,加上后面這段代碼就可以看到登陸的賬號信息:
# 上接上一段代碼 import xml.dom.minidom def get_login_info(s): baseRequest = {} for node in xml.dom.minidom.parseString(s).documentElement.childNodes: if node.nodeName == "skey": baseRequest["Skey"] = node.childNodes[0].data.encode("utf8") elif node.nodeName == "wxsid": baseRequest["Sid"] = node.childNodes[0].data.encode("utf8") elif node.nodeName == "wxuin": baseRequest["Uin"] = node.childNodes[0].data.encode("utf8") elif node.nodeName == "pass_ticket": baseRequest["DeviceID"] = node.childNodes[0].data.encode("utf8") return baseRequest baseRequest = get_login_info(baseRequestText) url = "%s/webwxinit?r=%s" % (redirectUri, int(time.time())) data = { "BaseRequest": baseRequest, } headers = { "ContentType": "application/json; charset=UTF-8" } r = session.post(url, data = json.dumps(data), headers = headers) dic = json.loads(r.content.decode("utf-8", "replace")) print("Log in as %s"%dic["User"]["NickName"])
這里做一個簡單的小結:
模擬數據包總體而言是以尋找未知的必須數據為線索,輔助一些技巧,串聯起整個過程。
首先需要用python初始化一個session,否則登錄過程的存儲將會比較麻煩。
模擬數據包的時候首先區分get與post請求,對應session的get與post方法。
get的數據為url后半部分的內容,post是數據包最后一部分的內容。
get方法中傳入數據的標示為params, post方法中傳入數據的標示為data。
session的get,post方法返回一個量,可以通過r.text自動編碼顯示。
存儲圖片有特殊的方式與配置。
小結到現在為止我展示了一個完整的抓包、分析、模擬的過程完成了模擬登陸,其他一些事情其實也都是類似的過程,想清楚每一步要做些什么即可。
這里用到的軟件都只介紹了最簡單的一些方法,進一步的內容這里給出一些建議:
wireshark可以直接瀏覽官方文檔,有空可以做一個了解。
requests包的使用通過搜索引擎即可,特殊的功能建議直接閱讀源碼。
那么做一個小練習好了,測試一下學到的東西:讀取命令行的輸入并發送給自己。(這部分的源碼放在了文末)
在分析包的過程中記得抓好位置的必要數據這個線索,練習之前提到過的一些技巧。
把大的過程拆分成一個一個小的任務可能會讓分析簡單很多。
如果發現登錄過程意料之外的斷了,分析不出原因,可以嘗試多抓幾次包再比較分析。
具體運用時可能遇到的難點 命令行登錄一段時間后無法與服務器正常交互這是因為微信網頁端存在心跳機制,一段時間不交互將會斷開連接。
另外,每次獲取數據時(webwxsync)記得更新SyncKey。
某個特定請求不知道如何模擬在項目中已經模擬好了幾乎所有的請求,你可以通過參考我的方法與數據包。
如果之后微信網頁版出現更新我會在本項目中及時更新。
項目中的微信網頁端接口見這里
無法上傳中文文件名的文件與圖片這是因為使用requests包會自動將中文文件名編碼為服務器端無法識別的格式,所以需要修改requests包或者使用別的方法上傳文件。
最簡單的方法即將requests包的packages/urlib3中的fields.py中的format_header_param方法改為如下內容:
def format_header_param(name, value): if not any(ch in value for ch in "" "): result = "%s="%s"" % (name, value) try: result.encode("ascii") except UnicodeEncodeError: pass else: return result if not six.PY3: # Python 2: value = value.encode("utf-8") value = email.utils.encode_rfc2231(value, "utf-8") value = "%s="%s"" % (name, value.decode("utf8")) return value登錄時出現不安全的提示
建議更新Python版本至2.7.11
小練習答案源碼可在該地址下載:這里
結束語希望讀完這篇文章能對你有幫助,有什么不足之處萬望指正(鞠躬)。
有什么想法或者想要關注我的更新,歡迎來Github上Star或者Fork。
160426
LittleCoder
EOF
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/37974.html
摘要:本文為教程的第二部分,主要以微信控制器群發助手好友刪除檢測為例演示如何調用微信。教程流程簡介這一系列教程從如何分析微信協議開始,第一部分教你如何從零開始獲取并模擬擴展個人微信號所需要的協議。 現在的日常生活已經離不開微信,本文將會拋磚引玉演示如何使用Python調用微信API做一些有意思的東西。 看完這一系列教程,你就能從頭開始實現自己關于微信的想法。 本文為教程的第二部分,主要以微信...
摘要:配置配置使用概率抽樣。采樣率定義了對跟蹤跨度進行采樣的概率,其值可以介于和含之間。例如,以下配置對象將采樣率更改為即每個跨度都被采樣,并使用協議將跟蹤發送到位于的服務器文件路徑注將采樣率更改為會完全禁用跟蹤。目錄手把手教你學Dapr - 1. .Net開發者的大時代手把手教你學Dapr - 2. 必須知道的概念手把手教你學Dapr - 3. 使用Dapr運行第一個.Net程序手把手教你學Da...
??蘇州程序大白一文從基礎手把手教你Python數據可視化大佬??《??記得收藏??》 目錄 ????開講啦!!!!????蘇州程序大白?????博主介紹前言數據關系可視化散點圖 Scatter plots折線圖強調連續性 Emphasizing continuity with line plots同時顯示多了圖表 數據種類的可視化 Plotting with categorical da...
摘要:按著我的步驟一步一步操作,你就可以成功的到這個微信支付技能包。原文鏈接手把手教你實現小程序微信支付由于自己本身就是開發的,所以只涉及到微信支付的開發。我將會一步一步的記錄如何實現微信支付的。第一步先上微信支付開發文檔境內普通商戶里面下載與。 這是我自己研究了兩天的微信支付整理得的開發筆記,然后在這里分享給大家,讓大家快速上手微信支付。 按著我的步驟一步一步操作,你就可以成功的get到這...
摘要:如何在低成本有限的時間里策劃一場合格的裂變活動呢常做裂變的朋友可能回到個詞裂變系數投入與產出比。存在成本的裂變活動嗎答案存在。在這條新規則宣布后,裂變分享率增加到了。優點進一步驗證用戶的朋友圈,防止渾水摸魚。 ...
閱讀 2771·2021-09-24 10:34
閱讀 1874·2021-09-22 10:02
閱讀 2262·2021-09-09 09:33
閱讀 1465·2021-08-13 15:02
閱讀 3276·2020-12-03 17:10
閱讀 1191·2019-08-30 15:44
閱讀 2152·2019-08-30 12:58
閱讀 3236·2019-08-26 13:40