[Реверс-инжиниринг, Игры и игровые приставки] «Heroes of Might and Magic IV»: баг с таверной или классика патчинга
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Эта короткая история описывает одну из работ, проведенную в рамках проекта «Equilibris» — неофициального мода для игры «Heroes of Might and Magic IV». С точки зрения как реверс-инжиниринга, так и патчинга она не представляет особого интереса — несколько забавным оказался только лишь финал.
Как известно, в данной серии игр в каждой таверне игрок может нанимать лишь одного нового Героя в неделю. Однако…
Описание бага: Если во внешней таверне не было найма, то, начиная с 8-го дня, можно купить двух героев в течение двух дней.
Для работы используется дизассемблированный файл heroes4.exe из последнего официального аддона «Winds of War». Процедура работы таверны найдена командой ранее и расположена по адресу 4705E0. Из всего алгоритма ее работы меня интересует место, в котором определяется, можно ли в данный момент нанять в таверне Героя, либо необходимо ожидание. В игре это проявляется выводом соответствующего сообщения:
С программной точки зрения это новое окно, которое в игре создается с помощью функции NewWindowCreate (720C80) (распознанным в дизассемблере функциям даны собственные имена). В процедуре таверны несколько вызовов этой функции, и первым претендентом является вызов по адресу 470823. С помощью отладчика убеждаюсь, что, действительно, этот вызов создает искомое диалоговое окно. Код, управляющий этим вызовом NewWindowCreate, находится выше — по адресу 470645:
00470638 call HeroesPricesInTavern_Lost
0047063D mov al, [ebp+48h] // 0 – если таверна работает; 1 – если героя нанять нельзя (ждешь 7 дней).
00470640 add esp, 8
00470643 test al, al
00470645 jz loc_470866 // Если таверна работает, пропустить вывод сообщения по адресу 470823
Покупаю в таверне Героя, затем устанавливаю «бряк» на запись на ячейку, адресуемую [ebp+48h], после чего жду 7 игровых дней. Когда таверна «освобождается», отладчик всплывает по адресу 470DFF. Давайте посмотрим окружающий код:
00470DF0 TavernCountDays proc near
00470DF0 mov dl, [ecx+48h] // ECX+48h – флаг работы таверны:
DL=0 – если таверна работает;
DL=1 – если Героя нанять нельзя (ждешь 7 дней)
00470DF3 xor eax, eax
00470DF5 cmp dl, al
00470DF7 jz short loc_470E06
00470DF9 cmp dword ptr [ecx+4Ch], 7 // В [ECX+4Ch] - число дней с момента найма последнего героя в таверне. Если меньше 7 – выходим.
00470DFD jl short loc_470E06
00470DFF mov [ecx+48h], al // Таверна работает (AL=0)
00470E02 mov [ecx+4Ch], eax // Обнулить число дней
00470E05 retn
00470E06
00470E06 loc_470E06:
00470E06
00470E06 inc dword ptr [ecx+4Ch] // Увеличить число дней с момента найма последнего Героя в таверне
00470E09 retn
00470E09 TavernCountDays endp
Эта небольшая процедура служит для проверки числа дней, в которые таверна закрыта для найма. Замечу, что она вызывается для каждой таверны на карте в каждый игровой день. Что же порождает баг? Программа зачем-то продолжает вести подсчет числа дней, в течении которых в таверне не было найма Героя и по истечении недели, в которую таверна была закрыта (см. счетчик по адресу 470E06). В результате получаем следующую картину. Пусть первый найм Героя происходит только на восьмой игровой день. На входе в процедуру значение флага доступности таверны по адресу [ecx+48h] будет равно «1» (таверна закрыта), а значение счетчика дней по адресу [ecx+4Ch] будет равно «8». Однако при этом, после сравнения по адресу 470DF9, управление получит код по адресу 470DFF, вновь открывающий таверну для найма! При этом счетчик дней сбросится, и после найма второго Героя алгоритм уже отработает, как задумывали авторы. Но через две игровых недели весь цикл повторится.
Самый простой способ пофиксить баг – отказаться от подобного подсчета дней. Пусть счетчик работает только тогда, когда таверна закрыта (что логичнее), а в остальное время зададим его равным нулю. Это достигается очень просто — изменением перехода по адресу 00470DF7 в конец функции:
00470DF5 cmp dl, al
00470DF7 jz short loc_470E09
Теперь остается лишь пропатчить имеющийся код. Для этого смотрим исходный
и измененный
варианты.
Как видно, необходимого результата можно достичь, заменив 0D на 10 по адресу 470DF8. Классика жанра: пропатчить баг, заменив всего лишь один байт!
===========
Источник:
habr.com
===========
Похожие новости:
- [Разработка под MacOS, Ноутбуки, Игры и игровые приставки, IT-компании] 32-битные приложения Windows заработали на Apple M1 через эмуляцию в CrossOver, запущенном в эмуляции x86
- [Информационная безопасность, Игры и игровые приставки] Nintendo подала в суд на продавца RCM Loader — устройства для взлома Switch
- [Safari, Облачные сервисы, Игры и игровые приставки] GeForce Now официально заработал на iOS
- [Assembler, Отладка, C, Реверс-инжиниринг] Дизассемблируем код на Си — switch() { case assembler: disass(); }
- [AR и VR, Игры и игровые приставки] Half-Life: Alyx не попала в число номинантов на игру года из-за того, что в неё сыграли слишком мало изданий
- [Разработка игр, Читальный зал, Дизайн игр, Старое железо, Игры и игровые приставки] История Crazy Taxi — интервью с создателем серии Кенджи Канно (перевод)
- [Игры и игровые приставки] Microsoft: дефицит Xbox Series X и S продолжится и в следующем году
- [Исследования и прогнозы в IT, Игры и игровые приставки] Оксфордский университет выявил связь между играми и психическим здоровьем
- [Игры и игровые приставки] Ремейк карманной консоли Nintendo Game & Watch взломали в первый день продаж
- [Игры и игровые приставки] В PlayStation 5 нашли работающий браузер и протестировали его производительность
Теги для поиска: #_reversinzhiniring (Реверс-инжиниринг), #_igry_i_igrovye_pristavki (Игры и игровые приставки), #_heroes_of_might_and_magic_iv, #_reversinzhiniring (
Реверс-инжиниринг
), #_igry_i_igrovye_pristavki (
Игры и игровые приставки
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 07:34
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Эта короткая история описывает одну из работ, проведенную в рамках проекта «Equilibris» — неофициального мода для игры «Heroes of Might and Magic IV». С точки зрения как реверс-инжиниринга, так и патчинга она не представляет особого интереса — несколько забавным оказался только лишь финал. Как известно, в данной серии игр в каждой таверне игрок может нанимать лишь одного нового Героя в неделю. Однако… Описание бага: Если во внешней таверне не было найма, то, начиная с 8-го дня, можно купить двух героев в течение двух дней. Для работы используется дизассемблированный файл heroes4.exe из последнего официального аддона «Winds of War». Процедура работы таверны найдена командой ранее и расположена по адресу 4705E0. Из всего алгоритма ее работы меня интересует место, в котором определяется, можно ли в данный момент нанять в таверне Героя, либо необходимо ожидание. В игре это проявляется выводом соответствующего сообщения: С программной точки зрения это новое окно, которое в игре создается с помощью функции NewWindowCreate (720C80) (распознанным в дизассемблере функциям даны собственные имена). В процедуре таверны несколько вызовов этой функции, и первым претендентом является вызов по адресу 470823. С помощью отладчика убеждаюсь, что, действительно, этот вызов создает искомое диалоговое окно. Код, управляющий этим вызовом NewWindowCreate, находится выше — по адресу 470645: 00470638 call HeroesPricesInTavern_Lost
0047063D mov al, [ebp+48h] // 0 – если таверна работает; 1 – если героя нанять нельзя (ждешь 7 дней). 00470640 add esp, 8 00470643 test al, al 00470645 jz loc_470866 // Если таверна работает, пропустить вывод сообщения по адресу 470823 Покупаю в таверне Героя, затем устанавливаю «бряк» на запись на ячейку, адресуемую [ebp+48h], после чего жду 7 игровых дней. Когда таверна «освобождается», отладчик всплывает по адресу 470DFF. Давайте посмотрим окружающий код: 00470DF0 TavernCountDays proc near
00470DF0 mov dl, [ecx+48h] // ECX+48h – флаг работы таверны: DL=0 – если таверна работает; DL=1 – если Героя нанять нельзя (ждешь 7 дней) 00470DF3 xor eax, eax 00470DF5 cmp dl, al 00470DF7 jz short loc_470E06 00470DF9 cmp dword ptr [ecx+4Ch], 7 // В [ECX+4Ch] - число дней с момента найма последнего героя в таверне. Если меньше 7 – выходим. 00470DFD jl short loc_470E06 00470DFF mov [ecx+48h], al // Таверна работает (AL=0) 00470E02 mov [ecx+4Ch], eax // Обнулить число дней 00470E05 retn 00470E06 00470E06 loc_470E06: 00470E06 00470E06 inc dword ptr [ecx+4Ch] // Увеличить число дней с момента найма последнего Героя в таверне 00470E09 retn 00470E09 TavernCountDays endp Эта небольшая процедура служит для проверки числа дней, в которые таверна закрыта для найма. Замечу, что она вызывается для каждой таверны на карте в каждый игровой день. Что же порождает баг? Программа зачем-то продолжает вести подсчет числа дней, в течении которых в таверне не было найма Героя и по истечении недели, в которую таверна была закрыта (см. счетчик по адресу 470E06). В результате получаем следующую картину. Пусть первый найм Героя происходит только на восьмой игровой день. На входе в процедуру значение флага доступности таверны по адресу [ecx+48h] будет равно «1» (таверна закрыта), а значение счетчика дней по адресу [ecx+4Ch] будет равно «8». Однако при этом, после сравнения по адресу 470DF9, управление получит код по адресу 470DFF, вновь открывающий таверну для найма! При этом счетчик дней сбросится, и после найма второго Героя алгоритм уже отработает, как задумывали авторы. Но через две игровых недели весь цикл повторится. Самый простой способ пофиксить баг – отказаться от подобного подсчета дней. Пусть счетчик работает только тогда, когда таверна закрыта (что логичнее), а в остальное время зададим его равным нулю. Это достигается очень просто — изменением перехода по адресу 00470DF7 в конец функции: 00470DF5 cmp dl, al
00470DF7 jz short loc_470E09 Теперь остается лишь пропатчить имеющийся код. Для этого смотрим исходный и измененный варианты. Как видно, необходимого результата можно достичь, заменив 0D на 10 по адресу 470DF8. Классика жанра: пропатчить баг, заменив всего лишь один байт! =========== Источник: habr.com =========== Похожие новости:
Реверс-инжиниринг ), #_igry_i_igrovye_pristavki ( Игры и игровые приставки ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 07:34
Часовой пояс: UTC + 5