利用网页版微信API做一个微信机器人
前一阵子一个朋友找我,问我能不能搞一个微信自动加好友的软件,(在普通人眼里,程序员就是专门写木马病毒外挂软件的三流黑客.不会写那就连三流都不是.
所以为了证明我是三流黑客,我随便百度了两个现成的给他.本来事情到这里应该结束了的,不过本着探索的精神,想顺便了解一下这种外挂的原理,于是百歌谷度了一下,
最终原理没找到,倒是找到几个有意思的 github 仓库,利用网页版的微信 API 做第三方微信.
先看个效果?
步骤
获取 UUID根据 UUID 获取二维码扫码登陆, 获取登陆信息拿登陆信息换初始化数据拿数据初始化获取好友列表和消息列表发送消息需要注意的是,每一步的请求所使用的方法(POST/GET) 和 Content-Type 都是不一样的,下面我都有标注,如果有请求不通的请参考 gtihub 源码.一、获取 UUID
参数类型(content-type) application/x-www-form-urlencoded
{ appid: 'wx782c26e4c19acffb', fun: 'new', lang: 'zh_CN', _: new Date().valueOf() }
二、获取二维码
三、监听二维码的扫描结果
参数类型(content-type) application/x-www-form-urlencoded
{ tip: 0, uuid: 'obizONtqZA==', _: new Date().valueOf(), loginicon: true }
tip 取值 0 或 1, 监听分2个阶段,第一阶段,监听用户是否扫码,tip 为 0,第二阶段,监听用户是否在微信上点确认登陆,tip 为 1.
loginicon 我猜应该是否扫码完返回用户头像,都填 true 即可.
{ 'window.code': 201, 'window.userAvatar': 头像的 base64 地址 }
得到的 code 是 201, 说明已扫码,但并不代表已登陆,还需要继续监听是否在手机微信上点击 确认登陆 按钮(重复上面步骤,把 参数里的 tip 改为 1 即可)
{ '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' } }
四、获取初始化数据(敏感数据)
上一步获取到的数据里面的 window.redirect_uri
里包含了一个 url 和一些 查询参数,直接请求这个地址好像没办法成功,需要将 url 和 参数拆分,然后加入其他参数
参数类型(content-type) application/x-www-form-urlencoded
{ ticket: 上面得到的 ticket, uuid: 上面得到的 uuid, lang: 'zh_CN', // 固定 scan: 上面得到的 scan, fun: 'new' // 固定 }
这一步的返回的头部里面,会有个 cookie ,需要存起来,接来来得到请求头里面要带上这个 cookie,另外就是一个 xml 格式的 敏感的信息,也是要存起来.
tip: xml 格式可以用 xml2js 转换成 json.五、初始化
呼,到这一步,终于接近登陆成功了,只需再调用以下接口,初始化以下
接口地址 https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=${~(new Date().valueOf())}
请求方法 POST
参数类型(content-type) application/json
参数
{ BaseRequest: { DeviceID: 'e747337466044216', // 这个好像随便填都可以 Sid: 上一步获取到的 wxsid, Uin: 上一步获取到的 wxuin, Skey: 上一步获取到的 skey } }
这里有 2 个地方跟之前不同的,第一是地址后面要跟一个时间戳,而且这个时间戳还要按位取反,第二个是请求参数是放在 BaseRequest 下面,而不是对象的一级属性下面.
返回的数据里面有 2 个数据需要保存起来,一个是 data.SyncKey, 一个是 res.data.User.UserName,后面都会用到
到此才真正完成登陆,下面如果你不需要好友列表的话,可以直接收取消息了
六、检测新消息
接口地址 https://webpush.wx.qq.com/cgi...
请求方法 GET
参数类型(content-type) application/json
参数
let time = new Date().getTime() let synckey = '' let sk = data.SyncKey.List || [] // data.SyncKey 就是上一步获取到的那个 for (let i = 0; i < sk.length; i++) { synckey += `${sk[i].Key}_${sk[i].Val}` if (i !== sk.length - 1) synckey += '|' } // 传递的参数 { r: time, sid: 第四步拿到的 wxsid, uin: 第四步拿到的 wxuin, skey: 第四步拿到的 skey, deviceid: 'e747337466044216', // 同上一步 synckey: synckey, _: time }
返回内容的 data 里面 包含如下内容
window.synccheck={retcode:"0",selector:"2"}
如果 selector 是 2, 说明有新消息,走下一步,获取消息内容
七、获取消息内容
接口地址 https://wx.qq.com/cgi-bin/mmw...
请求方法 POST
参数类型(content-type) application/json
参数
{ BaseRequest: { Uin: 第四步拿到的 wxuin, Sid: 第四步拿到的 wxsid, Skey: 第四步拿到的 skey, DeviceID: 'e747337466044216', // 同上一步 }, SyncKey: data.SyncKey, // 还记得上一步我们费尽千辛万苦转换这个数据吗? 你没看错,这里不需要转换,就是这么神奇 rr: ~(new Date().valueOf()) }
返回结果里面有个 data.AddMsgList
就是消息列表了,还有个 data.SyncCheckKey
就是下次请求的时候用的 SyncKey
, 每次都会变的.
AddMsgList 是一个数组,里面可能包含多条消息,消息的自动比较多,就不一一说明了,这里说说 2 个比较重要的字段,其他的字段有兴趣的可以自己打印出来看一下.
FromUserName 对方的微信名,说是微信名,其实是一个 @ 或 @@ 开头的内部的id, 完全不可读,据我猜测 @ 开头的应该是普通好友, @@ 开头的是群或者公众号之类的
Content 消息内容
有了消息内容,和发消息的人,我们就可以回复对方,不过回复什么? 当然不可能写一大堆 if else 或者 switch case 去适应各种情况,不妨网上搜索一下 价值一个亿的ai代码
哈哈哈
八、获取自动回复内容
这边我用的是图灵机器人的 API 地址,当然你也可以用其他的.
接口地址 http://openapi.tuling123.com/...
请求方法 POST
参数类型(content-type) application/json
参数
{
perception: { inputText: { text: '待回复的消息' } }, userInfo: { apiKey: tulingApiKey, // 在图灵官网申请 userId: tulingUserId // 同上
}
你要是懒得去申请的话,可以在我的项目里面复制, 在 src/global.js
里面,在返回的内容里面 data.results[0].values.text
下面可以看到图灵给你生成的自动回复内容(results是一个数组,支持一次回复多条)
九、回复消息
拿到自动回复以后,我们只需要把它发给你的好友,即完成一次自动对话.
接口地址 https://wx.qq.com/cgi-bin/mmw...
请求方法 POST
参数类型(content-type) application/json
参数
let timeStamp = new Date().getTime() + '' + (9000 * Math.random() + 1000) { BaseRequest: { Uin: 同上, Sid: 同上, Skey: 同上, DeviceID: 同上 }, Msg: { Type: 1, // 消息类型 1 是文字消息,其他的暂时没用过 Content: '回复的内容', FromUserName: '你的用户名,在第五步有拿到', ToUserName: '对方的微信名 第七步的 FromUserName', LocalID: timeStamp, ClientMsgId: timeStamp }
发送成功的话,会返回如下内容
{ BaseResponse: { Ret: 0, ErrMsg: '' }, MsgID: '2033517278669301361', LocalID: '' }
好了,这样我们的一个自动回复机器人就完成了.完整的代码在这里
广告时间
我们40人的前端团队常年招兵买马中,在厦门的和想来厦门的童鞋们,不要吝惜你的简历,使劲砸过来 邮箱:atob('bnVveWFAZ2FvZGluZy5jb20=')
, 期待你一起来稿
事