Гайд Реверс инжиниринг игр: Создание логгера пакетов для Dragomon Hunter

Модератор раздела «Создание читов CS2»
Модератор
Статус
Оффлайн
Регистрация
21 Июн 2022
Сообщения
148
Реакции[?]
365
Поинты[?]
151K



Вступление:
В своем посте я покажу, как отреверсить и создать логгер, и редактор пакетов для игры Dragomon Hunter. Может быть, в будущем посте я продемонстрирую, как отправлять свои собственные пакеты. Начиная с пакетов, это самый простой способ найти необходимые функции для создания бота, который может двигаться, покупать предметы, находить эксплоиты и все остальное, что вы хотите сделать.

Dragomon Hunter — это новая MMORPG, выпущенная компанией Aeria Games. Методология, используемая здесь, может быть применена к любой игре, хотя большинство игр сегодня поставляются с очень навязчивыми анти-читом, такими как nProtect GameGuard, AhnLab HackShield или XIGNCODE3. Эти анти-чити функционируют подобно антивирусу, сканируя известные образцы обнаруженных читов и закрывая игру, если вы запускаете любой тип ПО, которое она считает читерским. Они также обычно имеют драйвер режима ядра, который мешает использованию программ для анализа, такого как Ollydbg или Cheat Engine, зацепляя определенные API в Ring 0, чтобы остановить вас от использования API, таких как OpenProcess, ReadProcessMemory и WriteProcessMemory в Ring 3 (эти API часто используются для анализа). Кроме того, эти анти-читы используют техники анти-отладки и запускают сканирование целостности памяти, чтобы убедиться, что вы не модифицировали код анти-чита или защищаемой игры.

Легкий способ обойти эти анти-читы — остановить их работу, но в 95% случаев, примерно через 1-5 минут после начала игры, вы будете отключены от игрового сервера. Это происходит потому, что у большинства анти-читов есть так называемый «пакет сердцебиения» (heartbeat packet), чтобы убедиться, что анти-чит все еще работает. Сервер отправляет пакет на ваш клиент с некоторыми данными, который затем вызывает функцию анти-чита для запуска некоторого алгоритма в зависимости от античита, возвращает правильные данные, а затем данные отправляются обратно на сервер. Если данные, отправленные обратно на сервер, неправильные или вообще не отправлены, вы будете отключены. Это работает аналогично тому, как программное обеспечение, которое вы можете установить, требует лицензионный ключ. Если вы вставите неправильный ключ, программа не будет работать. Однако в случае с этими анти-читами код обычно сильно затруднен для понимания и запускается под виртуальными машинами с пользовательским байт-кодом, что делает алгоритмы очень сложными для реверс-инижиниринга.
Вы можете прочитать больше о том, как это работает, в статье, написанной специально для nProtect Gameguard E.T. на форуме unknowncheats.me здесь:
Пожалуйста, авторизуйтесь для просмотра ссылки.
.
В будущей статье блога я расскажу о моем анализе и способах обхода анти-чита XIGNCODE3, также известного как самопровозглашенный «World's #1 Anti-Cheat» (одна из строк, на которую ссылается античит...).
Dragomon Hunter — это MMORPG, переполненная ботами, которые фармят золото, не имеющая какого-либо анти-чита, не упакованная и не содержащая зашифрованный код, и я решил, что это хороший способ для тех, кто хочет научиться обращаться с онлайн-играми и реверс-инижинирингу в целом. Итак, приступим!

Примечание: 28.01.16 числа Aeria Games добавила XIGNCODE3 в Dragomon Hunter, который не позволит вам выполнить анализ, показанный ниже. В настоящее время не существует пакета «heartbeat», который можно было бы легко обойти, найдя функцию, инициализирующую XIGNCODE3, и изменив ее так, чтобы она возвращала значение true, не выполняя инициализацию. (Так же просто, как поместить mov eax, 1 и return в начало функции.)

Что вам потребуется:
  • Знания x86 Assembly, Reverse Engineering, а так же Win32 APIs;
  • Аккаунт Aeria Games (
    Пожалуйста, авторизуйтесь для просмотра ссылки.
    );
  • Dragomon Online (
    Пожалуйста, авторизуйтесь для просмотра ссылки.
    );
  • Ollydbg (актуальной версии) (
    Пожалуйста, авторизуйтесь для просмотра ссылки.
    );
  • IDA Pro (
    Пожалуйста, авторизуйтесь для просмотра ссылки.
    );
  • IDA Function String Associate Plugin by Sirmabus (
    Пожалуйста, авторизуйтесь для просмотра ссылки.
    );
  • Keygener Assistant v2.0 (
    Пожалуйста, авторизуйтесь для просмотра ссылки.
    ).
Анализ:
Примечание: если бы мы анализировали какой-то вредоносный код, процесс, который я демонстрирую ниже, был бы иным и должен был выполняться в VMWare, чтобы не заразить ваш компьютер. Однако, поскольку это исходит из доверенного источника — Aeria Games, в этом случае это не требуется.
Во-первых, пожалуйста, убедитесь, что Dragomon Hunter обновлен до последней версии, запустив лаунчер.



Откройте Keygener Assistant, нажмите на вкладку «Scanning» и найдите файл Game.bin в папке, в которую вы установили Dragomon Hunter. Убедитесь, что выпадающее меню «Files of type:» имеет выбранный вариант «All Files», иначе вы не найдете файл в Keygener Assistant, как показано на фотографии ниже (несмотря на расширение .bin, это .exe файл согласно PE заголовку).


Keygener показывает нам, что файл Game.bin не упакован и дает нам смещения всех обнаруженных им хэш и криптографических сигнатур, а также используемый компилятор. Давайте поместим игру в IDA Pro, чтобы продолжить наш анализ.



IDA Pro правильно анализирует игру, код не кажется зашифрованным.



Секция импортов на месте и не зашифрована.



Строки, кажется, тоже не зашифрованы.
В большинстве случаев, если вы анализируете вредоносное ПО вместо игры, вам нужно будет провести дополнительный анализ, чтобы подтвердить вышеизложенное.

Игра, по всей видимости, создана с использованием Gamebryo Game Engine (
Пожалуйста, авторизуйтесь для просмотра ссылки.
), на основе предыдущих знаний об играх, которые я получил за годы исследований, а также по ссылочным строкам в IDA, как показано на фото ниже.



Когда я анализирую онлайн-игры, одной из первых вещей, которые мне нравится делать, является запуск плагина IDA Function String Associate, созданного Sirmabus. Этот плагин создает комментарий в верхней части каждой функции, который содержит ссылочную строку («referenced string»). В IDA нужно нажать ALT+6, и появится меню этого плагина, показанное на фотографии ниже.


Нажмите «Continue», и плагин начнет анализ. Это может занять некоторое время, так как игры могут быть очень большими. Эта игра всего около 14 МБ, поэтому это не должно занять много времени. Затем вы должны увидеть комментарии над каждой функцией, которая ссылается на строку, как показано ниже.



Теперь, когда мы разобрались со всем этим, давайте перейдем к нашей основной цели — созданию редактора пакетов. Вопрос: с чего начать? Есть множество различных путей, которые мы можем выбрать, чтобы найти функции для отправки и получения пакетов.
Один из методов, который можно использовать — найти указатель на некоторый элемент, такой как координаты игрока, который, вероятно, будет использоваться в пакете, отправляемом на сервер. Затем вы можете найти код, который обращается к этому указателю, переместить своего персонажа и проследить до тех пор, пока вы не найдете код, ответственный за отправку пакета с движением игрока.
Лучший метод — начать с конца. Что я имею в виду? Поскольку мы работаем в Windows, последнее место, куда пакет попадет, если мы отправляем его, или первое место, где он появится, если мы получаем его, будет одной из функций Winsock, экспортированных из ws2_32.dll. Поэтому я продемонстрирую, как отслеживать обратно от одной из этих функций до момента, когда пакет зашифрован при отправке, и, возможно, в будущем опубликую пост о том, как регистрировать полученные пакеты после их расшифровки.

Winsock APIs отправки:
Winsock APIs получения:
Теперь давайте проверим, какие из этих функций импортирует игра. (Самый простой способ — отсортировать импорты в «Library» в IDA и прокрутить вниз до WS2_32)


Здесь мы видим, что игра использует функцию WSASend для отправки пакетов и функцию WSARecv для получения пакетов.
Начнем с функции отправки пакета, рассмотрев ссылки на WSASend.


Похоже, что есть две функции, которые вызывают WSASend. Давайте посмотрим на то, что я нашел в первой функции.


Если WSASend завершается с возвращаемым значением -1 или 0xFFFFFFFF в шестнадцатеричном формате, то он продолжит выполнение до WSAGetLastError и вернется из этой функции со значением 0, что означает, что функция вернула false, что, вероятно, приведет к закрытию игры из-за ошибки пакета. Если WSASend возвращает 0, что означает, что пакет был отправлен правильно, игра перейдет и выполнит код ниже.

Ниже вызова WSASend есть вызов WSAAsyncSelect. Я предполагаю, что при запуске игры может быть открыто более одного соединения, возможно два, поскольку есть две функции, которые вызывают WSASend. Учитывая, что параметр для количества буферов на WSASend всегда равен 1, игра также могла бы использовать WSAAsyncSelect, чтобы сообщить игре, что пакет был отправлен успешно, и отправить следующий пакет, а также сохранить порядок пакетов.

Строка, в которой написано mov [esi+288Ch], eax перед вызовом WSAAsyncSelect, также интересна. Возможно, это некий мьютекс или член структуры или класса сети, который должен быть установлен перед отправкой другого пакета.
Давайте посмотрим на вторую функцию, которая вызывает WSASend.


Здесь мы можем увидеть что-то, похожее на первую функцию. Если мы посмотрим выше в функции, мы увидим еще один вызов WSAAsyncSelect.


Ещё раз, мы находим, вероятно, тот же член какого-то класса или структуры сети, расположенный по указателю +0x288C. Я указываю на этот член, потому что, возможно, мы могли бы установить брикпоинт (точку останова) через Ollydbg по этому адресу и трассировать(отследить) член указателя сети.

На этом этапе я хотел бы начать анализировать игру динамически, используя Ollydbg. Так что загрузите игру и присоедините Ollydbg к Game.bin.

Установите брикпоинт на WSASend, как показано ниже. (Вы можете использовать горячую клавишу F2 в Olly для установки брикпоинта)


Обычно я трассирую, используя функцию чата в игре. Введите «hello» в игру и нажмите enter. Ollydbg остановится на WSASend, и вы должны увидеть что-то похожее на фото ниже в стеке. Также убедитесь, что вы не ставите брикпоинт слишком долго, иначе вы будете отключены от сервера.

Теперь давайте проверим, зашифрованы ли пакеты. Следуйте по адресу к указателю массива WSABUF (pBuffers). В моем случае это будет 0x0018FC10.
Вот как выглядит структура WSABUF на C++:


«len» — это длина буфера, а «buf» — указатель на буфер. Поскольку у нас есть только один буфер (nBuffers = 1, что также показано ранее в IDA), массив будет выглядеть следующим образом:
0x0018FC10 (pBuffers) + 0x00 = длина буфера (0x0018FC10)
0x0018FC10 (pBuffers) + 0x04 = указатель на буфер (0x0018FC14)

Почему мы добавляем 4, чтобы получить указатель на буфер? unsigned long в 32-битном ПО занимает 4 байта. Указатель на буфер также имеет размер 4 байта.


Здесь мы видим, что буфер имеет размер 0x19 или 25 в десятичном формате. Буфер хранится по адресу 0x180C4940. Теперь давайте следовать за буфером в просмотре памяти. Я ввел «hello» в чат, поэтому, если мы можем увидеть это в открытом виде там, где хранится буфер, это может означать, что пакеты не зашифрованы и наша задача по ведению логгера отправленных пакетов может быть окончена.


Похоже, что пакет скорее всего был зашифрован, так как в разделе ASCII секции просмотра памяти нельзя увидеть слово «hello». Это часто бывает в онлайн-играх в наши дни, хотя я видел сегодня несколько игр, которые все еще не шифруют свои пакеты.

Вот что произошло, когда я снова ввел «hello».


Хорошо, это интересно. Кажется, что шифрование использует вектор инициализации (IV) или начальную переменную (SV), поэтому вывод буфера не всегда одинаков, даже если мы отправляем одинаковый пакет с одинаковыми данными, но первые два байта буфера были одинаковыми (0x17 0x00).

Давайте попробуем отправить «hello1» и посмотрим, что произойдет.


17 00 было изменено на 18 00, что, вероятнее всего, означает, что первые два байта структуры пакета — это размер пакета.

Теперь, когда мы знаем, что пакеты зашифрованы, мы собираемся попытаться проследить за функцией, которая принимает буфер перед его шифрованием и размер буфера, чтобы мы могли поместить свой хук здесь для регистрации отправляемых пакетов на сервер. Обычно лучшее место для этого — прямо перед вызовом функции, которая шифрует буфер. Чтобы сделать это, давайте снова установим брикпоинт на WSASend, отправим пакет чата и посмотрим на стек, чтобы найти адрес возврата функции. Адрес возврата будет значением в верхней части стека, как показано выше на фотографии, где мы первый раз установили точку останова на WSASend.

Ollydbg показывает, что вызов был выполнен из второй функции, которую мы анализировали в IDA. Следуйте за этой функцией, пока не будет возврата, чтобы увидеть, откуда был вызов функции.


Если пакет был успешно отправлен, функция прыгает к концу, и если мы продолжим трассировку, мы окажемся в обратном вызове WindowProc. Отсюда не выглядит так, будто мы сможем отследить буфер до его шифрования.

Скорее всего, игра использует оконное сообщение для уведомления о том, готов ли пакет к отправке или уже был отправлен. Было несколько случаев, когда использовалась WSAAsyncSelect с параметром сообщения 0x9C40 для отправки оконного сообщения, и на фотографии выше вы можете увидеть вызов PostMessageW с другим параметром сообщения 0x9C41. Поскольку PostMessageW выше выполняется только в том случае, если пакет не был отправлен, я полагаю, что сообщение 0x9C41 уведомляет игру о том, что пакет не был отправлен.

Давайте установим точку останова на WSAAsyncSelect.


Перейдите по адресу, который вызывает функцию WSAAsyncSelect в Ollydbg. Давайте рассмотрим эту функцию.



Эта функция выглядит интересной из-за вызова WSAAsyncSelect и указателя, предположительно для их сетевого класса / структуры, найденного здесь в ESI, который также найден в функции, которая вызывает WSASend.

Исходя из моего опыта и чтения кода, вызывающее соглашение этой функции является «thiscall», так как сетевой указатель передается в ESI через регистр ECX в начале функции, и у нее есть еще один параметр, который можно увидеть по RETN 4 в конце функции. Keygen Assistant сообщил нам, что игра была скомпилирована с использованием MSVC++, что означает, что указатель «this», также известный как наш сетевой указатель, передается в ECX, а функция отвечает за очистку стека.
Если мы прочитаем код ассемблера, то кажется, что второй параметр является указателем на структуру.

Установим точку останова в начале функции и проанализируем параметр, который помещается в стек.


На фото выше показан указатель на структуру. Я объясню, как выглядит эта структура ниже, но сейчас, если мы следуем за вторым элементом структуры в просмотре памяти, давайте глянем, что мы получим.


Смотрите! У нас есть буфер пакета до его шифрования. Также в начале пакета, когда мы отправляли «hello» и смотрели на зашифрованный буфер, есть 0x0017 — размер буфера.

Структура выглядит так: первый параметр может быть хэшем буфера или идентификатором типа, используемым для очистки позже, второй элемент указывает на начало буфера, третий элемент — указатель на конец буфера, и четвертый элемент, похоже, может быть указателем на конец памяти, выделенной для буфера. Если мы вычтем из третьего элемента второй элемент (0x0E680279 - 0x0E680260), мы получим 0x19, что является размером всего буфера, включая первые два байта, которые в конечном итоге считывает сервер.

Давайте проверим, чтобы убедиться, что это действительно буфер до его шифрования. Изменим «hello» в представлении памяти на «hell1» и посмотрим, что появится в игре.




Похоже, мы успешно изменили буфер до его отправки на сервер, поскольку в игре не появляется сообщение до получения пакета чата.
Чтобы создать регистратор пакетов отсюда, вы можете просто разместить переход на обратный вызов в вашем коде, который будет печатать содержимое пакетов. Похоже, наша работа здесь завершена!

Что можно сделать с этим?
Теперь, когда вы успешно можете записывать и изменять пакеты, вы можете анализировать и изменять данные, отправляемые между вашим клиентом и сервером. Вы можете пойти еще дальше и выяснить, как отправлять свои собственные настраиваемые пакеты или даже создать свой собственный игровой клиент, развернув шифрование пакетов. (Подсказка: функция шифрования вызывается непосредственно в функции, которую я продемонстрировал выше.) Это часто приводит к обнаружению уязвимостей в игре, отправляя данные, которые обычно не отправляются игровым клиентом, для выполнения задач, не предусмотренных разработчиком игры. Вы также можете использовать пакеты для отслеживания функций, таких как чат, перемещение, покупка предметов и многого другого, вызывая игровые функции непосредственно, а не отправляя нажатия клавиш.

Я продемонстрирую простой и очень распространенный эксплоит, найденный в онлайн-играх, который я нашел во время написания этого поста. В большинстве современных онлайн-игр существует некоторый вид фильтра матерных слов, потому что создатели игр не хотят, чтобы вы ругались в чате с другими игроками.
Вот что происходит, если мы скажем слово «shit» в игре.




Игра сравнила текст, который я написал, с фильтром матерных слов и заменила его на что-то непонятное(мусор). Посмотрим, что произойдет, если я изменю буфер и напишу слово «shit».





Вывод:
Компании, занимающиеся играми, так же как и любые другие компании, должны уделять больше внимания кибербезопасности. Лучшая практика — давать конечному пользователю наименьшее количество контроля над тем, что они могут делать. Вместо того, чтобы фильтр матов контролировался клиентом игры, он должен контролироваться сервером. Всегда будут люди, пытающиеся использовать уязвимости, атаковать и взламывать, что может быть предотвращено только с помощью хорошей защиты. Компании, занимающиеся играми, часто получают множество жалоб на хакеров, читеров и ботов, что, в свою очередь, приводит к тому, что игроки уходят из игры, что означает потерю денег для компании. К сожалению, большинство компаний не склонны тратить деньги или уделять внимание безопасности. Они часто ставят один из анти-читов, упомянутых выше во введении, для борьбы с читерами. Эта практика обычно останавливает только самых неопытных хакеров, и вместо этого следует больше фокусироваться на безопасности своих серверов.

Надеюсь, вам понравилось и, возможно, вы узнали что-то новое из этого поста.

Для просмотра содержимого вам необходимо авторизоваться.
 
Последнее редактирование:
Легенда форума
Статус
Оффлайн
Регистрация
10 Дек 2018
Сообщения
4,219
Реакции[?]
2,184
Поинты[?]
84K
Хороший перевод, хорошее оформление, хороший текст без нехороших машинных конструкций.
Хорош.
 
Пользователь
Статус
Оффлайн
Регистрация
9 Июн 2020
Сообщения
457
Реакции[?]
59
Поинты[?]
0
спасибо за статью, интересно почитать
 
Пользователь
Статус
Оффлайн
Регистрация
6 Янв 2019
Сообщения
218
Реакции[?]
73
Поинты[?]
5K
Хороший, структурированный гайд +rep :seemsgood:
 
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
Пользователь
Статус
Оффлайн
Регистрация
10 Июн 2017
Сообщения
677
Реакции[?]
117
Поинты[?]
0
Ай умничка, рад что ты на модерку встал
 
Болотная зелибоба.
Начинающий
Статус
Оффлайн
Регистрация
13 Ноя 2020
Сообщения
91
Реакции[?]
8
Поинты[?]
0
Внатуре чётко
 
Keep Ev0lving, Stay Fatal
Эксперт
Статус
Оффлайн
Регистрация
6 Фев 2018
Сообщения
1,539
Реакции[?]
573
Поинты[?]
89K
Теперь не "Почти как в хо-яв".
Теперь "Гугл транслэйтор каэсго".ф
 
Начинающий
Статус
Оффлайн
Регистрация
31 Янв 2018
Сообщения
10
Реакции[?]
2
Поинты[?]
0
Хороший перевод, сразу и не понял что перевод. Что могу сказать, текст сложен для того кто не так сильно разбирается в этой теме, но думаю что для узконаправленный лиц будет полезно.
И ещё раз спасибо за перевод)
 
Сверху Снизу