Динамічний розподіл пам’яті в комп’ютерних іграх

29.03.2024 1 хвилин Автор: Lady Liberty

Сьогодні поговоримо на тему динамічного розподілу пам’яті (DMA) в контексті хакінгу ігор. Пояснюється, як у грі “Wesnoth” адреса пам’яті золота гравця змінюється при кожному перезапуску гри через DMA, що ускладнює створення повторно використовуваних хаків. Автори обговорюють, як можна перетворити “випадкові” адреси на консистентні, щоб полегшити розробку хаків, які можна розповсюджувати.

Огляд

Раніше ми змінили золото гравця у Весноті. Щоразу, коли ми перезапускали гру, нам доводилося повторювати процес пошуку золотої адреси пам’яті гравця, оскільки щоразу вона була іншою. Це через динамічний розподіл пам’яті або DMA. Щоб написати хаки, які можна повторно використовувати та поширювати, нам потрібно якимось чином перетворити ці «випадкові» адреси на узгоджені адреси. Існує багато методів для виконання цього завдання, але спочатку нам потрібно обговорити, як працює DMA і чому він існує.

Фон

Ігри — це великі програми з багатьма ресурсами. Немає можливості вмістити всі дані гри в оперативну пам’ять одночасно, тому їх потрібно завантажувати, коли це необхідно. Наприклад, гра не завантажуватиме модель або зображення ворога, поки гравець не зустрінеться з ними. Цей процес відомий як динамічне завантаження ресурсів.

Ці динамічно завантажувані ресурси мають бути розміщені в певній частині пам’яті, щоб гра могла знову отримати до них доступ. Гра відповідає за створення та знищення цих розділів пам’яті. Створення відоме як розподіл, а знищення відоме як зняття. Отже, динамічний розподіл пам’яті — це процес створення розділів пам’яті для зберігання ресурсів, коли вони потрібні грі. Гра може запитувати лише пам’ять у ОС і не може контролювати, де ця пам’ять розташована.

Давайте розглянемо золото гравця в Wesnoth і як воно створюється. Коли Веснот запускається, профіль гравця завантажується в клас гравця гри. Потім гравець може вибирати з безлічі режимів гри та інших параметрів у головному меню. Якщо потім гравець починає гру, кілька предметів розподіляються та розміщуються в класі гравця, наприклад, раса гравця, його доступні одиниці та його золото. Коли гравець виходить з гри, ці значення знищуються. Ось чому золота адреса гравця завжди відрізняється.

Програмування

Щоб запрограмувати хаки, нам потрібен певний спосіб постійно знаходити золоту адресу без пошуку в Cheat Engine. Для цього є кілька способів:

  • Використовуйте автоматичний сканер, наприклад Cheat Engine

  • Код Печери

  • Реверс

Ці методи можна використовувати для пошуку будь-якої динамічної адреси. Ми коротко обговоримо кожен із них у цьому уроці, але в наступних уроках ми використаємо всі методи.

Під час використання Cheat Engine або реверсу нашою метою буде знайти щось, відоме як базовий покажчик. Загалом, базовий вказівник представляє адресу пам’яті, яка завжди є узгодженою та може бути використана для зсуву до значень, які нас цікавлять. Цей метод працює, оскільки є деякі адреси, які мають бути постійними, щоб гра могла їх знайти. Наприклад, у Wesnoth грі потрібно знати, де знаходиться клас Player. Якщо ми знайдемо клас Player, ми зможемо використовувати його як базовий покажчик для зсуву до нашої золотої адреси.

Cheat Engine

Однією з особливостей Cheat Engine є можливість проводити сканування вказівника. Це можна зробити, знайшовши адресу (наприклад, золото гравця), а потім клацнувши її правою кнопкою миші, щоб відкрити контекстне меню. Це контекстне меню містить усі функції сканування вказівника.

Ця функція повертає всі місця пам’яті, які наразі посилаються на вибрану адресу. Потім ці адреси можна зберегти у файл сканування. Після цього гру можна буде перезавантажити і знову знайти адресу. Після порівняння нових місць пам’яті з файлом сканування можна звузити лише узгоджені місця, подібно до звичайного пошуку в пам’яті. Згодом у нас залишаться лише покажчики, які завжди вказують на вибрану нами адресу.

Код Печера

Інший спосіб перемогти DMA — використання кодової печери. За допомогою цього підходу знайдено місце, де здійснюється доступ до потрібного значення. У нашому прикладі Wesnoth це може бути будь-де, де золото змінюється. Одразу після цього місця код перенаправляється до нашої печери кодів. У нашій печері коду ми можемо зберегти поточне значення в частині пам’яті, якою ми керуємо. Потім наш хак може мати послідовний доступ до цієї пам’яті.

Наприклад, код у Wesnoth, який відповідає за зменшення нашого золота під час найму підрозділу, виглядає так:

sub dword ptr ds:[edx+4], ecx

Коли ця інструкція виконується, edx + 4 містить посилання на адресу золотої пам’яті, а ecx містить посилання на вартість щойно залученої одиниці. Перенаправляючи код, що йде відразу після цієї адреси, у печеру, ми можемо зберегти значення адреси в печері. Нижче наведено приклад печери, у якій це можна зробити:

pushad
mov dword ptr ds:[0x12345678], edx+4
popad
...original instruction replaced...
jmp 0xredirect_location

Зробивши це, наш хак зможе посилатися 0x12345678, щоб отримати поточне значення золотої адреси.

Реверс

Останнім методом боротьби з DMA є зміна цілі. Цей метод використовує комбінацію двох попередніх методів і є найбільш універсальним. У цьому підході ми спочатку знаходимо інструкцію, яка змінює значення, яке нас цікавить, наприклад, підінструкцію в попередньому розділі. Потім ми аналізуємо функцію перед цією інструкцією та визначаємо, куди призначається регістр, який нас цікавить (у цьому випадку edx). Часто цьому буде присвоєно значення іншого регістра зі зміщенням, наприклад eax+60 .

Потім ми повторюємо цей процес, щоб знайти, куди призначено попередній регістр. Згодом ми знайдемо базове значення або покажчик, який використовується для призначення всіх цих значень. Потім цей базовий вказівник можна поєднати з усіма зміщеннями, які ми змінили, щоб отримати адресу, яка нас цікавить.

Підписатися
Сповістити про
0 Коментарі
Найстаріші
Найновіше Найбільше голосів
Знайшли помилку?
Якщо ви знайшли помилку, зробіть скріншот і надішліть його боту.