Про мифы касательно ГМО здесь уже писали. В дополнение к этому я хотел бы поделиться отличной аналогией с разбором реальных примеров из области реверс-инжиниринга и модификации машинного кода, что будет понятно и близко именно программистам.
«Мутации» машинного кода
В качестве примера возьмём приставку NES (известную у нас как Dendy), в которой используется процессор 6502. Система команд у него очень проста — опкод представлен всегда одним байтом, и каждый из 256 хоть что-то, да делает. Никаких «защит» от дурака не предусмотрено, и почти любой случайный набор байт будет выполняться без сопротивления со стороны процессора. Таким образом, мы можем взять ROM какой-нибудь игры, исправить в нём случайные биты (будем называть это «мутациями») — и после запуска наблюдать забавные глюки в разных неожиданных местах, но при этом в целом игра скорее всего будет работоспособной. Похоже, что на YouTube имеется целый жанр подобного видео. Полученный таким образом машинный код наверняка не очень корректен, но в большинстве случаев процессор сможет его выполнить и что-то сделать.
Как оказалось, такую методику используют не только для веселья (а играть в знакомые игры с неожиданными глюками весьма забавно), но и для полученя вполне себе конкретных модификаций: делают большое количество «мутантов» и ищут тот, в котором проявился нужный эффект. Точь-в-точь как в современных методах селекции, когда зародыши организмов подвергаются воздействию мутагенов (что приводит к случайным изменениям в генетическом коде), а потом из того что смогло вырасти отбираются те, у которых есть нужный признак. Полученные таким образом организмы получают в довесок массу других нежелательных мутаций. Избавляются от них путем постепенного скрещивания c нормальным видом, добиваясь получения более-менее вменяемого организма с нужным признаком и минимумом других мутаций, которые оказались заметны. То же самое можно сделать и с машинным кодом.
«Генная инженерия» на машинном коде
В качестве прямой аналогии здесь напрашивается реверс-инжиниринг. Мы изучаем машинный (двоичный) код, разбираемся как он работает (целиком или только некоторые его части), после чего вносим именно те изменения, которые наверняка приведут нас к целевому эффекту.
У программистов существует огромное количество инструментов для анализа машинного кода (всевозможные дизассемблеры, отладчики и тому подобное). Не глядя на то, что сам по себе машинный код не предназначен для чтения человеком, он был придуман людьми и задокументирован, так что создание инструментов для преобразования его в более понятный вид (ассемблерный листинг) не было проблемой. Также практически любая исследуемая программа скорее всего тоже была написана человеком, поэтому то что делает её код обычно выглядит логичным и понятным.
Понятное дело, что генетикам гораздо сложнее. Нет никакой официальной документации, которая могла бы пролить свет на все возникающие вопросы. Генетический код был «написан» волей случая и отобран по принципу «смогло ли оно выжить, приспособиться и дать потомство», поэтому наверняка он далёк от логичного и оптимального, скорее даже любая придуманная нами обфускация программного кода покажется просто детским лепетом. Тем не менее это не значит, что генетический код невозможно изучать и пробовать его изменять.
Предыстория
Для меня Dendy всегда была чем-то большим, чем просто приставкой. Я не только играл в неё, но и значительное время провёл внутри неё с паяльником в руках для некоторых простых модификаций. По дороге куда-нибудь я часто размышлял о том, как же создаются эти игры и как это работает внутри. Наверняка, многие из вас тоже когда-то задавались подобными вопросами, такова уж натура будущих IT-шников.
Прошли годы. С некоторой периодичностью погружался в эму-тему, изучая всё новое на тематических сайтах, но я не решался окунуться в изучение ассемблера 6502 и архитектуры NES. Внутренний конфликт рационального и иррационального. Я долго убеждал себя, что мне не нужно тратить на это время, но… сорвался. Глядя на то, какие интересные вещи делают энтузиасты эму-сцены, я взялся за свою давнюю идею со светлой мыслью: «Я тоже смогу!».
Наверняка многие из вас помнят картриджи типа «9999-in-1», которые были примечательны красивым меню с романтическим сюжетом у моря, летающими чайками и приятной музыкой (Unchained Melody). Я дизассемблировал это меню и сделал на его основе трибьют-демку Unchained Nostalgia.
Основная идея — никакого списка игр, а слайды переключаются под музыку. В освободившемся небе я нарисовал осмысленные облака и звёзды; реализовал автоматическое переключение слайдов синхронно с музыкой и возможность ручного переключения; добавил автокоррекцию скорости воспроизведения и высоты звука для систем, отличных от Dendy (ведь это меню делалось именно для китайских фамиклонов, а они отличались от оригинальных NES, из-за чего оригинальное меню работает слишком быстро на NES NTSC, а на NES PAL получается слишком низкий звук); не устоял и перед соблазном добавления целого ряда любопытных пасхалок. То есть используемый подход ничем не ограничивает фантазию и позволяет в принципе вносить любые изменения за какое-то конечное время.
Однако, похожие идеи приходят в голову разным людям
Уже после релиза своей демки я обнаружил, что кто-то тоже пробовал реализовать эту же идею. Автор указал, что он использовал «corruptor», который обычно используется для создания испорченных версий игр с различными глюками.
Если бы мне раньше кто-то сказал, что подобный «случайный» метод реально используется для модификации машинного кода с нужными эффектами — я бы наверняка не поверил. Ведь для этого нужно уйма времени и удача. Хотя с другой стороны нет необходимости изучать и понимать машинный код. Поскольку у меня в руках уже был «живой» пример подобного хака, ничего не оставалось, кроме как исследовать его работу.
Слайды переключаются автоматически, примерно каждые 2 секунды (что слишком быстро). Ручного управления нет. При смене слайда экран почему-то мерцает дважды. Главное, что оно работает! Но каким образом?
Следы хирургического вмешательства
В картридже программный код и тайлы для графики хранятся раздельно. Код — в PRG ROM, тайлы — в CHR ROM. Второй может быть легко изменён с использованием стандартных инструментов, по этой причине для Dendy существует огромное количество графических хаков известных игр, где код оставлен абсолютно без изменений.
Сравним CHR ROM оригинального меню и исследуемого хака:
На лицо следы прямого «хирургического» вмешательства. По какой-то причине были вырезаны тайлы цифр, точки и маленькой чайки. Попробуем вернуть оригинальный CHR ROM и посмотрим, что именно было скрыто таким образом.
Теперь стало немного понятнее. В программном коде был сломан ввод, из-за чего менюшка думает, что кнопка «вниз» всегда нажата. Также был сломан вывод названий игр. Видимо, сломать вывод номеров игр и маленькой чайки (это курсор, указывающий на выбранную игру) не получилось, поэтому их пришлось прятать вырезанием соответствующих тайлов в CHR ROM.
… и немного магии!
Копаем глубже. При помощи дизассемблера посмотрим, что именно делают «мутировавшие» в PRG ROM байты.
Код оригинала | Код хака |
---|---|
NMI: |
NMI: |
Код оригинала | Код хака |
---|---|
LDA #0 |
LDA #0 |
Код оригинала | Код хака |
---|---|
ASL A |
ASL A |
Выводы
Вы смогли прочувствовать, как всё «лихо закручено» в модификациях, созданных подобным «случайным» образом? Одна поломка подпирает другую поломку, и оно как-то в целом даёт результат, близкий к нужному. При этом появляются просто невероятные зависимости между случайными и на первый взгляд никак не связанными участками кода, и при малейших дальнейших модификациях (даже самих по себе корректных) всё может рухнуть. Полноценный реверс-инжиниринг гораздо надёжнее. То же самое можно сказать и о генной инженерии, в сравнении с традиционной селекцией.
Ссылки на файлы
- unchained_nostalgia.zip — демка Unchained Nostalgia, созданная методами реверс-инжиниринга.
- guyver_hack.zip — исследуемый хак, созданный «случайным» образом, и его исходный ROM.