Пишем бота для MMORPG с ассемблером и дренейками. Часть 4.5

в 1:59, , рубрики: .net, c#.net, game development, mmorpg, reverse engineering, world of warcraft, боты, игры, Программирование, реверс-инжиниринг

Пишем бота для MMORPG с ассемблером и дренейками. Часть 4.5 - 1 Привет %username%! Сделаем небольшую остановку, что бы расставить все точки над «и», понять что к чему и как работает. За последнее время, я получил очень много вопросов связанных с офсетами для различных версий World of Warcraft, множество предложений по способам реализации инъекции сторонних инструкций в игровой процесс и теперь настало время это все обсудить. Если есть вопросы или предложения, добро пожаловать под кат!

Disclaimer: Автор не несет ответственности за применение вами знаний полученных в данной статье или ущерб в результате их использования. Вся информация здесь изложена только в познавательных целях. Особенно для компаний разрабатывающих MMORPG, что бы помочь им бороться с ботоводами. И, естественно, автор статьи не ботовод, не читер и никогда ими не был.


Содержание

  1. Часть 0 — Поиск точки внедрения кода
  2. Часть 1 — Внедрение и исполнение стороннего кода
  3. Часть 2 — Прячем код от посторонних глаз
  4. Часть 3 — Под прицелом World of Warcraft 5.4.x (Структуры)
  5. Часть 4 — Под прицелом World of Warcraft 5.4.x (Перемещение)
  6. Часть 5 — Под прицелом World of Warcraft 5.4.x (Кастуем фаерболл)

1. Вопросы и ответы
Самый часто задаваемый вопрос, это «почему ассемблер?». Складывается ощущение, что у людей при слове ассемблер начинается паническая атака, закладывает уши и отключается мозг. Не нужно его боятся на столько, он не так страшен. Ведь что может быть проще, чем попросить саму программу выполнить свою же функцию и результат поместить по указателю который вы знаете? Не нужно изобретать велосипед, я использую, то что есть. Смотрите как просто вызвать внутреннюю функцию DoAnythingFunction имея на нее указатель DoAnythingFunctionPointer на ассемблере

"call " + GetAnyGameObjectFunctionPointer,
"push " + argument3Pointer,
"push " + argument2Pointer,
"push " + argument1Pointer,
"push " + argument0Pointer,
"mov ecx, eax",
"call " + DoAnythingFunctionPointer,
"retn"

GetAnyGameObjectFunctionPointer — возвращает нам какой-либо объект, указатель на него будет помещен в eax
argument[N]Pointer — указатель на N-ый аргумент для DoAnythingFunction.

Затем идет вопрос, о DLL injection. На battle.net сервере, это потенциально опасный способ, т.к. ваша DLL может уйти на исследование в отдел по защите. Ведь это самый распространенный подход как в читерстве так и в ботоводстве внедрить свою DLL. И помните, популярность подхода, прямо пропорциональна вероятности попасться.

Следующий вопрос, это «почему не c++?». Это уже дело вкуса. Если вы можете сделать лучше и быстрее на c++ — делайте, но на данный момент, я кроме неконструктивной критики подхода ничего не увидел. Ни одного примера реализации на c++. Ведь странно, когда все могут и никто не делает.

Еще интересный вопрос «почему не x64?». Если поднять 4 виртуалки с win7 x86 и запустить бота на каждой, при этом ресурсов потреблять от хост-машины они будут меньше чем win7 x64. Ну и вообще мне индифферентно на какой платформе бегает бот, да и ему тоже. Этот вопрос актуален будет при написании читов, когда сам играешь.

На все остальные вопросы ответ будет следующим: «За последние 4 года на battle.net сервере, я ни разу не получил бан или предупреждение»

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

2. Поиск офсетов
Для поиска офсетов, я предпочитаю поиск по маске. Естественно, что самый лучший способ найти указатель на функцию — это отладка и только она даст 100% гарантию, что вы нашли именно то, что нужно. Но это процесс может быть очень утомительным и долгим, да и как для новичков в 5 статей объяснить про отладку, брейкпоинты и дизассемблер, когда и так почти ничего не понятно, как я заметил. Поэтому я использую в статье поиск по маске. Давайте рассмотрим все на примере. Для начала скачаем 2 разных файла Wow.exe, одной мажорной версии (я взял 5.4.7 17898 и клиент WowCircle-32.exe 5.4.7 18019). Наша задача найти офсеты для Морфера при этом офсеты для 17898 нам известны:

CGUnit_C__UpdateDisplayInfo = 0x42E3A8,
CGUnit_C__OnMountDisplayChanged = 0x42E193,
CGUnit_C__UpdateScale = 0x424AE3,

Открываем в IDA Wow.17898.exe, ждем пока он загрузится, скроллим в самый верх, смотрим Imagebase = 400000 и запоминаем это значение.
Пишем бота для MMORPG с ассемблером и дренейками. Часть 4.5 - 2
Затем жмем G и переходим по адресу CGUnit_C__UpdateDisplayInfo + Imagebase = 0x82E3A8
Пишем бота для MMORPG с ассемблером и дренейками. Часть 4.5 - 3
Открываем его в Hex-View нажатием Alt+3, копируем первых 15 байт — это первые 8 инструкций в функции, которые не изменятся при компиляции, т.е. избегаем команд типа jxx xxxx, push offset xxxx, call xxxx, xxx dword_xxxx и т.д.
Пишем бота для MMORPG с ассемблером и дренейками. Часть 4.5 - 4
После всего запускаем новый инстанс IDA уже для исследуемого файла, жмем Alt+B, вводим скопированную последовательность байт и ищем Ctrl + B, если что-либо нашлось, то нужно сравнить c оригиналом.
Пишем бота для MMORPG с ассемблером и дренейками. Часть 4.5 - 5
Как видите, эти функции идентичны, за исключением указателей на них. Для точности нажмем еще раз Ctrl+B и если ничего не выдало, значит офсет найден. Все может быть гораздо сложнее, когда первые 15-20 байт в функции изменились при компиляции. В этом случае можно поискать в ней статический кусок, который не содержит меток и переходов либо придется заменить некоторые байты вопросами в шаблоне поиска. Вот выдержка из справки по поиску в IDA:

CD 21 — bytes 0xCD, 0x21
21CD — bytes 0xCD, 0x21 (the order depends on the endiannes)
«Hello», 0 — the null terminated string «Hello»
L«Hello» — 'H', 0, 'e', 0, 'l', 0, 'l', 0, 'o', 0
B8???? 90 — byte 0xB8, 4 bytes with any value, byte 0x90

Например для поиска CGUnit_C__UpdateScale я возьму не первые 15 байт, а с 21-го по 35-ый, т.к. там нет нежелательных инструкций. Можно для этих целей так же использовать IDA плагин MakeSig.

P.S. Если у кого-нибудь есть силы и желание написать статью про то, как искать адреса функций отладкой, буду признателен
P.P.S. Ошибки и опечатки в личное сообщение

Автор: 3axap4eHko

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js