了解一波网页端微信是如何登录的

7次阅读

共计 4670 个字符,预计需要花费 12 分钟才能阅读完成。

前言
工作之余突然对微信的网页版的协议通信感兴趣可以搞一波了解下。毕竟网页版容易抓,靠一个浏览器的开发者工具的 Network 就开始抓包解析了。这是我 2019 年 03 月写的文档。因为微信的协议可能随时存在变动,以下内容可以参考一波。本人爬虫的方法很简单,就是尽一切方法模仿被爬虫者的行为。该文档目前只写到获取最新消息。先记录一波。有空更新
项目地址:楠尼玛大帝 / wxWebR(Java 版)

流程步骤
(这里只说到成功登录到微信并获取最新消息,因为只是模仿到这里,其他的全部都已经清清楚楚只是看你调不调用而已了。该拿到的参数都有了)

去获取一个 uuid,可以根据这个 uuid 获取一张二维码登录的图片
微信客户端扫描该二维码,在客户端确认登录。
浏览器不停的调用一个接口,如果返回登录成功,则调用登录接口
循环遍历一个检查是否有新消息的接口。
如果新消息的接口返回有新消息的状态码去获取消息接口。(完)

WebWechat API
(这里也只说到成功登录到微信并获取最新消息。其他可以自行去抓包或者参考其他文档比如码云参考 ->python 版 ( 老版本)
第一步获取 UUID(参考方法 getUUID)

API
获取 UUID

url
https://login.wx.qq.com/jslogin

method
POST

data
URL Encode(text/javascript)

params

appid: 应用 ID 参考:wx782c26e4c19acffb redirect_uri 转发地址 参考:https://wx.qq.com/cgi-bin/mmw…fun: 应用类型 参考:new lang: 语言 参考:zh_CN _: 时间戳 参考:当前时间毫秒级 13 位数的时间戳

返回数据 (String):
window.QRLogin.code = 200; window.QRLogin.uuid = “xxx”
注:目前看来参数除了_ 当前时间毫秒级 13 位数的时间戳 其他都是固定的值。在微信给的 js 里面 index_ad43596.js 里搜索 API_jsLogin 可以得到这些参数。而且大部分不理解参数都可以从这个 js 文件得到答案。

显示二维码就不浪费时间直接就是拿第一步拿到的 uuid 拼接就是二维码地址:https://login.weixin.qq.com/q…{uuid}
第二步等待扫码登录即微信确认登录

API
获取二维码扫描登录状态

url
https://login.wx.qq.com/cgi-b…

method
GET(text/javascript)

params

tip : 这个东西根据浏览器走的话就是第一次为 1,后面都是为 0,网上说是扫码状态 loginicon 参考:true uuid : 获取到的 uuid _ : 当前时间毫秒级 13 位数的时间戳

返回数据 (String):
window.code=xxx;

xxx:
【未扫码的话】-> window.code=408;
【手机扫码但是未登录】-> window.code = 201;
【手机取消登录】-> window.code=400;
【手机授权登录】-> window.code=200;
当返回 200 时:
wechatLoginStatus:window.code=200; window.redirect_uri=
“https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=XXX&uuid=XXX&lang=XXX&scan=XXX”;
当返回 201 时可以获取扫码用户头像的 base64 数据哦 (好像没啥用)
注:像这种成功的话得到这种参数自己一定存起来,下一步肯定要用即 ticket,lang,uuid,scan

第三步扫描成功去获取你的登录凭据

API
获取登录凭据

url
https://wx2.qq.com/cgi-bin/mm…

method
GET(text/plain;charset=utf-8)

params

ticket : ticket uuid : uuid lang : lang scan : scan fun : 参考:new version 参考:v2

返回数据 (XML):
<error>
<ret>0</ret>
<message>OK</message>
<skey>xxx</skey>
<wxsid>xxx</wxsid>
<wxuin>xxx</wxuin>
<pass_ticket>xxx</pass_ticket>
<isgrayscale>1</isgrayscale>
</error>
核心数据点: skey, wxsid, wxuin, pass_ticket
注:切记,第三步会返回 cookie, 存下来,这里这个接口会得到 cookie 的。cookie 哪里用到我会说明的。
第四步微信初始化

API
微信初始化

url

https://wx2.qq.com/cgi-bin/mm…lang&pass_ticket=pass_ticket

method
POST

data
JSON(application/json; charset=UTF-8)

header
Content-Type: application/json; charset=UTF-8

params
{BaseRequest: {          Uin: wxuin,          Sid: wxsid,          Skey: skey,          DeviceID: xxx,} }

注:r 这个参数是通过 js 的一个 ~new Date 这是一个类似二进制反转的一个,可自行百度或者打开控制台输出一下就知道了。DeviceID 这个参数是一个简单 js 拼接出来的参数 “e”+(Math.random().toFixed(15)).substring(2, 17)

返回数据 (JSON):
{
“BaseResponse”: {
“Ret”: 0,
“ErrMsg”: “”
},
“Count”: 11,
“ContactList”: […],
“SyncKey”: {
“Count”: 4,
“List”: [
{
“Key”: 1,
“Val”: 635705559
},

]
},
“User”: {
“Uin”: xxx,
“UserName”: xxx,
“NickName”: xxx,
“HeadImgUrl”: xxx,
“RemarkName”: “”,
“PYInitial”: “”,
“PYQuanPin”: “”,
“RemarkPYInitial”: “”,
“RemarkPYQuanPin”: “”,
“HideInputBarFlag”: 0,
“StarFriend”: 0,
“Sex”: 1,
“Signature”: “Apt-get install B”,
“AppAccountFlag”: 0,
“VerifyFlag”: 0,
“ContactFlag”: 0,
“WebWxPluginSwitch”: 0,
“HeadImgFlag”: 1,
“SnsFlag”: 17
},
“ChatSet”: xxx,
“SKey”: xxx,
“ClientVersion”: 369297683,
“SystemTime”: 1453124908,
“GrayScale”: 1,
“InviteStartCount”: 40,
“MPSubscribeMsgCount”: 2,
“MPSubscribeMsgList”: […],
“ClickReportInterval”: 600000
}
第四步中获取 SyncKey, User 后面的消息监听用。
第五步消息检查是否有新消息 (这里要带上 cookie)

API
synccheck

url

https://webpush.wx2.qq.com/cg…skey&sid=wxsid&uin=wxuin&deviceid=xxx&synckey=Synckey&_=xxx

method
POST

data
JSON(text/javascript)

header
ContentType: application/json; charset=UTF-8

params

返回数据 (String):
window.synccheck={retcode:”xxx”,selector:”xxx”}

retcode:
0 正常
1100 失败 / 登出微信
1101 在其他地方登录了微信
1102 无凭据或者凭据已失效
selector:
0 正常
2 新的消息
7 进入 / 离开聊天界面
注:deviceid 和上面的 DeviceID 这个参数是一样的:一个简单 js 拼接出来的参数 “e”+(Math.random().toFixed(15)).substring(2, 17) 我们叫他时间戳取反吧
_是一个当前时间毫秒级 13 位数的时间戳

第六步获取最新消息(要带上 Cookie)

API
webwxsync

url

https://wx2.qq.com/cgi-bin/mm…wxsid&skey=Skey

method
POST

data
JSON(text/plain)

header
ContentType: application/json; charset=UTF-8

params
{BaseRequest: { Uin: User 下的 Uin, Sid: wxsid, Skey: skey, DeviceID: DeviceID},      SyncKey: syncKey,      rr: 时间戳取反 }

返回数据 (JSON):
{
‘BaseResponse’: {‘ErrMsg’: ”, ‘Ret’: 0},
‘SyncKey’: {
‘Count’: 不确定个数,
‘List’: [
{‘Val’: 636214192, ‘Key’: 1},

]
},
‘ContinueFlag’: 0,
‘AddMsgCount’: 1,
‘AddMsgList’: [
{
‘FromUserName’: ”,
‘PlayLength’: 0,
‘RecommendInfo’: {…},
‘Content’: “”,
‘StatusNotifyUserName’: ”,
‘StatusNotifyCode’: 5,
‘Status’: 3,
‘VoiceLength’: 0,
‘ToUserName’: ”,
‘ForwardFlag’: 0,
‘AppMsgType’: 0,
‘AppInfo’: {‘Type’: 0, ‘AppID’: ”},
‘Url’: ”,
‘ImgStatus’: 1,
‘MsgType’: 51,
‘ImgHeight’: 0,
‘MediaId’: ”,
‘FileName’: ”,
‘FileSize’: ”,

},

],
‘ModChatRoomMemberCount’: 0,
‘ModContactList’: [],
‘DelContactList’: [],
‘ModChatRoomMemberList’: [],
‘DelContactCount’: 0,

}
注 这一块比较要特别注意,得到消息后发现返回的信息也是有 SyncKey 这个要更新一波直接拿下来替换自己的旧的,不然第五步检查消息是会出现问题就是刷的特别快,而且消息是不正确的。因为真正成功访问的到是微信的请求不会立即返回,一个请求会跑的比较久至少几十秒,因为防止疯狂遍历,不用担心因为一旦有数据返回微信服务器会立刻返回数据给你进入下一阶段的循环。这一步也是比较坑的就是 SyncKey 要记得更新就行了。还有一个很骚的点就是_这个参数虽然是毫秒级的 13 位时间戳,但是在微信第一次获取后他不会再去 new 了,就是一直 +1+1;
致谢

本项目受到以下项目的启发:
Zhao / wxBot

正文完
 0