Пишем бот для MMORPG с ассемблером и дренейками. Часть 0
Привет, %username%! Покопавшись в статьях хабра, я нашел несколько оных про написание ботов для MMORPG. Несомненно это очень интересные и познавательные статьи, но возможности в них весьма скудны. Что если, например нужно пофармить мобов или руду по заданному маршруту убивая агрессивных мобов, игроков и всех кто будет на Вас нападать по пути, выкрикивая им вслед непристойности, да что б еще и определить не смогли. В общем полная эмуляция среднестатистического MMORPG игрока. Написание макросов для AutoIt, симуляция кликов в окне, анализ пикселей под курсором — это совсем не наш вариант. Заинтриговал? Добро пожаловать под кат! Disclaimer: Автор не несет ответственности за применение вами знаний полученных в данной статье или ущерб в результате их использования. Вся информация здесь изложена только в познавательных целях. Особенно для компаний разрабатывающих MMORPG, что бы помочь им бороться с ботоводами. И, естественно, автор статьи не ботовод, не читер и никогда ими не был.СодержаниеЧасть 0 — Поиск точки внедрения кода
Часть 1 — Внедрение и исполнение стороннего кода
Часть 2 — Под прицелом World of Warcraft 5.4.x (Структуры)
Часть 3 — Под прицелом World of Warcraft 5.4.x (Перемещение)
Часть 4 — Под прицелом World of Warcraft 5.4.x (Фармим руду)
И так с места в карьер.1. Выбор способа реализации внедрения (немного теории)
Определенно нам необходимо внедрить код в процесс игры, который и будет ей управлять. Для это можно модифицировать сам исполняемый файл (это очень легко сделать, но и легко определить и получить бан) или внедрить DLL (это тоже определяется очень просто), но это все не для нас. Наш подход — это внедрение кода, в главный поток процесса, получающего управление и возвращающего его обратно.Для этого нужно найти/придумать точку внедрения, которая будет не столь очевидна для анти-читов и полезна для нас. Таких точек может быть очень много, но по многим причинам, лучшим решением будет внедрение в отрисовку игры, т.е. создание хука для Direct3D. Опять же по многим причинам лучше всего перехватывать EndScene функцию, потому как до ее вызова, все изменения игрового мира и иные расчеты уже произойдут. Вот происходящий процесс внутри для наглядности:…
Отрисовка объектов текущей сцены игры
Вызов подмененной D3D EndScene
Наш код
Вызов оригинальной D3D EndScene
Следующая сцена
…
Сцена в данном ключе это так называемый frame. Другими словами — наш код будет работать с частотой вашего fps.Замечание: fps может быть достаточно высоким значением, по-этому не стоит обрабатывать каждый вызов кода. Думаю достаточно будет 10–15 вызовов в секунду2. Инструментарий
И так план мы наметили, теперь нужны инструменты. Я (как и большинство надеюсь) люблю использовать все готовое. По сему предлагаю обзавестись следующими вещами: Любая IDE где будем писать код на C#
OllyDbg — на мой взгляд лучший дебагер после IDA
HackCalc — калькулятор для пересчета VA (виртуального адреса) в Offset и обратно
SlimDX — DirectX фреймворк для .NET
FlatAsm Managed — библиотека преобразует мнемокоды ассемблера в байткод
3. Поиск точки внедрения
И так со способом разобрались, инструментами обзавелись, теперь нам необходимо понять, куда внедрять наш код.При отрисовке с помощью D3D создается виртуальный объект Direct3D device, который по сути представляет собой VMT (виртуальная таблица методов, которая является указателем на указатель на таблицу методов D3D). Это таблица хранит, опять же, указатели на методы Direct3D, например BeginScene, EndScene, DrawText и т.д. Нас в данном случае интересует только EndScene, т.к. Direct3D device создается в единственном экземпляре, то нам нужно получить указатель на него, а затем получить указатели на таблицу. Опять же нам необходимо определить какой D3D используется в клиенте игры и т.к. вариантов у нас 2 (DX9 и DX11), то решить эту проблему можно простым перебором. Для этого мы и будем использовать SlimDX.В коде processMemory.Read и processMemory.ReadBytes обертки стандартной ReadProcessMemory из kernel32.dllПроверка на DX9:
//Создаем устройство D3D9
var device = new SlimDX.Direct3D9.Device (
new SlimDX.Direct3D9.Direct3D (),
0,
DeviceType.Hardware,
Process.GetCurrentProcess ().MainWindowHandle,
CreateFlags.HardwareVertexProcessing,
new[] { new PresentParameters () });
using (device)
{
//Открываем текущий процесс
var processMemory = new ProcessMemory ((uint)Process.GetCurrentProcess ().Id);
//Считываем необходимый нам адрес расположения в памяти D3D9 функции по смещению 0xA8 от указателя на Com объект
_D3D9Adress = processMemory.Read
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.