Тактика и советы к игре Age of Mythology: The Titans

Введение

Age of Mythology — это стратегическая игра в реальном времени, в которой игрок стремится построить свою цивилизацию и победить всех врагов. В стандартном режиме игрок начинает игру на карте, полностью закрашенной чёрным, что обозначает неизвестную и неисследованную территорию. В процессе игры пользователь исследует карту, и на исследованных областях появляются обозначения рельефа, ресурсов, вражеских построек, на которые накладывается «туман войны», обозначающий исследованную территорию, которую игрок не видит.
Целью этого поста будет создание открывающего всю карту хака, дающего игроку значительное преимущество. Он позволит игроку видеть, что делают противники на карте, и выбирать наилучшее время и место для атаки. Этот хак будет разработан для оригинальной версии игры, но позже я покажу, как применить его к новой, расширенной версии, которая сейчас распространяется на Steam.

Вот хеши для основного исполняемого файла, который будет разобран реверс-инжинирингом в этой статье:

CRC32: 7F1AF498 MD5: 09876F130D02AE760A6B06CE6A9C92DB SHA-1: AAAC9CD38B51BEB3D29930D13A87C191ABF9CAD4

Скайп помогает всегда быть на связи

Скайп | Инструмент для связи с бесплатными звонками и чатами

Этот сайт использует файлы cookie для аналитики, персонализированного контента и рекламы. Продолжая просмотр этого сайта, вы соглашаетесь с этими условиями использования. Узнайте больше

Перейти к основному контенту

Microsoft Скайп

Скайп

Скайп не предназначен для вызова экстренной помощи

Скайп не является заменой обычного телефона, и его нельзя использовать для вызова экстренной помощи

Русский (Россия)

Часть вторая: лёгкий способ

В предыдущей части я рассказал о том, как создать хак карты с помощью встроенных функций игры. Эта техника использовала возможность переключения скрытого/открытого состояния. Я последовательно применял эти встроенные функции для поиска по ассемблерному коду. В результате это привело меня к логике, выполняющей сокрытие и раскрытие карты, в которой можно было написать хак, вызывающий эти возможности. В этой части будет рассмотрена гораздо более простая техника, и она оказалась возможной только благодаря полезным строкам, найденным в двоичном файле.
В этой части я буду использовать x64dbg, отличный отладчик и дизассемблер, который я считаю преемником устаревшего уже OllyDbg. К сожалению, в этой части я не часто использовал его, потому что мне почти не требовался анализ в процессе выполнения кода (в конце концов, эта часть называется «простой способ»). Фрагменты на ассемблере вставлены из IDA Pro, потому что я считаю её формат копирования-вставки наиболее читабельным.

Начав с подключения к процессу и выполнения дампа строк (правая клавиша мыши -> Search for -> Current Module -> String references) основного исполняемого файла, мы получили 25817 строк — довольно большая область для поиска.

Фильтр по строке «map» даёт нам более удобный набор. Просмотрев его, я нашёл несколько строк, которые могут привести к чему-то интересному:

«trSetFogAndBlackmap( ): fog and black map on/off.» «trRevealEntireMap — shows whole map, similar to how revealed mode works» «trPlayerResetBlackMap(: Resets the black map for a given HUMAN player.» «map visibility» «blackmap([integerState]): toggles or sets unexplored black map rendering.»

Две самые многообещающие строки я выделил оранжевым. Строки дают чёткое представление о том, что делает функция, и даже сообщают аргументы параметров. Похоже, что функции «trX» связаны с имеющейся в игре системой триггеров, которая позволяет создателям карт добавлять эффекты и условия. Изучение ссылок в первой строке приводит к следующему:

… .text:008B2B76 loc_8B2B76: ; CODE XREF: sub_8AE4A0+46CDj .text:008B2B76 mov ecx, esi .text:008B2B78 call sub_59C270 .text:008B2B7D push 1 .text:008B2B7F push offset loc_8AAEE0 .text:008B2B84 push offset aTrsetfogandbla ; «trSetFogAndBlackmap» .text:008B2B89 mov ecx, esi .text:008B2B8B call sub_59BE80 .text:008B2B90 test al, al .text:008B2B92 jnz short loc_8B2BAE .text:008B2B94 push offset aTrsetfogandbla ; «trSetFogAndBlackmap» .text:008B2B99 push offset aSyscallConfigE ; «Syscall config error — Unable to add th»… .text:008B2B9E push esi ; int .text:008B2B9F call sub_59DBC0 …

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

Переход к механизму обработки события приводит нас к следующему фрагменту кода:

.text:008AAEE0 loc_8AAEE0: ; DATA XREF: sub_8AE4A0+46DFo .text:008AAEE0 mov eax, dword_A9D244 .text:008AAEE5 mov ecx, [eax+140h] .text:008AAEEB test ecx, ecx .text:008AAEED jz short locret_8AAF13 .text:008AAEEF mov edx, [esp+4] .text:008AAEF3 push 0 .text:008AAEF5 push edx .text:008AAEF6 call sub_5316B0 .text:008AAEFB mov eax, [esp+8] .text:008AAEFF mov ecx, dword_A9D244 .text:008AAF05 mov ecx, [ecx+140h] .text:008AAF0B push 0 .text:008AAF0D push eax .text:008AAF0E call sub_5316D0 .text:008AAF13 .text:008AAF13 locret_8AAF13: ; CODE XREF: .text:008AAEEDj .text:008AAF13 retn

Два вызова здесь (зелёных) должны быть вам знакомы, если вы внимательно читали первую часть статьи. Это две функции, которые, как мы обнаружили, управляют раскрытием и сокрытием карты. Каждая функция получает указатель «this», который, как мы видим здесь, загружается с постоянного адреса и скорее всего является классом для главного игрока вмести со значением true/false, описывающим то, что происходит с картой. Здесь есть третий неизменяемый параметр 0, который отличается от неизменяемого параметра 1 в другом месте вызова из предыдущей части статьи. Возможно он указывает, что состояние карты изменено игроком или триггером.

Зная это, хак из предыдущей части можно сделать немного лучше. В старом хаке была проблема с предоставлением фальшивого указателя «this», который должен был иметь записываемое поле, и имелся только один вариант переключения: true/false. Исходя из документации, полученной дампом строк, эта функция принимает два булевых значения; предположительно, они управляют наложенным чёрным цветом и туманом войны, затеняющим области, уже исследованные игроком, но которые игрок в данный момент не видит.

Новый (но всё ещё немного грязный) представлен ниже:

#include using pToggleMapFnc = void (__cdecl *)(bool bEnableBlackOverlay, bool bEnableFogOfWar); int APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) { switch (dwReason) { case DLL_PROCESS_ATTACH: { (void)DisableThreadLibraryCalls(hModule); pToggleMapFnc ToggleMap = (pToggleMapFnc)0x008AAEE0; while (!GetAsyncKeyState(‘0’)) { if (GetAsyncKeyState(‘6’)) { ToggleMap(true, true); } else if (GetAsyncKeyState(‘7’)) { ToggleMap(true, false); } else if (GetAsyncKeyState(‘8’)) { ToggleMap(false, true); } else if (GetAsyncKeyState(‘9’)) { ToggleMap(false, false); } Sleep(10); } break; } case DLL_PROCESS_DETACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; } return TRUE; } Вызывая функцию с разными сочетаниями параметров, удалось получить следующее поведение:

True/True — наложенный чёрный цвет с туманом войны True/False — нет наложенного чёрного, туман войны есть. Пометки на карте отсутствуют. False/True — наложенный чёрный без тумана войны. Исследованные области всегда видимы. False/False — нет наложенного чёрного цвета, нет тумана войны. Видима вся карта.

Ниже показаны скриншоты для всех четырёх состояний:

Хак стал более чистым, потому что теперь он выполняет прямой вызов функции и не требует передачи ничего неизвестного. Надеюсь, очевидно, почему я считаю это «лёгким способом», в отличие от предыдущего решения, потребовавшего долгой отладки и трассировки.

В следующей, последней части статьи мы подумаем, как сделать этот хак ещё немного чище и профессиональнее. Кроме того, мы рассмотрим, что необходимо для портирования хака под новую версию игры Extended Edition.

Кампания

В отличие от режимов кампании Age of Empires

и
Age of Empires II: The Age of Kings
, в
Age of Mythology
всего одна центральная кампания. Кампания состоит из 32 миссий, озаглавленных «Падение Трезубца» (англ. Fall of the Trident). Сценарий игры основан на вольном переложении древнегреческих, древнеегипетских и скандинавских мифов. Сюжет излагается в виде кат-сцен, созданных на движке, показываемых в начале, а также, иногда, в конце миссий. Игра предваряется отрендеренным видеороликом, показывающим сцену битвы людей с мифическими монстрами, в котором изображается заточение Кроноса в Тартар.

Структурно кампанию можно разделить на несколько частей: первые 10 миссий игрок играет за греческую расу, затем идёт несколько миссий за египтян, после — за скандинавов, а последние две миссии и миссия между египетской и скандинавской частями кампании снова заставляют игрока управлять греческими войсками.

В отличие от других вариантов одиночной игры и мультиплеера, в кампании условия победы в каждой миссии различны. Для победы в миссии надо выполнить все обязательные задания, которые даются игроку в порядке их выполнения. Также могут быть и дополнительные задания, выполнение которых не обязательно, но даёт игроку некое преимущество или бонус.

Сюжет

История игры начинается в Атлантиде, где адмирал Аркант пытается восстановить покровительство бога атлантов Посейдона[12]. Аркант защищает Атлантиду от нападения пиратов и вскоре вынуждает их отступить. Затем, пустившись за ними в погоню, чтобы вернуть украденный со статуи Посейдона трезубец, он отправляется к Агамемнонону и участвует в Троянской войне. После нескольких сражений Аркант вместе с Одиссеем и Аяксом разрабатывает план захвата Трои с помощью Троянского коня. Одержав победу во взятии города, Аркант и Аякс отправляются в Грецию к кентавру Хирону, чтобы починить корабли. Но добравшись до его мастерских, они обнаруживают, что порт захвачен неизвестными разбойниками. Освобождённый Аркантом и Аяксом из плена Хирон сообщает им, что все его люди угнаны в рабство. Вместе они отправляются на север, где находят пленников раскапывающими проход в Преисподнюю под надзором циклопа Гаргаренсиса, руководящего Камосом, предводителем пиратов, стоявшим за нападением на Атлантиду[13]. Когда раскопки завершаются, герои следуют за Гаргаренсисом вниз и доходят до огромных ворот Тартара, которые пытаются разрушить тараном циклопы-слуги Гаргаренсиса. Троица, несмотря на незнание назначения этих врат, уничтожает таран, не дав их разрушить. Но Гаргаренсис выбирается наверх, отрезав своим преследователям путь назад, и они остаются в подземном мире.

Найдя ближайший выход на поверхность, герои попадают в Египет, где встречают нубийскую воительницу Аманру, собирающую разрозненные части тела бога Осириса, убитого Сетом, чтобы воскресить его, и соглашаются помочь ей. Во время путешествия по Египту в поисках ковчегов с останками Осириса Аркант видит сон, в котором Афина рассказывает ему о намерениях Гаргаренсиса освободить из Тартара Крона, разрушив одни из четырёх врат, за награду от него — бессмертие[14]. Аманра отвоёвывает ковчег у прислужника Гаргаренсиса — жреца Кемсита, Хирон извлекает голову Осириса из священного дерева Тамариска, а Аркант и Аякс убивают командира пиратов Камоса, завладевшего последней частью. После проведения обряда Осирис воскресает и уничтожает армию Гаргаренсиса, но последнему удаётся избежать возмездия, отплыв к третьим вратам Тартара в Скандинавию.

По пути на север Аркант и Аякс находят потерпевшее кораблекрушение судно Одиссея и помогают ему уничтожить Цирцею. Прибыв в Скандинавию, герои сталкиваются с дворфами Брокком и Эйтри, которые решают показать им дорогу в Нифльхайм в обмен на защиту своих мастерских от великанов. По пути они встречают старика Скалта, поручающего им нести знамя, которое, как он утверждает, должно воссоединить разрозненные кланы, но при попытке примирить враждующих, показав знамя, герои узнают, что на нём вышит знак снежнего великана Фольстага, терроризирующего местных жителей, — символ раздора. В конце концов знамя возымеет прямо противоположный эффект и гнев лидеров кланов обращается на героев. После того как Скалт разоблачается, признавшись, что он — воплощение бога Локи, герои узнают, что Локи помогает Гаргаренсису. Найдя третьи врата в Тартар, герои снова пытаются уничтожить таран Гаргаренсиса, а Хирон приносит себя в жертву, перекрывая путь армии противника. Слугам Гаргаренсиса удаётся взломать запор врат, но они тут же запечатываются молотом Тора. Гаргаренсис оказывается разбит, на подмогу героям приходят войска Одиссея, и Аякс отрубает голову Гаргаренсису[15] .

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

The Golden Gift

Дополнение к официальной кампании, The Golden Gift

(рус. Золотой подарок) было выпущено в виде свободного контента на сайте Microsoft. Кампания повествует о дальнейшей судьбе братьев Брокка и Эйтри, героев оригинальной игры. Они собираются сделать механического золотого борова в подарок Фрейру. Вновь появившийся Скалт пытается помешать этим планам, сказав обоим гномам, что брат собирается присвоить себе авторство борова. Когда же они, несмотря на это, всё-таки заканчивают сооружение механизма, Скалт выкрадывает борова и прячет его в крепости Локи. Но братья собирают армию и отвоёвывают подарок, который преподносят Фрейру[16].

Часть третья: собираем всё вместе

В предыдущих двух частях мы говорили о том, как разработать хак карты Age of Mythology. Мы сделали это, найдя и выполнив обратную разработку частей игры, ответственных за переключение состояний карты (наложенный чёрный слой, туман войны, полностью раскрытая карта) и вызывая эти функции через DLL, инъектированную в процесс игры. В этой короткой части мы завершим тему, добавив в исходный код инъектор, который будет инъектировать разработанную нами DLL хака в процесс Age of Mythology. Хак будет работать в многопользовательском режиме, в оригинальной игре и в расширенной версии.
Код выложен на github и в целом не требует объяснений. DLL хака карты экспортирует обратный вызов KeyboardProc, который управляет логикой переключения состояний карты в зависимости от нажатых пользователем клавиш (7, 8, 9, 0). Инъектор устанавливает в процесс игры хук клавиатуры, который инъектирует DLL хака в процесс игры и активизирует обратный вызов KeyboardProc. После этого все передаваемые игре нажатия клавиш перехватываются и проверяются на соответствие четырём клавишам переключения состояний карты. Если нажата клавиша переключения, то вызывается соответствующая функция, изменяющая состояние карты.

Рейтинг
( 2 оценки, среднее 5 из 5 )
Понравилась статья? Поделиться с друзьями: