Эта статья не требует знаний об ИИ.Если вы здесь для ИИ, вы можете быть разочарованы.
Некоторое время назад ко мне подошел друг и спросил, могу ли я разработать программу для WeChat, которая автоматически добавляет друзей (в глазах обычных людей программист — это хакер третьего сорта, который специализируется на написании плагинов для троянских вирусов). Если ты не можешь это написать, ты даже не третьесортный.
Так что для того, чтобы доказать, что я третьесортный хакер, я просто Baidu два готовых для него.Изначально дело должно было закончиться здесь, но в духе исследования, я хотел понять принцип такого рода плагина кстати, так Байгогуду на минутку, Окончательного принципа найти не удалось, но было найдено несколько интересных репозиториев на гитхабе, а в качестве стороннего WeChat использовалась веб-версия WeChat API.
Давайте сначала посмотрим на эффект?
шаг
Давайте посмотрим на общие шаги
- получить UUID
- Получить QR-код на основе UUID
- Отсканируйте код для входа, получите данные для входа
- Обмен данными для входа на данные инициализации
- выполнить инициализацию данных
- Получить список друзей и список сообщений
- отправлять сообщения
Ниже приведен конкретный процесс, если вы не заинтересованы, вы можете напрямую потянуть до конца, чтобы просмотреть хранилище исходного кода.
Следует отметить, что метод (POST/GET) и Content-Type, используемые на каждом шаге запроса, различаются. Я отметил их ниже. Если есть какой-либо запрос, пожалуйста, обратитесь к исходному коду gtihub.
1. Получить UUID
адрес интерфейсаwx.qq.com/jslogin
метод запроса POST
Тип параметра (тип контента) application/x-www-form-urlencoded
параметр
{
appid: 'wx782c26e4c19acffb',
fun: 'new',
lang: 'zh_CN',
_: new Date().valueOf()
}
За исключением того, что последняя текущая метка времени не фиксирована, остальные три параметра жестко закодированы, просто скопируйте их, если вызов будет успешным, он получит строкуwindow.QRLogin.code = 200; window.QRLogin.uuid = "obizONtqZA==";, вам нужно найти способ перехватитьwindow.QRLogin.uuid =Следующая строка символов является UUID.
2. Получите QR-код
Этот шаг очень прост, с помощью UUID мы можем напрямую запросить'https://wx.qq.com/qrcode/' + UUIDПолучите QR-код.После получения QR-кода не спешите сканировать QR-код, потому что мы должны сначала отслеживать статус сканирования QR-кода, чтобы мы могли знать, когда мы вошли в систему.
Метод запроса GET без параметров
3. Следите за результатами сканирования QR-кода
адрес интерфейсаЯ думаю, что .QQ.com/CGI-bin/ называется…
метод запроса ПОЛУЧИТЬ
Тип параметра (тип контента) application/x-www-form-urlencoded
параметр
{
tip: 0,
uuid: 'obizONtqZA==',
_: new Date().valueOf(),
loginicon: true
}
Значение подсказки равно 0 или 1. Мониторинг делится на два этапа: первый этап — отслеживание того, сканирует ли пользователь код, а подсказка — 0. Второй этап — отслеживание того, нажимает ли пользователь WeChat для подтверждения логин, а подсказка 1.
uuid — это UUID, полученный на первом этапе.
_ текущая метка времени
loginicon Думаю вернуть ли аватарку пользователя после сканирования кода, только заполните true.
Верните результат, когда вы сканируете QR-код, интерфейс вернет вам такой объект
{
'window.code': 201,
'window.userAvatar': 头像的 base64 地址
}
Получен код 201, что указывает на то, что код был отсканирован, но это не означает, что вы вошли в систему. Вам нужно продолжать следить за тем, нажимаете ли вы кнопку «Подтвердить вход» на мобильном телефоне WeChat (повторите вышеуказанные шаги и изменить подсказку в параметре на 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' }
}
4. Получить данные инициализации (конфиденциальные данные)
В данных, полученных на предыдущем шагеwindow.redirect_uriОн содержит URL-адрес и некоторые параметры запроса. Похоже, что нет возможности напрямую запросить этот адрес. Вам нужно разделить URL-адрес и параметры, а затем добавить другие параметры.
Адрес интерфейса указан выше
метод запроса ПОЛУЧИТЬ
Тип параметра (тип контента) application/x-www-form-urlencoded
параметр
{
ticket: 上面得到的 ticket,
uuid: 上面得到的 uuid,
lang: 'zh_CN', // 固定
scan: 上面得到的 scan,
fun: 'new' // 固定
}
В возвращаемом заголовке этого шага будет куки, которую нужно сохранить, а затем куку нужно привести в заголовке запроса, а также сохранить конфиденциальную информацию в формате xml.
совет: можно использовать формат xmlxml2jsПреобразовать в json.
5. Инициализация
Да, на этом этапе вход в систему, наконец, успешен, просто вызовите следующий интерфейс и инициализируйте следующий
адрес интерфейсаhttps://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=${~(new Date().valueOf())}
метод запроса POST
Тип параметра (тип контента) application/json
параметр
{
BaseRequest: {
DeviceID: 'e747337466044216', // 这个好像随便填都可以
Sid: 上一步获取到的 wxsid,
Uin: 上一步获取到的 wxuin,
Skey: 上一步获取到的 skey
}
}
Здесь есть два разных места: во-первых, за адресом должна следовать временная метка, а временная метка должна быть обращена битом, во-вторых, параметры запроса помещаются под BaseRequest, а не на уровне объекта. свойства ниже.
В возвращаемых данных есть два данных, которые нужно сохранить, один — data.SyncKey, другой — res.data.User.UserName, который будет использоваться позже.
На этом вход в систему действительно завершен.Если вам не нужен список друзей, вы можете напрямую получать сообщения.
6. Обнаружение новых новостей
адрес интерфейсаВеб-пуш. Думаю, QQ.com/CGI-bin/named…
метод запроса ПОЛУЧИТЬ
Тип параметра (тип контента) 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
}
Данные возвращаемого содержимого содержат следующее содержимое
window.synccheck={retcode:"0",selector:"2"}
Если селектор равен 2, это означает, что есть новое сообщение, перейдите к следующему шагу и получите содержимое сообщения.
7. Получите содержание сообщения
адрес интерфейсаЯ думаю, что .QQ.com/CGI-bin/ называется…
метод запроса POST
Тип параметра (тип контента) application/json
параметр
{
BaseRequest: {
Uin: 第四步拿到的 wxuin,
Sid: 第四步拿到的 wxsid,
Skey: 第四步拿到的 skey,
DeviceID: 'e747337466044216', // 同上一步
},
SyncKey: data.SyncKey, // 还记得上一步我们费尽千辛万苦转换这个数据吗? 你没看错,这里不需要转换,就是这么神奇
rr: ~(new Date().valueOf())
}
В возвращаемом результате естьdata.AddMsgListЭто просто список сообщений, и есть ещеdata.SyncCheckKeyЭто для следующего запросаSyncKey, будет меняться каждый раз.
AddMsgList - это массив, который может содержать несколько сообщений. Автоматических сообщений много, поэтому я не буду описывать их по одному. Вот еще два важных поля. Если вас интересуют другие поля, вы можете их распечатать и посмотреть сами.
FromUserName WeChat-имя другой стороны, говорят, что это имя WeChat, но на самом деле это внутренний идентификатор, начинающийся с @ или @@, что совершенно нечитаемо.По моему мнению, те, кто начинается с @, должны быть обычными друзьями , а те, которые начинаются с @@, являются группами или общедоступными учетными записями.
Содержимое сообщения
Имея содержание сообщения и человека, отправившего сообщение, мы можем ответить друг другу, но что? Конечно, много писать if else или переключать регистр для адаптации к разным ситуациям нельзя, можно поискать в интернете价值一个亿的ai代码Хахаха
8. Получите автоматический ответ
Здесь я использую API Turing Robot.адрес, конечно, вы также можете использовать другие.
адрес интерфейсаоткрытый API. Turing123.com/open API/API…
метод запроса POST
Тип параметра (тип контента) application/json
параметр
{ восприятие: { вводтекст: { text: 'Сообщение, на которое нужно ответить' } }, Информация о пользователе: { apiKey: tulingApiKey, // Подать заявку на официальном сайте Turing userId: tulingUserId // то же, что и выше }
Если вам лень подавать заявку, можете скопировать в моем проекте, вsrc/global.jsвнутри, внутри возвращаемого содержимогоdata.results[0].values.textНиже вы можете увидеть контент автоматического ответа, сгенерированного для вас Turging для вас (результаты - это массив, который поддерживает несколько ответов одновременно)
9. Ответить на сообщение
После получения автоматического ответа нам нужно только отправить его вашим друзьям, то есть завершить автоматический разговор.
адрес интерфейсаЯ думаю, что .QQ.com/CGI-bin/ называется…
метод запроса POST
Тип параметра (тип контента) 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='), с нетерпением жду вашего приезда稿предмет
Если у вас есть какие-либо комментарии или предложения по этой статье, пожалуйста, постарайтесьgithubподниматьissue, я был занят в последнее время, и я не очень часто посещаю сообщество