Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

14 Commits

Repository files navigation

Гайд на API MAX

Нашли ошибку или хотите задать вопрос? Создайте Issue

Общая информация

У Max существует два API:

  • WSS (WebSocket) - для web-версии
  • TLS - для приложений

По факту это один и тот же API, но разница между ними все же есть. Как пример: в web-версии вырезали аутентификацию по номеру телефона.


Как анализировать Web API

Анализ можно проводить прямо в браузере с помощью панели разработчика:

  1. Заходим на сайт: web.max.ru
  2. Открываем панель разработчика:
  • Ctrl + Shift + J, либо
  • ПКМ -> Проверить (название пункта зависит от браузера)
  1. Переходим во вкладку Network (Сеть)
  2. (Опционально) В фильтрах сверху выбираем WS (или Socket)
  3. Перезагружаем страницу
  4. Находим и открываем WebSocket-подключение:
  • Если выполнен пункт 4, оно будет единственным в списке
  1. Переходим во вкладку Messages (Сообщения)

После выбора сообщения в левом нижнем углу можно изменить режим отображения View (по умолчанию там выставлено UTF-8).

Про содержание сообщений подробнее написано здесь.


Как анализировать App API

Здесь не обойтись без стороннего софта.

  1. Скачиваем Windows-версию приложения:
  1. Устанавливаем:
  • Рекомендуется использовать виртуальную машину, но это не принципиально.
  1. Скачиваем и устанавливаем mitmproxy:
  1. Запускаем mitmweb (веб-интерфейс, так как он более удобен)
  2. Устанавливаем сертификат:
  • Путь к файлу: C:\Users\%User%\.mitmproxy\mitmproxy-ca-cert.cer
  • Устанавливать для: Локального компьютера
  • Хранилище: Доверенные корневые центры сертификации

Настройка mitmproxy

В интерфейсе mitmproxy:

  1. Переходим во вкладку Capture
  2. Включаем Local Applications
  3. Выбираем max.exe
  • Max должен быть запущен в фоне.
  1. Переходим во вкладку Flow List
  2. Очищаем список:
  • File -> Clear All
  1. (Опционально) Перезапускаем Max.

Готово.

После выбора соединения в правом верхнем углу можно выбрать режим View.

Наиболее полезные режимы:

  • Hex Dump
  • Hex Stream - то же самое, но в одну строку

Содержание сообщений смотрите далее.


Содержание сообщений

Заголовок составляет 10 байт.

Номер байтаОписание
1ver - версия протокола
2cmd - команда (см. значения cmd)
3..4seq - порядковый номер операции.
5..6opcode - код операции (см. список opcode)
7cof - степень сжатия LZ4 (0 - сжатие не используется)
8..10Длина payload в байтах
11..Payload - содержание сообщения (кодируется в формате MsgPack)

Советы по анализу сообщений

Для анализа Hex Stream удобно использовать:

  • hexed.it - отличный онлайн-инструмент для работы с бинарными данными.
  • HxD - полноценный офлайн-аналог.

Также советую декомпилировать мобильную версию приложения с помощью jadx. Это даст гораздо больше понимания внутренних процессов.


Значения cmd

ЗначениеОписание
0Request
1Response
3Error

Сжатие

Байт cof отвечает за коэффициент сжатия.

Формула расчета: $\lfloor \text{исходная длина} / \text{длина при сжатии} \rfloor + 1$ (округляется до целого).

Сжатие применяется только в том случае, если длина payload превышает 32 байта.


Список opcode

Здесь собраны все возможные opcode.
Актуально для Android-приложения версии 26.23.1 и версии протокола: 10. Знак ~ означает, что opcode не подтвержден исходниками выбранной версии приложения.

OpcodeОписание
1PING
2DEBUG
3RECONNECT
5LOG
6SESSION_INIT
8LOGIN2
16PROFILE
17AUTH_REQUEST
18AUTH
19LOGIN
20LOGOUT
21SYNC
22CONFIG
23AUTH_CONFIRM
25PRESET_AVATARS
26ASSETS_GET
27ASSETS_UPDATE
28ASSETS_GET_BY_IDS
29ASSETS_ADD
32CONTACT_INFO
33CONTACT_ADD
34CONTACT_UPDATE
35CONTACT_PRESENCE
36CONTACT_LIST
37CONTACT_SEARCH
38CONTACT_MUTUAL ~
39CONTACT_PHOTOS
40CONTACT_SORT
42CONTACT_VERIFY
43REMOVE_CONTACT_PHOTO
46CONTACT_INFO_BY_PHONE
48CHAT_INFO
49CHAT_HISTORY
50CHAT_MARK
51CHAT_MEDIA
52CHAT_DELETE
53CHATS_LIST
54CHAT_CLEAR
55CHAT_UPDATE
56CHAT_CHECK_LINK
57CHAT_JOIN
58CHAT_LEAVE
59CHAT_MEMBERS
60PUBLIC_SEARCH
61CHAT_PERSONAL_CONFIG
62CHAT_LIVESTREAM_INFO
63CHAT_CREATE ~
64MSG_SEND
65MSG_TYPING
66MSG_DELETE
67MSG_EDIT
68CHAT_SEARCH
70MSG_SHARE_PREVIEW
71MSG_GET
72MSG_SEARCH_TOUCH
73MSG_SEARCH
74MSG_GET_STAT
75CHAT_SUBSCRIBE
76VIDEO_CHAT_START
77CHAT_MEMBERS_UPDATE
78VIDEO_CHAT_START_ACTIVE
79VIDEO_CHAT_HISTORY
80PHOTO_UPLOAD
81STICKER_UPLOAD
82VIDEO_UPLOAD
83VIDEO_PLAY
84VIDEO_CHAT_CREATE_JOIN_LINK
86CHAT_PIN_SET_VISIBILITY
87FILE_UPLOAD
88FILE_DOWNLOAD
89LINK_INFO
91GET_COMMENTS_UPDATES
92MSG_DELETE_RANGE
94MSG_DELETE_USER
96SESSIONS_INFO
97SESSIONS_CLOSE
98PHONE_BIND_REQUEST
99PHONE_BIND_CONFIRM
101AUTH_LOGIN_RESTORE_PASSWORD
103GET_INBOUND_CALLS
104AUTH_2FA_DETAILS
105EXTERNAL_CALLBACK
106PHONE_WEBAPP_SHARE
107AUTH_VALIDATE_PASSWORD
108AUTH_VALIDATE_HINT
109AUTH_VERIFY_EMAIL
110AUTH_CHECK_EMAIL
111AUTH_SET_2FA
112AUTH_CREATE_TRACK
113AUTH_CHECK_PASSWORD
115AUTH_LOGIN_CHECK_PASSWORD
116AUTH_LOGIN_PROFILE_DELETE
117CHAT_COMPLAIN
118MSG_SEND_CALLBACK
119SUSPEND_BOT
124LOCATION_STOP
125LOCATION_SEND
126LOCATION_REQUEST
127GET_LAST_MENTIONS
128NOTIF_MESSAGE
129NOTIF_TYPING
130NOTIF_MARK
131NOTIF_CONTACT
132NOTIF_PRESENCE
134NOTIF_CONFIG
135NOTIF_CHAT
136NOTIF_ATTACH
137NOTIF_CALL_START
139NOTIF_CONTACT_SORT
140NOTIF_MSG_DELETE_RANGE
142NOTIF_MSG_DELETE
143NOTIF_CALLBACK_ANSWER
144CHAT_BOT_COMMANDS
145BOT_INFO
147NOTIF_LOCATION
148NOTIF_LOCATION_REQUEST
150NOTIF_ASSETS_UPDATE
152NOTIF_DRAFT ~
153NOTIF_DRAFT_DISCARD ~
154NOTIF_MSG_DELAYED
155NOTIF_MSG_REACTIONS_CHANGED
156NOTIF_MSG_YOU_REACTED
158OK_TOKEN
159NOTIF_PROFILE
160WEB_APP_INIT_DATA
161COMPLAIN
162COMPLAIN_REASONS_GET
163CALL_HISTORY
164CALL_HISTORY_CLEAR
165NOTIF_CALL_HISTORY
166VIDEO_CHAT_JOIN
176DRAFT_SAVE ~
177DRAFT_DISCARD ~
178MSG_REACTION
179MSG_CANCEL_REACTION
180MSG_GET_REACTIONS
181MSG_GET_DETAILED_REACTIONS
193STICKER_CREATE
194STICKER_SUGGEST
195VIDEO_CHAT_MEMBERS
196CHAT_HIDE
198CHAT_SEARCH_COMMON_PARTICIPANTS
199PROFILE_DELETE
200PROFILE_DELETE_TIME
202TRANSCRIBE_MEDIA
203PHOTO_URL_REFRESH
208STORIES_LIST
209STORIES_LIST_BY_OWNER_ID
210STORIES_GET_BY_OWNER_ID
211STORIES_GET_STATS
212STORIES_GET_DETAILED_STATS
213STORIES_REACT
214STORIES_MARK
215STORIES_SEND
216NOTIF_STORIES_UPDATE
217STORIES_EDIT
218STORIES_DELETE
220STORIES_GET_BY_STORY_ID
256ORG_INFO
257CHAT_REACTIONS_SETTINGS_SET
258REACTIONS_SETTINGS_GET_BY_CHAT_ID
259ASSETS_REMOVE
260ASSETS_MOVE
261ASSETS_LIST_MODIFY
272FOLDERS_GET
273FOLDERS_GET_BY_ID
274FOLDERS_UPDATE
275FOLDERS_REORDER
276FOLDERS_DELETE
277NOTIF_FOLDERS
290AUTH_QR_APPROVE
292NOTIF_BANNERS
293NOTIF_TRANSCRIPTION
300CHAT_SUGGEST
301AUDIO_PLAY
302BANNERS_GET
303MSG_DELIVERY
304SEND_VOTE
305VOTERS_LIST_BY_ANSWER
306GET_POLL_UPDATES
307CHAT_CHECK_ESIA

Структура сообщения ошибки

Error
{
string description
string error
string title
string message
string localizedMessage
}

title и description не гарантированы.


Структуры запросов и ответов

Здесь описаны структуры сообщений запросов и ответов под каждый opcode. Названия полей полностью соответствуют тем, что будут в сообщениях, т.е. их можно использовать для парсинга.

Optional не значит, что поле можно полностью игнорировать. Оно может быть обязательным при определённых условиях.
EnumAsString значит, что поле представляет из себя String, но может содержать ограниченное количество значений, которые можно представить в виде Enum.

PING

Request
{
bool interactive
}
Response { }

DEBUG

Request
{
[EnumAsString]
CmdType cmd
string[] args
}
Response { }

RECONNECT

Request
{
bool tls
string redirectHost
}
Response { }

LOG

Request
{
ApiLogEntry[] events
}
Response { }

SESSION_INIT

Request {
UserAgent userAgent
string deviceId
long clientSessionId
[Optional]
string mt_instanceid
}
Response
{
long callsSeed
bool lang
bool isVpn
string[] reg-country-code
int app-update-type
string location
string recovery-url
}

LOGIN2

Request
{
string configHash
long contactsSync
bool needProfile
}
Response
{
Configuration config
Profile profile
ContactInfo[] contacts
}

PROFILE

Request
{
[Optional]
string firstName
[Optional]
string lastName
[Optional]
string photoToken
[Optional]
long photoId
[Optional]
RectF crop
[Optional]
string description
[Optional]
string link
[EnumAsString]
AvatarType avatarType
}
Response
{
Profile profile
}

AUTH_REQUEST

Request
{
string phone
[EnumAsString]
AuthType type
[Optional]
byte[] mode
}
Response
{
int codeLength
long altActionDuration
int requestCountLeft
string token
long requestMaxDuration
}

AUTH

Request
{
string token
[Optional]
string verifyCode
string authTokenType
}
Response
{
Profile profile
Dictionary<string, TokenAttribute> tokenAttrs
NeuroAvatarsPresetInfo[] presetAvatars
PasswordChallenge passwordChallenge
}

LOGIN

Request
{
string token
bool interactive
[Optional]
long chatsSync
[Optional]
long contactsSync
long presenceSync
[Optional]
string configHash
[Optional]
long callsSync
[Optional]
long lastLogin
[Optional]
long draftsSync
[Optional]
long bannersSync
[Optional]
byte[] chatCacheFingerprint
[Optional]
byte[] chatsCountGroups
ExpObject exp
}
Response
{
bool videoChatHistory
long chatMarker
Configuration config
DraftsNews drafts
Dictionary<long, Presence> presence
ContactInfo[] contacts
Dictionary<long, Message[]> messages
Profile profile
int updates
long time
Call[] calls
Chats[] chats
string token
Login2Flags login2Flags
long resetAt
}

LOGOUT

Request
{
string pushToken
}
Response { }

SYNC

Request
{
Dictionary<string, ContactNameWrapper> contactList
}
Response
{
ContactInfo[] contacts
Dictionary<string, long> phones
}

CONFIG

Request
{
[Optional]
string pushToken
[Optional]
long pushOptions
[Optional]
Configuration settings
[Optional]
bool reset
}
Response
{
string hash
ConfigurationUserSettings user
}

AUTH_CONFIRM

Request
{
string token
[EnumAsString]
LoginTokenType tokenType
string firstName
[Optional]
string lastName
[Optional]
long photoId
[Optional, EnumAsString]
AvatarType avatarType
}
Response
{
[EnumAsString]
LoginTokenType tokenType
string token
Profile profile
}

PRESET_AVATARS

Request { }
Response
{
NeuroAvatarsPresetInfo[] presetAvatars
}

ASSETS_GET

Request
{
[Optional, EnumAsString]
AssetType type
[Optional]
string sectionId
long from
int count
[Optional]
string query
}
Response
{
long marker
long[] stickers
long[] stickerSets
Background[] backgrounds
}

ASSETS_UPDATE

Request
{
[Optional, EnumAsString]
AssetType type
long sync
[Optional]
long chatId
[Optional]
long userId
}
Response
{
Dictionary<long, long> animojiUpdates
Dictionary<long, long> stickerSetsUpdates
long sync
Dictionary<long, long> stickersUpdates
Section[] sections
Dictionary<long, long> animojiSetUpdates
string[] stickersOrder
}

ASSETS_GET_BY_IDS

Request
{
AssetType type
long[] ids
}
Response
{
Animoji[] animoji
AnimojiSet[] animojiSets
Sticker[] stickers
StickerSet[] stickerSets
}

ASSETS_ADD

Request
{
AssetType type
long[] ids
}
Response
{
bool success
long updateTime
}

CONTACT_INFO

Request
{
long[] contactIds
[Optional]
long chat_id
}
Response
{
ContactInfo[] contacts
}

CONTACT_UPDATE

Request
{
long contactId
[Optional, EnumAsString]
ContactUpdateAction action
[Optional]
long firstName
[Optional]
long lastName
}
Response
{
ContactInfo contact
}

CONTACT_PRESENCE

Request
{
long[] contactIds
[Optional]
long sync
}
Response
{
Dictionary<long, Presence> presence
long time
}

CONTACT_LIST

Request
{
[EnumAsString]
StatusType status
[Optional]
int from
[Optional]
int count
}
Response
{
ContactInfo[] contacts
}

CONTACT_SEARCH

Request
{
}
Response
{
ContactSearchResult[] result
int total
}

CONTACT_MUTUAL

Request
{
}
Response
{
long[] contactIds
}

CONTACT_PHOTOS

Request
{
long contactId
[Optional]
int count
[Optional]
int from
}
Response
{
long[] ids
string[] urls
int total
}

CONTACT_VERIFY

Request { }
Response
{
[EnumAsString]
VerifyResultType verifyResult
string name
}

REMOVE_CONTACT_PHOTO

Request
{
long photoId
}
Response
{
Profile profile
}

CONTACT_INFO_BY_PHONE

Request
{
string phone
}
Response
{
ContactInfo contact
}

CHAT_INFO

Request
{
long[] chatIds
}
Response
{
Chat chat
ContactInfo user
Chat[] chats
}

CHAT_HISTORY

Request
{
long chatId
[Optional]
long postId
long from
int forward
long forwardTime
int backward
long backwardTime
bool getChat
bool getMessages
[Optional]
string chatAccessToken
string itemType
bool interactive
}
Response
{
Chat chat
Message[] messages
long[] messageIds
}

CHAT_MARK

Request
{
long chatId
long mark
[Optional]
long messageId
[EnumAsString]
MarkType type
}
Response
{
long mark
int unread
bool success
}

CHAT_MEDIA

Request
{
long chatId
[Optional]
long messageId
[Optional, EnumAsString]
AttachType[] attachTypes
[Optional]
int forward
[Optional]
int backward
}
Response
{
long forward
Message[] messages
int pos
int total
long backward
}

CHAT_DELETE

Request
{
long chatId
long lastEventTime
bool forAll
}
Response { }

CHATS_LIST

Request
{
long marker
int count
}
Response {
long marker
Chat[] chats
}

CHAT_CLEAR

Request
{
long chatId
long lastEventTime
bool forAll
}
Response { }

CHAT_UPDATE

Request
{
long chatId
[Optional, EnumAsString]
AccessType access
[Optional]
string link
[Optional]
bool revokePrivateLink
[Optional]
bool removeLink
[Optional]
string description
[Optional] Dictionary<string, bool> options
[Optional]
string theme
[Optional]
string photoToken
[Optional]
RectF crop
[Optional]
long pinMessageId
[Optional]
bool notifyPin
[Optional]
long changeOwnerId
}
Response {
Chat chat
}

CHAT_CHECK_LINK

Request
{
string link
[EnumAsString]
LinkType linkType
}
Response { }

CHAT_JOIN

Request
{
string chatAccessToken
string link
}
Response {
Chat chat
}

CHAT_LEAVE

Request
{
long chatId
}
Response { }

CHAT_MEMBERS

Request
{
long chatId
[Optional, EnumAsString]
MemberType type
[Optional]
long marker
[Optional]
int count
[Optional]
string query
}
Response
{
Member[] members
long marker
}

PUBLIC_SEARCH

Request
{
string query
int count
[Optional]
long marker
[Optional]
SearchType type
}
Response
{
long marker
SearchResult[] result
string ucpQId
int total
}

CHAT_PERSONAL_CONFIG

Request
{
long chatId
bool hideNonContactBar
}
Response
{
Chat chat
}

About

Гайд на API мессенджера MAX

Topics

Resources

Stars

17 stars

Watchers

4 watching

Forks

Contributors