摘要:本文不涉及到的知識(shí)如果你是沖著來(lái)的那么可能會(huì)讓你失望了前一陣子一個(gè)朋友找我問我能不能搞一個(gè)微信自動(dòng)加好友的軟件在普通人眼里程序員就是專門寫木馬病毒外掛軟件的三流黑客不會(huì)寫那就連三流都不是所以為了證明我是三流黑客我隨便百度了兩個(gè)現(xiàn)成的給他本來(lái)
本文不涉及到 AI 的知識(shí),如果你是沖著 AI 來(lái)的,那么可能會(huì)讓你失望了.
前一陣子一個(gè)朋友找我,問我能不能搞一個(gè)微信自動(dòng)加好友的軟件,(在普通人眼里,程序員就是專門寫木馬病毒外掛軟件的三流黑客.不會(huì)寫那就連三流都不是.
所以為了證明我是三流黑客,我隨便百度了兩個(gè)現(xiàn)成的給他.本來(lái)事情到這里應(yīng)該結(jié)束了的,不過(guò)本著探索的精神,想順便了解一下這種外掛的原理,于是百歌谷度了一下,
最終原理沒找到,倒是找到幾個(gè)有意思的 github 倉(cāng)庫(kù),利用網(wǎng)頁(yè)版的微信 API 做第三方微信.
先看個(gè)效果?
我們看看大致步驟
獲取 UUID
根據(jù) UUID 獲取二維碼
掃碼登陸, 獲取登陸信息
拿登陸信息換初始化數(shù)據(jù)
拿數(shù)據(jù)初始化
獲取好友列表和消息列表
發(fā)送消息
以下為具體過(guò)程,不感興趣的可以直接拉到末尾查看源碼倉(cāng)庫(kù)
需要注意的是,每一步的請(qǐng)求所使用的方法(POST/GET) 和 Content-Type 都是不一樣的,下面我都有標(biāo)注,如果有請(qǐng)求不通的請(qǐng)參考 gtihub 源碼.一、獲取 UUID
接口地址 https://wx.qq.com/jslogin
請(qǐng)求方法 POST
參數(shù)類型(content-type) application/x-www-form-urlencoded
參數(shù)
{ appid: "wx782c26e4c19acffb", fun: "new", lang: "zh_CN", _: new Date().valueOf() }
除了最后一個(gè)當(dāng)前時(shí)間戳不是固定的,其他的3個(gè)參數(shù)都是寫死的,照抄即可,調(diào)用成功的話,會(huì)到一個(gè)字符串 window.QRLogin.code = 200; window.QRLogin.uuid = "obizONtqZA==";, 需要自己想辦法截取到 window.QRLogin.uuid = 后面的那串字符,即 UUID.
二、獲取二維碼這一步很簡(jiǎn)單,有了 UUID 后,我們可以直接請(qǐng)求 "https://wx.qq.com/qrcode/" + UUID 獲取到二維碼. 獲取到二維碼以后,先別急著去掃描二維碼,因?yàn)槲覀円热ケO(jiān)聽二維碼的掃描狀態(tài),這樣我們才能知道什么時(shí)候被登陸.
請(qǐng)求方式 GET 無(wú)需參數(shù)
三、監(jiān)聽二維碼的掃描結(jié)果接口地址 https://wx.qq.com/cgi-bin/mmw...
請(qǐng)求方法 GET
參數(shù)類型(content-type) application/x-www-form-urlencoded
參數(shù)
{ tip: 0, uuid: "obizONtqZA==", _: new Date().valueOf(), loginicon: true }
tip 取值 0 或 1, 監(jiān)聽分2個(gè)階段,第一階段,監(jiān)聽用戶是否掃碼,tip 為 0,第二階段,監(jiān)聽用戶是否在微信上點(diǎn)確認(rèn)登陸,tip 為 1.
uuid 就是第一步獲取到的那個(gè) UUID
_ 當(dāng)前時(shí)間戳
loginicon 我猜應(yīng)該是否掃碼完返回用戶頭像,都填 true 即可.
返回結(jié)果,當(dāng)你掃描二維碼的時(shí)候,接口會(huì)返回你一個(gè)這樣的對(duì)象
{ "window.code": 201, "window.userAvatar": 頭像的 base64 地址 }
得到的 code 是 201, 說(shuō)明已掃碼,但并不代表已登陸,還需要繼續(xù)監(jiān)聽是否在手機(jī)微信上點(diǎn)擊 確認(rèn)登陸 按鈕(重復(fù)上面步驟,把 參數(shù)里的 tip 改為 1 即可)
這步如果成功的話,會(huì)返回一個(gè)如下對(duì)象
{ "window.code": "200", "window.redirect_uri": "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=ARD37_ikx-Kakd2i0W-f-E7q@qrticket_0&uuid=4f6yOkV4AA==&lang=zh_CN&scan=1548300672" } }四、獲取初始化數(shù)據(jù)(敏感數(shù)據(jù))
上一步獲取到的數(shù)據(jù)里面的 window.redirect_uri 里包含了一個(gè) url 和一些 查詢參數(shù),直接請(qǐng)求這個(gè)地址好像沒辦法成功,需要將 url 和 參數(shù)拆分,然后加入其他參數(shù)
接口地址 就是上面的 url
請(qǐng)求方法 GET
參數(shù)類型(content-type) application/x-www-form-urlencoded
參數(shù)
{ ticket: 上面得到的 ticket, uuid: 上面得到的 uuid, lang: "zh_CN", // 固定 scan: 上面得到的 scan, fun: "new" // 固定 }
這一步的返回的頭部里面,會(huì)有個(gè) cookie ,需要存起來(lái),接來(lái)來(lái)得到請(qǐng)求頭里面要帶上這個(gè) cookie,另外就是一個(gè) xml 格式的 敏感的信息,也是要存起來(lái).
tip: xml 格式可以用 xml2js 轉(zhuǎn)換成 json.五、初始化
呼,到這一步,終于接近登陸成功了,只需再調(diào)用以下接口,初始化以下
接口地址 https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=${~(new Date().valueOf())}
請(qǐng)求方法 POST
參數(shù)類型(content-type) application/json
參數(shù)
{ BaseRequest: { DeviceID: "e747337466044216", // 這個(gè)好像隨便填都可以 Sid: 上一步獲取到的 wxsid, Uin: 上一步獲取到的 wxuin, Skey: 上一步獲取到的 skey } }
這里有 2 個(gè)地方跟之前不同的,第一是地址后面要跟一個(gè)時(shí)間戳,而且這個(gè)時(shí)間戳還要按位取反,第二個(gè)是請(qǐng)求參數(shù)是放在 BaseRequest 下面,而不是對(duì)象的一級(jí)屬性下面.
返回的數(shù)據(jù)里面有 2 個(gè)數(shù)據(jù)需要保存起來(lái),一個(gè)是 data.SyncKey, 一個(gè)是 res.data.User.UserName,后面都會(huì)用到
到此才真正完成登陸,下面如果你不需要好友列表的話,可以直接收取消息了
六、檢測(cè)新消息接口地址 https://webpush.wx.qq.com/cgi...
請(qǐng)求方法 GET
參數(shù)類型(content-type) application/json
參數(shù)
let time = new Date().getTime() let synckey = "" let sk = data.SyncKey.List || [] // data.SyncKey 就是上一步獲取到的那個(gè) for (let i = 0; i < sk.length; i++) { synckey += `${sk[i].Key}_${sk[i].Val}` if (i !== sk.length - 1) synckey += "|" } // 傳遞的參數(shù) { r: time, sid: 第四步拿到的 wxsid, uin: 第四步拿到的 wxuin, skey: 第四步拿到的 skey, deviceid: "e747337466044216", // 同上一步 synckey: synckey, _: time }
返回內(nèi)容的 data 里面 包含如下內(nèi)容
window.synccheck={retcode:"0",selector:"2"}
如果 selector 是 2, 說(shuō)明有新消息,走下一步,獲取消息內(nèi)容
七、獲取消息內(nèi)容接口地址 https://wx.qq.com/cgi-bin/mmw...
請(qǐng)求方法 POST
參數(shù)類型(content-type) application/json
參數(shù)
{ BaseRequest: { Uin: 第四步拿到的 wxuin, Sid: 第四步拿到的 wxsid, Skey: 第四步拿到的 skey, DeviceID: "e747337466044216", // 同上一步 }, SyncKey: data.SyncKey, // 還記得上一步我們費(fèi)盡千辛萬(wàn)苦轉(zhuǎn)換這個(gè)數(shù)據(jù)嗎? 你沒看錯(cuò),這里不需要轉(zhuǎn)換,就是這么神奇 rr: ~(new Date().valueOf()) }
返回結(jié)果里面有個(gè) data.AddMsgList 就是消息列表了,還有個(gè) data.SyncCheckKey 就是下次請(qǐng)求的時(shí)候用的 SyncKey, 每次都會(huì)變的.
AddMsgList 是一個(gè)數(shù)組,里面可能包含多條消息,消息的自動(dòng)比較多,就不一一說(shuō)明了,這里說(shuō)說(shuō) 2 個(gè)比較重要的字段,其他的字段有興趣的可以自己打印出來(lái)看一下.
FromUserName 對(duì)方的微信名,說(shuō)是微信名,其實(shí)是一個(gè) @ 或 @@ 開頭的內(nèi)部的id, 完全不可讀,據(jù)我猜測(cè) @ 開頭的應(yīng)該是普通好友, @@ 開頭的是群或者公眾號(hào)之類的
Content 消息內(nèi)容
有了消息內(nèi)容,和發(fā)消息的人,我們就可以回復(fù)對(duì)方,不過(guò)回復(fù)什么? 當(dāng)然不可能寫一大堆 if else 或者 switch case 去適應(yīng)各種情況,不妨網(wǎng)上搜索一下 價(jià)值一個(gè)億的ai代碼 哈哈哈
八、獲取自動(dòng)回復(fù)內(nèi)容這邊我用的是圖靈機(jī)器人的 API 地址,當(dāng)然你也可以用其他的.
接口地址 http://openapi.tuling123.com/...
請(qǐng)求方法 POST
參數(shù)類型(content-type) application/json
參數(shù)
{
perception: { inputText: { text: "待回復(fù)的消息" } }, userInfo: { apiKey: tulingApiKey, // 在圖靈官網(wǎng)申請(qǐng) userId: tulingUserId // 同上
}
你要是懶得去申請(qǐng)的話,可以在我的項(xiàng)目里面復(fù)制, 在 src/global.js 里面,在返回的內(nèi)容里面 data.results[0].values.text 下面可以看到圖靈給你生成的自動(dòng)回復(fù)內(nèi)容(results是一個(gè)數(shù)組,支持一次回復(fù)多條)
九、回復(fù)消息拿到自動(dòng)回復(fù)以后,我們只需要把它發(fā)給你的好友,即完成一次自動(dòng)對(duì)話.
接口地址 https://wx.qq.com/cgi-bin/mmw...
請(qǐng)求方法 POST
參數(shù)類型(content-type) application/json
參數(shù)
let timeStamp = new Date().getTime() + "" + (9000 * Math.random() + 1000) { BaseRequest: { Uin: 同上, Sid: 同上, Skey: 同上, DeviceID: 同上 }, Msg: { Type: 1, // 消息類型 1 是文字消息,其他的暫時(shí)沒用過(guò) Content: "回復(fù)的內(nèi)容", FromUserName: "你的用戶名,在第五步有拿到", ToUserName: "對(duì)方的微信名 第七步的 FromUserName", LocalID: timeStamp, ClientMsgId: timeStamp }
發(fā)送成功的話,會(huì)返回如下內(nèi)容
{ BaseResponse: { Ret: 0, ErrMsg: "" }, MsgID: "2033517278669301361", LocalID: "" }
好了,這樣我們的一個(gè)自動(dòng)回復(fù)機(jī)器人就完成了.完整的代碼在這里
廣告時(shí)間我們40人的前端團(tuán)隊(duì)常年招兵買馬中,在廈門的和想來(lái)廈門的童鞋們,不要吝惜你的簡(jiǎn)歷,使勁砸過(guò)來(lái) 郵箱:atob("bnVveWFAZ2FvZGluZy5jb20="), 期待你一起來(lái)稿事
對(duì)本文有意見或者建議,請(qǐng)盡量在 github 上提 issue, 最近比較忙,比較不怎么逛社區(qū)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/101410.html
摘要:本文不涉及到的知識(shí)如果你是沖著來(lái)的那么可能會(huì)讓你失望了前一陣子一個(gè)朋友找我問我能不能搞一個(gè)微信自動(dòng)加好友的軟件在普通人眼里程序員就是專門寫木馬病毒外掛軟件的三流黑客不會(huì)寫那就連三流都不是所以為了證明我是三流黑客我隨便百度了兩個(gè)現(xiàn)成的給他本來(lái) 本文不涉及到 AI 的知識(shí),如果你是沖著 AI 來(lái)的,那么可能會(huì)讓你失望了. 前一陣子一個(gè)朋友找我,問我能不能搞一個(gè)微信自動(dòng)加好友的軟件,(在普通...
摘要:基于和端微信開發(fā)的聊天機(jī)器人。使用的微信賬號(hào)即充當(dāng)機(jī)器人的賬號(hào)為個(gè)人賬號(hào),可自定義指令。關(guān)閉玫瑰感謝您的使用玫瑰閃電需要開啟請(qǐng)?jiān)诳刂婆_(tái)啟動(dòng)程序閃電微信發(fā)出關(guān)閉口令,程序退出。 Github: https://github.com/doterlin/wechat-robot showImg(https://segmentfault.com/img/remote/1460000010601...
摘要:本文為教程的第二部分,主要以微信控制器群發(fā)助手好友刪除檢測(cè)為例演示如何調(diào)用微信。教程流程簡(jiǎn)介這一系列教程從如何分析微信協(xié)議開始,第一部分教你如何從零開始獲取并模擬擴(kuò)展個(gè)人微信號(hào)所需要的協(xié)議。 現(xiàn)在的日常生活已經(jīng)離不開微信,本文將會(huì)拋磚引玉演示如何使用Python調(diào)用微信API做一些有意思的東西。 看完這一系列教程,你就能從頭開始實(shí)現(xiàn)自己關(guān)于微信的想法。 本文為教程的第二部分,主要以微信...
摘要:關(guān)于本教程有任何建議或者疑問,都?xì)g迎郵件與我聯(lián)系,或者在上提出教程流程簡(jiǎn)介教程將會(huì)從如何分析微信協(xié)議開始,第一部分將教你如何從零開始獲取并模擬擴(kuò)展個(gè)人微信號(hào)所需要的協(xié)議。 現(xiàn)在的日常生活已經(jīng)離不開微信,難免會(huì)生出微信有沒有什么API可以使用的想法。 那樣就可以拿自己微信做個(gè)消息聚合、開個(gè)投票什么的,可以顯然沒有這種東西。 不過(guò)還好,有網(wǎng)頁(yè)版微信不就等于有了API么,這個(gè)項(xiàng)目就是出于這個(gè)...
閱讀 1141·2021-08-12 13:24
閱讀 2988·2019-08-30 14:16
閱讀 3315·2019-08-30 13:01
閱讀 2077·2019-08-30 11:03
閱讀 2778·2019-08-28 17:53
閱讀 3092·2019-08-26 13:50
閱讀 2273·2019-08-26 12:00
閱讀 953·2019-08-26 10:38