Как сделать чит (пакетчик) на примере авто-спама для Blood and Soul.
А точнее в статье описан способ реализации читов на основе использования функций игрового клиента. А если ещё точнее, то описан метод создания пакетчика на примере спамера :)
Недавно получил заказ на создание авто-спамилки для игры Blood and Soul с сохранением моего права на его распространение. Штука не особо востребованная, поэтому решил рассказать вам на примере реализации спамера о довольно интересном методе создания читов для игр. Ну и в целом статья поможет вам понять ход мыслей программиста при создании нужного чита.
Ссылки на инструменты я дам в конце статьи.
Итак, задача - Научиться программным способом постить в чат свои сообщения. Защита игрового клиента не даёт использовать кликеры, поэтому этот вариант сразу опустим. Можно, конечно, рыть защиту или просто заюзать мой обход для неё - но в контексте статьи эти варианты не интересны. Первым вариантом реализации поставленной задачи в голову приходит, разумеется, "пакетный" способ. Иными словами мы можем разобрать сетевой протокол клиент-серверного взаимодействия BS и отталкиваясь от этого генерить нужный пакет для посылки сообщения в чат. Как его слать? Можно через WPF, можно сделать DLL, которая бы хукала какую-либо wsock API для определения сокета и просто в цикле слала бы в сокет ваш пакет. Но это уже второе дело, сейчас главное найти вариант хотя бы вручную постить сообщения в чат без мышки и клавы :)
Для начала пробуем определить какими пакетами осуществляется пост сообщений в чат. Для этого нам требуется перехватить исходящие пакеты игрового клиента. Как? Вариантов много - начиная со сниффера, заканчивая API-шпионами и дебаггерами. Я выбрал третий вариант, т.к. у него просто больше возможностей чем у остальных. Из дебаггеров я выбрал, разумеется, ollydbg. Аттачимся к игре и ставим бряк на send():
Далее постим в чат, например, "aaaa", после чего срабатывает наш breakpoint:
В стеке мы имеем аргументы, с которыми вызывался send. Из них вытаскиваем адрес пакета и его длину. Вот таким образом разным текстом и в разные чаты шлём несколько сообщений и ловим соответствующие пакеты. Вот несколько пакетов чата:
Меняя тип чата, длину текста и перелогиниваясь мы можем по пакету понять, какой байт за что отвечает. Исходя из этого набора пакетов я делаю следующие выводы на примере последнего пакета:
B4 A9 CB D5 A6 0F FB 76 38 00 00 00 00 00 00 00 FF FF FF FF 00 00 00 00 05 00 61 00 61 00 61 00 61 00 .......
B4 A9 CB D5 - неизвестная составляющая, которая в рамках сессии периодически меняется.
A6 0F FB 76 - не меняется. Видимо, ID персонажа или аккаунта - для нас не важно, главное, что константа.
38 00 00 00 - если посмотреть на второй скриншот, то видно, что это длина пакета минус 4. Это нам говорит о том, что первые 4 байта идут как бы отдельно от тела пакета и несут иной функциональный смысл.
00 00 00 00 FF FF FF FF 00 00 00 00 - константы. Не известно что, но нам впрочем и не важно.
05 - это тип чата! Видно, что в пакете для общего чата и локации этот байт отличается
00 61 00 61 00 61 00 61 ... - это сам текст в юникоде.
Вот тут мы сталкиваемся с главной проблемой, которая весьма усложняет поставленную задачу. Мы не знаем как генерируются первые 4 байта и для чего они нужны. Вероятно, они призваны защитить игру как раз от инжекта чужих пакетов. Что делать дальше? У нас два варианта - либо копать игру дебаггером в поисках места, где генерируется эти 4 байта, либо искать другой вариант решения задачи. Проблема первого варианта в том, что в алгоритме генерации этих 4 байт могут быть забиты такие величины, из-за которых наши пакеты внесут ассинхронизацию генерации этих байт между сервером и клиентом. Сложно, да? :) Ну допустим этот код генериться через каждые 3 отосланных пакета. Клиент и сервер абсолютно точно знают, когда его генерировать снова. Если мы вдруг шлём свой пакет в обход клиента, то клиент о посылке знать не будет, а сервер будет - отсюда последствия в виде ассинхронизации и дисконнекта. Вроде понятно объяснил.. Чтобы избежать подобных вероятных проблем, можно не генерировать свой код, а воспользоваться непосредственно клиентской функцией, которая его генерирует! Как найти эту самую функцию? Точно также, через дебаггер. Я не зря выше писал о причине использования дебаггера вместо сниффера и апи-шпиона.
Итак, снова брякаемся на send() и смотрим стек (тот скриншот №2). Первый же адрес в нём - это адрес возврата в функцию, которая вызвала send(). Точнее олька нам подсказывает, что это функция-член (или метод) ThreadSend класса XClient. Далее отпускаем и ищем этот метод в vEngine.dll, брякаем:
Шлём сообщение в чат и что мы видим? Бряк не срабатывает. Чисто логически это означает, что данный метод зациклен (если исключить варианты защиты от бряков). Да и по его названию можно понять, что это поток, который берёт из некой кучи пакеты и отправляет их в сокет. Побегав по этому методу бряками моя версия подтверждается.
Может показаться, что мы в тупике, потому что мы не знаем какая функция или метод кладёт сгенеренные пакеты в кучу. На самом деле логично предположить, что адрес этой кучи должен быть константным. Снова пару раз брякаемся на send() и видим, что отсылаемый пакет меняется, но всегда лежит по одному и тому же адресу!
В нашем случае это 0x05280264 (смотрите скриншот №2). Дальше всё элементарно! Ставим бряк на запись в память по этому адресу и пишем в чат:
Вуаля! Мы попадаем в метод AddMsg, в котором пакет записывается в эту самую очередь (буду называть её "кучей"). Этот метод в свою очередь вызывается методом Send класса XClient. Брякаемся на нём и постим любимые "aaaaa" в чат:
И вот мы внутри Send, смотрим его аргументы и понимаем, что дело в шляпе. Функция Send принимает два аргумента: отсылаемый пакет и его размер, после чего просто добавляет его в очередь. Если внимательнее посмотрите на пакет, то заметите, что в нём отсутствуют те первые 4 байта, значение которых мы хотели определить. По всей видимости они добавляются к пакету в методе ThreadSend. Но это для нас уже не важно, потому что мы можем слать пакеты через этот самый Send, а неопознанные байты будут добавлены методом ThreadSend.
Теперь перейдём к реализации. Я решил описать этот момент, т.к. там есть пара подводных камней. Первый из которых - это согласование вызовов. Метод Send должен вызываться как __thiscall, ибо это функция-член класса XClient. Подробнее об этом читайте в MSDN. Мы это легко можем определить по коду. Вот как вызывается Send:
Оба аргумента передаются через стек, а вот через регистр ECX передаётся указатель на свой класс. Так какое согласование следует использовать нам? Я пошёл путём использования __fastcall. Данное соглашение о вызовах говорит компилятору о том, что первые два аргумента должны передаваться через регистр ECX (да, да!) и EDX. А остальные через стек. Получается, что прототип функции Send мы можем представить вот так:
Код:
int (__fastcall *vEngine__XClient__Send)(void *This, void *_EDX, void *Src, int Size);
В EDX можно передавать мусор, а вот указатель на класс, к сожалению, должен быть заполнен. Как его найти? Можно тупо через Cheat Engine найти его расположение через указатели, можно хукнуть какой-нибудь из методов этого класса и просто сохранять значение ECX для дальнейшего использования. Тут уже сами, т.к. задача тривиальна.
В итоге код, который шлёт пакет, занимает всего несколько строчек:
Всё гениальное - просто. Точно также в других в играх вы можете обходить, например, шифрование траффика. Обратите внимание, что этим способом вы можете слать любой игровой пакет! Просто в контексте моей задачи я затронул только чат.
Мало того, используя описанный подход, вы можете использовать любую игровую функцию. Допустим, хотите из своего кода атаковать моба с неограниченной скоростью? Не вопрос - точно так же брякаетесь на методе Send и далее по описанному выше сценарию ищите ту функцию, которая отвечает за атаку и вызываете её с нужной вам скоростью. Огромный плюс этого способа написания читов заключается в том, что игровые обновления очень редко на него влияют. Используемая выше функция Send вообще врядли когда-либо будет изменена, таким образом этот пакетчик (и спамилка) будут работать вечно.
Я не оказываю услуги гаранта!
База данных кидал: blacklist.rf-cheats.ru
Обязательно проверяйте человека через чёрный список прежде чем совершать с ним сделку.
То есть я так понимаю теперь можно заменять вещи ?
Теперь НУЖНО заменять вещи!
Добавлено через 23 минуты
Цитата:
Сообщение от dark
Иными словами мы можем разобрать сетевой протокол клиент-серверного взаимодействия BS и отталкиваясь от этого генерить нужный пакет для посылки сообщения в чат. Как его слать? Можно через WPF, можно сделать DLL, которая бы хукала какую-либо wsock API для определения сокета и просто в цикле слала бы в сокет ваш пакет. Но это уже второе дело, сейчас главное найти вариант хотя бы вручную постить сообщения в чат без мышки и клавы :)
Я кстати ваще не парился когда спамер на BS у меня заказывали, обычный winsocks Send похукал и все. Ты кстати по чем спамер на БС продаешь? Под хайдом чиркани.
Последний раз редактировалось Тигрь; 30.09.2014 в 18:40.
Причина: Добавлено сообщение
Я кстати ваще не парился когда спамер на BS у меня заказывали, обычный winsocks Send похукал и все. Ты кстати по чем спамер на БС продаешь? Под хайдом чиркани.
то есть ты эти первые 4 байта разобрал как генерить?
А спаммер делал на заказ за 10к. Больше никому не продавал.
Я не оказываю услуги гаранта!
База данных кидал: blacklist.rf-cheats.ru
Обязательно проверяйте человека через чёрный список прежде чем совершать с ним сделку.
А точнее в статье описан способ реализации читов на основе использования функций игрового клиента. А если ещё точнее, то описан метод создания пакетчика на примере спамера :)
Сообщений этому человеку за его труды!!!!
Последний раз редактировалось dark; 01.10.2014 в 09:47.
то есть ты эти первые 4 байта разобрал как генерить?
А спаммер делал на заказ за 10к. Больше никому не продавал.
Да там в этих байтах размер пакета закодирован. У меня они не менялись от сессии к сессии если одинаковый пакет слать. Хз мож щас чо то изменилось. У меня чел покупал спамер за 1к в месяц. А потом он забил на торговлю в BS и я забил на спамер. Там к стати его потом банить стали по железу за спам, я еще обход бана по железу делал.
Я не оказываю услуги гаранта!
База данных кидал: blacklist.rf-cheats.ru
Обязательно проверяйте человека через чёрный список прежде чем совершать с ним сделку.
Я не оказываю услуги гаранта!
База данных кидал: blacklist.rf-cheats.ru
Обязательно проверяйте человека через чёрный список прежде чем совершать с ним сделку.