visilii's blog

Блог о программировании, инфосеке и чём-то ещё
Гостевая книга | Ссылки

Райтап по заданию No way out (PicoCTF)

February 06, 2025 — visilii

Сегодня я хотел бы рассмотреть одно из заданий на реверс-инжиниринг с сайта PicoCTF, которое мне показалось достаточно любопытным, чтобы написать его полноценный разбор.


Вопросы и замечания направлять сюда (Telegram): @visilii или сюда (e-mail): workregor собака mail тчк ru

Скриншот задания

Скачав архив по ссылке, нам предстает необычное зрелище - вместо консольной программки, требующей пароль, или простенького GUI-приложения с текстовым полем и кнопкой мы видим… игру на Unity:

Папка с файлами

Запустим её. Мы оказываемся в помещении без потолка с несколькими кирпичными кубами одинаковых размеров и лестницей, ведущей на платформу (это будет важно далее). За пределами коробки видна область с огромным флагштоком - очевидно, чтобы получить флаг, нам нужно туда попасть. Но перед нами встаёт любимый приём ленивых разработчиков игр - невидимая стена, не дающая нам выбраться!

Свобода так близко…

Итак, очевидно, что нам как-то нужно обойти ограничение, поставленное разработчиком. Очевидный способ - каким-то образом изменить координаты игрока так, чтобы оказаться за пределами комнаты.

Не знаю, как вы, а я сразу подумал о Cheat Engine. Этот дебаггер/сканер позволяет довольно легко находить и изменять игровые значения в памяти процесса. В этом райтапе я коснусь лишь основ этой программы - это очень мощный инструмент и в Интернете можно найти довольно много материалов по нему. Только не пытайтесь его использовать в мультиплеерных играх и помните - читерить плохо ;) Советую пройти встроенный туториал, он содержит бóльшую часть того, что я покажу здесь, и даже больше.

Откроем Cheat Engine и присоединим его к процессу нашей игры:

Интерфейс CE

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

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

Допустим, мы хотим изменить количество очков здоровья в какой-то игре. Мы знаем, что в данный момент у игрока 100 очков, поэтому ищем все числа, в данный момент равные 100. Их, скорее всего, очень много, поэтому после этого мы получаем урон и наше здоровье падает до 72. В Cheat Engine мы ищем среди ранее найденных значений те, что упали со 100 до 72. Cheat Engine способен автоматически отсеять не подходящие под критерий числа, нам достаточно указать новое значение и пересканировать. После этого можно попробовать вылечить здоровье и найти в имеющейся выборке числа, которые выросли в значении. Подобное продолжается до тех пор, пока у нас не остается ограниченный набор чисел (в идеале - одно), которое мы затем можем пытаться изменить, чтобы поменять здоровье игрока в игре.

Какое значение мы можем предсказуемо поменять? Нас интересуют координаты, но мы не знаем, в какую сторону положительное направление координат X/Z, а в какую - отрицательное. Но мы точно знаем, где верх, а где низ! Вот где нам пригодятся разные возвышенности внутри комнаты.

Для начала в Cheat Engine мы выбираем “Неизвестное начальное значение” (мы не знаем, на какой высоте изначально находимся) типа “float”.

Начало поиска
Over 9000!!!

Cheat Engine нашёл почти 218 млн. дробных чисел. Теперь заберёмся повыше - например, вскарабкаемся на середину лестницы - и просканируем все значения, которые выросли.

Выросшие числа

Красные числа в колонке Value означают, что число изменилось со времени последнего сканирования.

Выборка значительно сократилась - с 218 млн. до полутора. Немного подождём, повертим камерой, но не будем двигать нашего игрока в пространстве, и на этот раз просканируем оставшиеся полтора миллиона чисел, чтобы найти те, что не менялись - поскольку мы не меняли нашу высоту, это должно отсеять всё лишнее.

Круг сужается

Дальнейший процесс отсеивания заключается в том же - забираемся на возвышенность, выбираем Increased value, ходим по ровной поверхности, не спускаясь и не поднимаясь, выбираем Unchanged value, спускаемся вниз - выбираем Decreased value. В конечном итоге у нас остаётся около 20 значений - и теперь мы уже можем вручную определить нужное нам.

Все, что осталось

Выбираем все значения, ПКМ > Add selected addresses to the addresslist. Теперь, в списке адресов последовательно меняем каждое значение и смотрим, изменяется ли положение игрока. Я уменьшал каждое значение, предварительно забравшись на платформу, чтобы оказаться под ней, а не под всей игровой картой в случае успеха. Важно менять значения осторожно, чтобы не улететь в космос!

Телепортация в пол

Мы нашли координату Y, но нам нужно оказаться за пределами комнаты, а не над/под ней! Удалим остальные переменные из списка адресов и откроем участок памяти, где хранится наша координата Y (ПКМ > Browse this memory region):

Меню
Память

Нас встречает hex viewer, и наше значение координаты Y расположено в самом начале показанной области памяти в нижней половине окна. Здесь красным фоном подсвечиваются значения, изменившиеся в течение последней секунды. Я изменю это время на 7 секунд (ПКМ > Change fade timer) - так проще увидеть, что поменялось, совершив действия в игре.

Подпрыгнув и быстро заглянув в Memory Viewer, я вижу, что участок, где хранится наша координата, был изменён.

Координата Y

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

Как видим, участок из 8 байт (с 98 по 9F) загорелся красным - скорее всего, это и есть наша координата X (или Z). Не обращайте внимания на красные значения ниже - они меняются несколько раз в секунду и не зависят от движений игрока:

Наша координата

Всё, что нам осталось - это аккуратно изменить это значение, чтобы оказаться за пределами карты. Числовые значения, включая числа с плавающей точкой, хранятся в памяти в LE (Little Endian)-формате, что означает, что старшие байты числа идут после младших разрядов. Попробуем поменять предпоследний (т.е. второй по старшинству) байт:

Свобода!

И оказываемся на свободе! Теперь нам осталось лишь подойти к флагштоку, чтобы увидеть наш заветный флаг :)

На мой взгляд, это очень остроумное задание, и я был рад вновь пощупать Cheat Engine. Есть что-то волшебное в том, чтобы поменять одно число в памяти и получить реальный, ощутимый эффект внутри игры.

Я постараюсь публиковать больше райтапов по тем задачкам, которые показались мне интересными и познавательными. А пока - до новых встреч!

Теги: инфобез, reverse-engineering

badge: proud member of the 250KB Club badge: proud member of the darktheme.club
previous no ai webring siteno ai webringrandom no ai webring sitenext no ai webring site
Free Website Counter
Free Website Counter

Домен предоставлен FreeDNS