Разбор протокола World of Tanks
Приветствую, сегодня будем разбирать протокол танков (мобильных)
Автор не несет ответственности за материал предоставленный в данной статье, все что вы прочитали или увидели — мне приснилось. Инструменты, написанные в процессе анализа протокола, никогда не будут выпущены в публичный доступ.
Инструменты которые нам понадобятся
x64 dbg
Cutter (Radare2)
C++4. WireShark
Начало (Протокол)
Начинать анализ я начал с определения протокола который использует игра для коммуникации (TCP / UDP).
Открываем procmon (делаем попытку авторизации в клиенте игры).
Сетевая активность показывает что в игре используется UDP протокол (на момент авторизации точно)Я заметил пакеты размером 12 байт (сообщения ping / pong), но что самое интересное, это пакет размером 273 байта и ответ размером 30 байтМожно смело сказать что этот пакет является пакетом авторизации.Немного изучив директорию игры я наткнулся на файл «loginapp_wot.pubkey«Содержимое данного файла — публичный ключ RSA-2048 (Но об этом позже)Сейчас нам нужно взглянуть на содержимое этих пакетов
Пакеты (Ассиметричное шифрование)
Открываем WireShark — ставим фильтр на UDP протокол и делаем попытку авторизации.
Шифрование (Кто бы мог подумать что мы его найдем)Клиент отправляет на сервер зашифрованный пакет с фиксированным размером (273 байт) и получает незашифрованный пакет от сервера. Выполнив несколько попыток авторизоваться, я решил сравнить пакеты:
Помеченные байты не меняются (только незначимые 1–2 байта) Структура пакета получается следующей:
HEADER => [0x01, 0x00, 0x00, 0x04, 0x01, 0x31, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02]
BODY => [? ? ? ? ?]
FOOTER => [0x02, 0x00]
Размер тела пакета равна 256 байт * 8 = 2048 бит (вспоминаем о публичном ключе RSA-2048)
Динамический Анализ
Открываем наш любимый x64dbg и ставим 2 брекпоинта на экспортируемые функции ws2_32 [send / sendTo]
Отлично (это тот самый пакет который отправляется на сервер)Теперь нужно найти функцию шифрования которая шифрует данные авторизации. Изучив call stack, я нашел эту чудесную функцию которая принимает наш буфер и размер 0×100:
Тело сообщения это Json Объект.
К слову body имеет тоже свою структуру, но углубляться в это я не буду.
Как это работает?
Авторизация работает с использованием ассиметричного шифрования (RSA-2048) пакет имеет свою кастомную структуру.
После успешной авторизации клиент переключается на симметричное шифрование по заранее согласованному сеансовому ключу.
Шифрование (Симметричное шифрование)
После успешной авторизации, от сервера прилетает зашифрованный пакет и тут включается симметричное шифрование.
Немного проанализировав функции я нашел функцию которая отвечает за дешифровку пакета
Сигнатура функции выглядит приблизительно вот так
Пример вызова такой функции (caller)
Все что нам нужно это сделать сплайсинг данной функции.
Сплайсинг (от англ. splice) — метод перехвата API функций путём изменения кода целевой функции. Вместо них вставляется переход на функцию, которую определяет программист.
Для начала нам нужно вызвать оригинальную функцию дешифровки.
После этого прочитать [ptr* dest]
Я решил написать свою Dll на C++ чтобы сделать трамплин функции
Не забываем о соблюдении соглашении при вызове (__cdecl / __fastcall / __thiscall)
Получаем адрес функции через GetModuleBaseAddress + RVA
Делаем сплайсинг функции
Итог
Инжектим dll в процесс игры (я использовал CE).
Выполняем авторизацию в игру и наслаждаемся.