Results 1 to 1 of 1
  1. #1
    the-no-name
    the-no-name is offline
    New member
    Join Date
    2010 May
    Posts
    8
    Thanks Thanks Given 
    9
    Thanks Thanks Received 
    1
    Thanked in
    1 Post
    Rep Power
    0

    [VC++] Пишем трейнер на VC++

    Пишем трейнер на VC++
    В этой статье я покажу, как сделать трейнер, используя Visual C++. На написание этой статьи меня подтолкнул тот факт, что когда я пытался найти в инете хоть какую-нибудь информацию о том, как сделать простой трейнер в VC, все, что я находил, были статьи, показывающие примеры на С/С++, а в основном на Delphi и MASM. Казалось бы что в этой ситуации можно было использовать материал статей на С/С++ если бы не одно "но" - сильная привязанность VC++ к классам, в следствии чего некоторые API функции ведут себя не так, как надо. Позже это станет понятно.

    Итак приступим
    Вот что нам понадобится:
    * Сама игра. Я выбрал интересную RPG - Avernum 3
    * Программа типа GameHack или TSearch для поиска нужных нам значений в памяти. Я предпочитаю TSearch, поскольку, на мой взгляд, она наиболее функциональна из всех подобных программ. Хотя дело выбора каждого. (берем отсюда)
    * Visual C++. У меня стоит версия 6.0, поэтому туториал будет сделан на ней. Версия не особо принципиальна, как ты понимаешь

    Разведка:
    Для начала соберем необходимую нам информацию, а именно найдем адреса в которых лежат нужные нам значения. Думаю с этим проблем у Тебя не будет, поэтому приведу уже готовые данные:

    HP первого character'a 0x00C1C050 2 байта
    MP первого character'a 0X00C1C054 4 байта

    HP второго character'a 0x00C1C420 2 байта
    MP второго character'a 0x00C1C424 4 байта

    HP третьего character'a 0x00C1C7F0 2 байта
    MP третьего character'a 0x00C1C7F4 4 байта

    HP четвертого character'a 0x00C1CBC0 2 байта
    MP четвертого character'a 0x00C1CBC4 4 байта

    К нашему счастью игрушка не является DMA, то есть адреса наших переменных останутся неизменными все время. Конечно можно было найти ещё кучу полезных адресов, таких как, к примеру, опыт каждого из персонажей или их характеристики, но это уже дополнения, которые можно будет сделать потом. Сейчас главное понять принцип, а уж наворачивать будем позже.

    Кодинг:
    Приступим к самому главному и творческому процессу - написанию нашего трейнера. Делать будем, конечно, используя API функции, поскольку так будет проще, да и прога будет работать намного быстрее. Вот необходимые нам функции (посмотри их описания в Win32 API reference):
    Code:
     SetTimer
    FindWindow
    GetThreadProcessId
    OpenProcess
    WriteProcessMemory
    GetAsyncKeyState
    KillTimer
    CloseHandle
    Тепeрь создадим новый проект для будующего трейнера. Запусти Visual С и дави File->New. В появившемся окне выбирай тип MFC AppWizard (exe), набери имя проекта - Avernum3tr. Дави Next. Выбирай Dialog based. Next. Тут убери галочки с Active X и About box - они нам нафиг не нужны. Все, дави Finish и получай каркас. Как видишь AppWizard уже сгенерировал диалоговоё окно для нас, как и много кода, инициализирующего много всякой ерунды. Можешь сразу удалить static text и две кнопки с окна - они тоже лишние.

    Разберемся с таймером и его функцией-обработчиком. Чтобы создать таймер, нажми Ctrl+W. Откроется окно MFC ClassWizard - эдакий редактор классов. Выбери следующее на вкладке Message Maps:
    Code:
     Class name - CAvernum3trDlg
    Object ID's - CAvernum3trDlg
    Member functions - OnIntiDialog
    и нажми Edit code. Поскольку эта функция уже создана, попадем на кусок кода этой функции, которая вызывается когда создается наше окно. Там мы и инициализируем наш таймер. Добавляй перед строчкой return TRUE строку:
    Code:
     SetTimer(1, 100, NULL);
    Тем самым, при запуске нашего трейнера, будет создаваться таймер , который будет посылать нашему окну сообщение WM_TIMER примерно 4 раза в секунду (второй параметр). Но раз мы создали таймер при запуске, надо его уничтожить при выходе из трейнера. Дави опять Ctrl+W и добавляй функцию WM_DESTROY (думаю понятно как) и жми Edit code. Пиши там:

    Code:
     KillTimer(1);
    OK, перейдем к обработчику таймера. Ctrl+W и добавляй функцию WM_TIMER и перейди на её код. Вот. Эта функция будет вызываться каждый раз, когда сработает таймер. Как ты уже понял, тут мы будем писать код, который будет отвечать за отлов нажатия нужных нам клавиш и делать то, для чего, собственно, создается трейнер

    Лови приколы:
    Вот мы и подобрались к тому моменту, почему , собственно, многие статьи по написанию трейнера на С/С++ не срабатывали в VC. Попробуй в теле функции ON_WM_TIMER написать функцию FindWindow( и увидишь всплывшую подсказку о параметрах функции:
    Code:
     CWnd *FindWindow(LPCTSTR lpszClassName, LPCTSTR plszWindowName);
    и сравни ее с тем, что нам нужно:
    Code:
     HWND FindWindow(LPCTSTR lpszClassName, LPCTSTR plszWindowName);
    Дело в том, что первый вариант является функцией-членом класса нашего окна (я знаю, чтo это звучит запутанно, но тем не менее) и поэтому возвращает несколько другой тип. Что же делать??? А сделаем мы вот что - создадим свой собственный независимый универсальный класс, который мы будем использовать не только в этой проге. Если у нас будет такой класс, то в следующий раз, когда Ты будешь писать свой следующий трейнер, ты просто добавишь этот класс к проекту, впишешь в тело функции таймера всего пару строчек (позже поймешь почему) и все - готово. Это, друг мой, классы - просто супер возможность ООП. Да, конечно, это займет некоторое время сейчас, но здорово сэкономит его позже. Не веришь - смотри.

    Пальцы веером - лепим класс:
    Справа, в окне выбери вкладку ClassView и кликни на Avernum3tr classes правой кнопкой. Выбери New Class. В появившемся окне выбирай:
    Code:
     Class type Generic Class
    Name CProcess
    и дави ОК и увидишь, что он появился в списке классов нашего проекта. Если Ты нажмешь на значок "+" рядом с названием нашего нового класса, то увидишь там две функции-члена - конструктор и деструктор класса.
    Теперь я покажу как добавить одну функцию, а остальные Ты уже добавишь сам. Жми правой кнопкой на нашем классе и выбирай Add member function. В появившемся окне пиши следующее:
    Code:
     Function Type HANDLE
    Function Declarations cOpenProcess(char *p_ClassName, char *p_WindowName)
    Access Public
    а в тело вбей:
    Code:
     HWND hWindow;
    DWORD pid;
    
    hWindow = FindWindow(p_ClassName, p_WindowName);
    if(hWindow)
    {
    GetWindowThreadProcessId(hWindow, &pid);
    return ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    }
    return NULL;
    У тебя должно получится следующее:
    Code:
     HANDLE CProcess::cOpenProcess(char *p_ClassName, char *p_WindowName)
    {
    HWND hWindow;
    DWORD pid;
    
    hWindow = FindWindow(p_ClassName, p_WindowName);
    if(hWindow)
    {
    GetWindowThreadProcessId(hWindow, &pid);
    return ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    }
    return NULL;
    }
    Таким же макаром пиши следующие функции:
    Code:
     bool CProcess::FindProcess(char *p_WindowTitle)
    {
    if(process==NULL)
    {
    process=this->cOpenProcess(NULL, p_WindowTitle);
    }
    if(process)
    {
    isrunning = TRUE;
    return isrunning;
    }
    else
    return FALSE;
    
    }
    
    bool CProcess::IsRunning()
    {
    return isrunning;
    }
    
    bool CProcess::IsKeyPressed(int key)
    {
    if (IsRunning()) return ((GetAsyncKeyState(key) & 1) == 1);
    return FALSE;
    }
    
    bool CProcess::WriteByteToProcess(DWORD p_Adress, BYTE p_Value)
    {
    DWORD bytes;
    
    if(isrunning)
    {
    return (WriteProcessMemory
    (process, (void*)(p_Adress), (void*)(&p_Value), 1, &bytes) != 0);
    }
    return FALSE;
    }
    Ах да, чуть не забыл - добавь в класс две private переменных (правый click->Add member variable):
    Code:
     HANDLE pocess
    bool isrunning
    Почти финиш:
    Открой во вкладке (справа) FileView файл Avernum3trDlg.cpp и в самом верху (после всех #include'ов напиши:
    Code:
     СProcess game;
    Это создаст глобальную переменную типа CProcess с названием game. Так мы будем общаться с нашим классом и с игрой (через него)

    Теперь вернемся с нашей функции ON_WM_TIMER. Впиши туда вот этот фрагмент - я думаю с его пониманием проблем возникнуть не должно:
    Code:
     bool check;
    
    check = game.IsRunning();
    
    if(!check)
    {
    game.FindProcess("Avernum 3");
    }
    else
    {
    if(game.IsKeyPressed(VK_F4))
    {
    game.WriteByteToProcess(0x00c1c050, 0xFF);
    game.WriteByteToProcess(0x00c1c051, 0x10);
    }
    
    }
    
    if( (!check && GetAsyncKeyState(VK_F4)) )
    {
    MessageBox("Zapusti igru snachala!!!", "lameru", MB_OK);
    }
    
    
    CDialog::OnTimer(nIDEvent);
    Теперь откомпилируй проект и запусти его. Вроде проблем быть не должно - переписывал, вроде, как и у себя. Не запуская игру, нажми F4 - лови ругательства. Теперь запусти игру, создай персонажей... и в игре нажми F4 - получай бонусы здоровья. Остальные опции допиши сам - это тебе как домашнее задание.

    (C) M.A.M.O.H.T

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •