Интро
Про что здесь
В этом цикле статей я расскажу о том, как занимался реверсом данных из DOS-игры LHX Attack Chopper - симулятора боевых вертолетов от EA и одной из самых любимых игр моего детства (как оказалось, не я один такой - вот современный оммаж играм такого жанра той эпохи).
Это повествование не претендует ни на художественную, ни на, скорее всего, техническую ценность. Единственная изюминка описываемого мероприятия - это то, что я так до сих пор толком и не знаю ни ассемблера (гуглеж не в счет), ни архитектуры самого DOS (таблицы векторов прерываний, модели памяти - вот это вот все). То есть, это как нормальный реверс, только без реверса.
Как вы понимаете - это было долгое путешествие, которое я проделал из чистого любопытства и прямо-таки импринтинга к этой игре. Не будь у меня такой мотивации - я бы бросил это все на полдороге.
Мотивация
Компьютер, который у меня был в детстве (девяностые), отнюдь не блистал техническими характеристиками - процессор NEC V20 (слегка улучшенный клон 8088), 640 кБ памяти, 20 МБ диска, дисковод 5.25 на 360 кБ, CGA-адаптер. Всё. Не Байт и не Спектрум, но и дум на ней не запустишь. Да и много чего не запустишь. И LHX была одной из немногих игр, которые можно запустить, и которые при этом выглядели на этом компе впечатляюще, на мой взгляд. И после, когда я сменил железо (неоднократно), LHX все равно осталась в моем сердечке. И много лет я хотел покопаться в ее внутренностях, как бы двусмысленно это ни звучало.
Бэкграунд
Знания, которыми я пользовался в процессе описываемого - практически все они из тех DOS-времен. Ограниченность того компьютера и отсутствие интернетов не дали (увы) мне утонуть в играх (по вышеозначенным причинам). Потому мне пришлось со скуки погрузиться в азы программирования в частности и айти в целом - но это были именно азы и именно программирования, а не реверса. Я знал Турбо Паскаль и писал на нем игры (2 штуки, обе затерялись в годах), я слышал краем уха про ассемблер (но это казалось мне чем-то запредельным), я даже знал о том, что DOS - это нереентерабельная ОС (и это меня не очень сильно волновало). Я отличал байт от бита, знал об упаковке экзешников как явлении и бесился от 4-цветности CGA. Но это все было довольно стандартным набором знаний для подростка, который более-менее интересовался компьютерами в то время.
По наклонной
Единственная вещь, которую вряд ли можно считать прям стандартной - это то, что я успешно расковырял (ну частично) данные в одной игре уже тогда, в девяностые. Это была игра Goody (с совершенно дурацким управлением - q, a, o, p, space, enter). И сделал я это от скуки и любопытства (то еще сочетание), еще не имея ни малейшего представления о программировании вообще.
Как я уже написал, игр у меня на том компе было немного, интернетов тогда не было, а развлекаться с компьютером хотелось. Одним из развлечений были встроенные функции просмотра и редактирования файлов в Volkov Commander (клавиши F3 и F4). Причем любых файлов - и текстовых, и бинарных. И вот в попытке понять, как же устроены игры, я просматривал содержимое их экзешников - и ничего не понимал. Потому что не там смотрел.
А потом как поня однажды просто по наитию в режиме просмотра байтов взял да и вбил в совершенно рандомное место несколько повторяющихся значений (типа 999999999999999), сохранил и запустил. И где-то в игре вместо нормального спрайта появилось что типа такого:
Не видно? Это потому что тогда экраны были с разрешением в 6-10 раз меньше, а диагональ - меньше только в 2, а то порой и почти такая же 🙂. Ну вот же, на лампочке:
То, что мне очень повезло и почему полоска двоится - я понял почти сразу. То, что одной цифре “9” из введенной последовательности соответствуют сразу 2 пикселя (красный и зеленый) - тоже. А вот почему их 2 и почему они именно красный и зеленый - я до конца понял только некоторое время назад, когда собственно реверсил LHX (не то, чтобы это занимало меня все эти годы, да).
А на тот момент времени я просто составил таблицу цветов для каждой цифры и буквы (A-F). И, используя ее, нашел положения кусков спрайтов в файле. Ну то есть, посмотрел на исходный спрайт, сконвертил цвета пикселей в циферки согласно таблице, после чего поиском в файле нашел. Проблемой было то, что паузу поставить нельзя (а анимация с нужным спрайтом уже прокрутилась), скриншот сделать нечем, а фотики с циклом получения готовой фотки быстрее, чем через неделю, еще не придумали. Но так или иначе, для всех спрайтов главного героя я нашел их размеры и положение в файле.
И, конечно же, нарисовал свои и вписал их в экзешник. Вручную. Так главный герой игры моими стараниями превратился в шагающего боевого робота. Я даже нашел свои тетрадки с тех времен, так что сейчас еще немного картинок.
Первая (палитра) и вторая (сочиненный мной спрайт с наложенной палитрой, пустые клетки - нули) картинки давали набор байт (типа 000555555550000 для предпоследней строки), который и мне надо было записать в экзешник по адресу с третьей картинки, чтобы получить четвертое изображение уже в игре - конкретно тут это “присевший робот”. Особый шарм придавало то, что указывать надо было не цвет пикселя, а сочетание цветов двух соседних пикселей. То еще упражнение. Для экономии пространства в тетрадке я придерживался принципа “одна клетка - одна цифра”, что, очевидно, давало в игре растягивание конечной картинки в 2 раза по горизонтали.
Сам факт вот такого перехода из “бессмысленно пялюсь в байтовый дамп” в “заменил все спрайты главного героя на собственноручно сделанные” я, собственно, и назвал “частично расковырял данные”.
Ну и еще, имея на руках упомянутую таблицу цветов стало возможным быстро найти спрайты в других досовских 2д-играх - повторюсь, надо просто посмотреть сквозь заземленный защитный экран на миллиметрового размера пиксели, списать последовательность цветов в одной из строк спрайта и составить строку значений по таблице цветов. Потом поискать эту строку значений в экзешнике. Нашлась - значит, здесь лежит описание спрайта. Не нашлась - отбросить у исходной последовательности цветов первый пиксель (помним про два цвета на одну цифру) и попробовать еще раз. Опять не нашлась - ну, значит, не судьба. Я помню, что я и находил, и исправлял, но уже без энтузиазма, первый раз - это все же первый раз.
Из этого всего я вынес для себя три вещи:
-
модифицированный экзешник goody.exe (утерян)
-
подход “чтоб понять непонятное - испорти его копию и сравни результат с оригиналом” (порой пригождался)
-
и веру в то, что я норм такой хакер (была быстро утрачена)
Завязка
Действие первое
И вот с этой нерастраченной верой что я норм такой хакер я полез в экзешник lhx.exe (помимо него в папке игры хватало файлов, но я же хакер). Внутри его бинарного содержимого проскакивали строковые английские названия техники и окружения из игры - su25, bridge, camel и т.п. Даже тогда это как бы намекало мне, что внутри экзешника в этих местах есть что-то связанное с этими объектами. Но новообретенный подход не помогал - порченный экзешник тупо не запускался или вылетал в какой-то момент времени. Да и размеры (61 килобайт у Goody против 279 килобайт у LHX) тоже играли не в мою пользу. Дополнительно, как мне думается, не в мою пользу сыграл тот факт, что файл lhx.exe был, оказывается, упакован.
Действия со второго по n-ное
Несколько раз, с перерывами в несколько лет, я пытался делать подходы к разборке этой игры.
Я узнал-таки (сейчас это можно сделать при помощи, например, Detect It Easy), что экзешник упакован упаковщиком MS EXEPACK 4.06 - и распаковал его.
Нашел описание распаковщика ресурсных файлов EA тех лет (.lib) на профильной вики, заимел откуда-то исходник утилитки распаковки на Nim (то ли сам по описанию написал, то ли скачал откуда то - это было так давно, что даже не помню - но на всякий случай выкладываю). Им распаковал ресурсные файлы.
По итогу, у меня на руках оказалась полностью распакованная игра.
Это я тогда так думал.
Действие очередное
Следующим шагом для себя я видел как-то подступиться к дизассемблированию всей этой распакованный красоты. Это были уже далеко не девяностые, а вполне себе 2010-ые. Я знал, что это будет непросто, потому что я абсолютный нубяра в ассемблере, а это 3D игра под DOS, выпущенная в 1990 году, и которая довольно шустро шевелилась даже на том архаичном моем компе. Все эти факты приводили к трем выводам - DOS наложит свою некислую специфику; скорее всего, не будет никаких стандартов/библиотек (слишком рано для них); но будет уйма хаков/хитрых телодвижений (потому что оно шустро шевелилось). Не сказать, что все это упростило бы дело для новичка в дизассемблировании. Я попытался подстелить соломки инструментами (ссылки скорее для историчности):
-
Ida (естественно) с плагинами к ней - snowman (реверс компилятор) и dosbox plugin. Мне это не сильно помогло. Потом были:
-
Ghidra (дизассемблер от ЦРУ (шучу, от АНБ))
-
Reco (декомпилятор общего пользования, по утверждению авторов)
-
radare2 (целый тулчейн для реверса)
-
И даже SoftIce (мощный дизассемблер времен LHX).
Всё, на что меня хватило со всем этим счастьем - это понять две вещи. Первая - одна из функций в файле lhx.exe предназначена для работы с Adlib Sound; вторая - скорее всего, при старте программа лезет патчить вектора прерываний и при этом досбокс плагин обламывается ее отследить и брейкпоинты не срабатывают (в этом я уверен примерно на 7%). Ну или у меня совсем уж кривые руки, этого совсем нельзя исключать.
Как вишенка торте - я нагуглил как-то пост от какого-то мастера реверса, в котором он вскрыл досовский самолетный симулятор F-19 и достал оттуда модельки. В треде не было особых подробностей, но сами картинки подогревали интерес. Который невозможно было удовлетворить.
В общем, я осознал довольно-таки очевидную вещь. Надо или вписываться в это вот все и начинать тратить очень много времени на изучение реверса в целом и DOS в частности, причем с бОльшим упором на DOS. Или решить для себя, что все же эпоха ушла (MS отказался от поддержки DOS в июне 1994 - это 30 лет назад на момент написания), и это уже не реверс, а палеонтология и поставить точку.
И несколько лет назад я поставил, как мне казалось, точку.
Автор: unbalanced