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

  • Tutorial
Привет, %username%! Итак, продолжим написание нашего бота. Из прошлых статей, мы научились находить адрес перехватываемой функции для DirectX 9 и 11, исполнять произвольный ассемблерный код в главном потоке игры скрывая его от различных методов защиты и получать информацию об окружающем мире. Другими словами, мы можем совершать осознанные действия в игре. И для начала я предлагаю научиться передвигаться!

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 (Кастуем фаерболл)

Так уж сложилось что и взаимодействие с игровым объектом и перемещение по щелчку в World of Warcraft возможно при клике мыши. Но мы не будем симулировать клики, через WinApi, мы сделаем круче. Мы перехватим то место, где уже клик обрабатывается игрой, как клик на экране, причем он уже будет переведен из координат экрана в координаты игрового мира. Для начала получим адреса некоторых функций, они нам очень понадобятся в процессе, это просто сделать с помощью нашего всеми любимого дебагера IDA:
    public enum FunctionWow
    {
        ClntObjMgrGetActivePlayer = 0x39B615,
        ClntObjMgrGetActivePlayerObj = 0x4FC6,
        FrameScript_ExecuteBuffer = 0x4fd12,
        Spell_C_HandleTerrainClick = 0x38f129,
        FrameScript__GetLocalizedText = 0x414267,
        IsOutdoors = 0x414b53,
        UnitCanAttack = 0x41ad3c,
        CGUnit_C__InitializeTrackingState = 0x41fb57,
        CGWorldFrame__Intersect = 0x5eef7b,
        CGUnit_C__Interact = 0x8D01D0,
    }

    public enum ClickToMove
    {
        CTM = 0x420543,
        CTM_PUSH = 0xD0EEBC,
        CTM_X = 0xD0EF2C,
        CTM_Y = CTM_X+4,
        CTM_Z = CTM_Y+4,
    }

Объявим класс WorldClick:
public enum ClickType
{
    FaceTarget = 0x1,
    Face = 0x2,
    StopThrowsException = 0x3,
    Move = 0x4,
    NpcInteract = 0x5,
    Loot = 0x6,
    ObjInteract = 0x7,
    FaceOther = 0x8,
    Skin = 0x9,
    AttackPosition = 0xa,
    AttackGuid = 0xb,
    ConstantFace = 0xc,
    None = 0xd,
    Attack = 0x10,
    Idle = 0x13,
}

public static class WorldClick
{
    public static void ClickTo(float x, float y, float z, ulong guid, ClickType action, float precision)
    {
        if (Mathf.Abs(x) < 0.1 && Mathf.Abs(y) < 0.1 && (Mathf.Abs(z) < 0.1 && (long)guid == 0L))
            return;
        //память для 3х координат
        var positionAddress = Memory.Process.AllocateMemory(3 * sizeof(float));
        //guid типа ulong в 8 байт
        var guidAddress = Memory.Process.AllocateMemory(sizeof(ulong));
        //значение точности, до которой продолжать движение, я беру 0.5f
        var precisionAddress = Memory.Process.AllocateMemory(sizeof(float));
        if (positionAddress <= 0U || guidAddress <= 0U || precisionAddress <= 0U)
            return;
        Memory.Process.Write<ulong>(guidAddress, guid);
        Memory.Process.Write<float>(precisionAddress, precision);
        Memory.Process.Write<float>(positionAddress, x);
        Memory.Process.Write<float>(positionAddress + IntPtr.Size, y);
        Memory.Process.Write<float>(positionAddress + IntPtr.Size * 2, z);
        var asm = new[]
        {
        "call " + Memory.Process.GetAbsolute(FunctionWow.ClntObjMgrGetActivePlayer ),
         //Проверка на наличие активного игрока
        "test eax, eax",
        "je @out",
         //Получаем указатель на объект - понадобится ниже
        "call " + Memory.Process.GetAbsolute(FunctionWow.ClntObjMgrGetActivePlayerObjAddress),
        "test eax, eax",
        "je @out",
        "mov edx, [" + precisionAddress + "]",
        "push edx",
        "push " + positionAddress,
        "push " + guidAddress,
        "push " + (int)action,
        "mov ecx, eax",
        //Вызываем ClickToMove()
        "call " + Memory.Process.GetAbsolute((int)ClickToMove.CTM),
        "@out:",
        "retn"
        };
        Memory.Hook.InjectAndExecute(asm);
        Memory.Process.FreeMemory(positionAddress);
        Memory.Process.FreeMemory(guidAddress);
        Memory.Process.FreeMemory(precisionAddress);
    }

    public static ClickType GetClickTypePush()
    {
        return (ClickToMoveType)Memory.Process.Read<int>((int)ClickToMove.CTM_PUSH, true);
    }

    public static Vector3 GetClickPosition()
    {
        return new Vector3(
                Memory.Process.Read<float>((int)ClickToMove.CTM_X, true),
                Memory.Process.Read<float>((int)ClickToMove.CTM_Y, true),
                Memory.Process.Read<float>((int)ClickToMove.CTM_Z, true));
    }
}

Ну все, теперь можно бегать по просторам Азерота с помощью:
WorldClick.ClickTo(x,y,z, 0, ClickType.Move, 0.5f);

На сегодня все. Вы узнали много интересного и практичного. Можете проверить это на какой-нибудь пиратке, а если уверены в своей обфускации кода, то можно даже и на официальном сервере побегать, с какой-нибудь стартовой записью, что бы не рисковать. Ведь вдруг сотрудники Blizzard, тоже читают Хабр.
Поделиться публикацией

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 12

    0
    Трололо?
    var positionAddress = Memory.Process.AllocateMemory(3 * IntPtr.Size);
    ...
    Memory.Process.Write<float>(positionAddress, x);
    Memory.Process.Write<float>(positionAddress + IntPtr.Size, y);
    Memory.Process.Write<float>(positionAddress + IntPtr.Size * 2, z);
    Выделили 3 IntPtr, а пихаете float. Это только для x86 их размеры равны.
      +1
      пардон, ошибся)
        0
        У вас по-прежнему 3 ошибки подобного рода.
        Ну и раз вспомнили про sizeof(float), тогда и от magic number
        var guidAddress = Memory.Process.AllocateMemory(8);
        можно избавиться :)
          +1
          Да, статью писал на ночь глядя, а ошибки, обычно в пм пишут…
            –1
            В пм обычно пишут опечатки, а не исправления кода.
              0
              А в чем разница между опечаткой и ошибкой, сделанной просто потому, что устал? Обе сделаны неумышленно, обе нужно исправить и после исправления, комментарии в обоих случаях не будут представлять никакой ценности.
                –3
                Опечатка не влияет на содержание поста.
                  –1
                  Но ошибка в коде, может быть тоже опечаткой.
      0
      А где были взяты все эти структуры, описание структур (объектов в wow)?
        0
        Разные источники, что-то из чужих проектов, что-то из форумов, что-то пришлось выковыривать из бинарика, я уже всего и не помню.
          +1
          Игре почти 10 лет, и в ней мало что менялось за эти годы. Сама игра была разобрана по винтикам плюс в разное время происходили утечки исходного кода, по которым в частности интузиасты воссоздавали серверную часть игры. Очень много информации по реверсу игры, терминологии, внутреннему устройству, методам программирования можно найти на англоязычном ресурсе ownedcore. В разделе варкрафта. Среди постоянных посетителей форума много разработчиков. Не сочтите за рекламу, но аналогов по объёму аудитории и тематике у него нет. P. S. Автору огромное спасибо за его труд. Русскоязычного материала фактически нет. Каждый новичок делает свой велосипед. Спасибо большое.
          0
          Часть 5 — Под прицелом World of Warcraft 5.4.x (Кастуем фаерболл)

          Интересные статьи, продолжения не будет?

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое