Пособие для мелкого пакостника
или
КАК СТАТЬ БЕССМЕРТНЫМ
(C) Ржавельщик (А.А.М.) 1996
________________________________
Итак, Вы успешно переписали
игру на диск. Однако порубившись
в нее часа четыре, сделали вы-
вод, что если бы попыток было бы
побольше, то, несомненно, джой-
стик остался бы еще жив, а Га-
лактика уже спасена. Отсюда де-
лается простой, как кассетная
нейтронная боеголовка, вывод:
Ваша черная работа еще не закон-
чена. Придется снова грузить мо-
нитор и шарить голодными глазами
по килобайтам программы.
Здесь глобальное преимущество
имеют владельцы Скорпионов, т.к.
они могут оперировать по живому,
сразу видя результат. Для прочих
требуется преодолеть барьер де-
компрессии и ксорки (т.е. прос-
матривать игру нужно такой, ка-
кой она является во время ее ра-
боты). Для этого можно использо-
вать сброс MAGIC'ом и программу
@-CRACK (возможно, что полученый
файл не будет работать как игра,
но этого и не требуется, - он
нужен только для просмотра). Ес-
ли LOADER бейсиковый, то следует
вместо последнего RANDOMIZE USR
поставить выход в монитор. Тяже-
лее всего будет владельцам 48К
(неужели еще есть 48 с дисково-
дом?), им советую пользоваться
MONS - подобным монитором, кото-
рый помещается в экранной облас-
ти.
Итак приступим. Первое: опре-
делим диагноз. Допустим, мы ус-
тановили, что игра страдает
острой жизненной недостаточ-
ностью. Тогда надо определить
метод лечения - прибавление на-
чальных ресурсов, либо удаление
процедуры вычитания (чтобы знать
когда остановиться, иначе можно
переборщить и вместо бесконечной
энергии получить,например,BATTLE
COMMAND, в котором танк спокойно
проходит сквозь все объекты, за-
кончить игру за 5 минут и выбро-
сить).
Кстати, поиск бессмертия -
лучший способ освоить ассемблер,
однако если Вы совсем не знакомы
с данным предметом, то придется
трудновато. Посему запишите и
запомните основные команды, на
которые Вам придется обращать
внимание.
код: мнемоника:
#3E,#DD: LD A,#DD регистр А=#DD
(под #DD и #DDDD подразумевается
любое число одно- и двубайтное )
#32,#DD,#DD: LD (#DDDD),A
эквивалент POKE adr,A
#3A,#DD,#DD: LD A,(#DDDD)
LET A=PEEK adr
#21,#DD,#DD: LD HL,#DDDD
----
#D6 #DD: SUB #DD A=A-#DD
#3D: DEC A декремент А: А=А-1
#3C: INC A инкремент А: А=А+1
#35: DEC (HL) Соответственно
#34: INC (HL) dec и inc содер-
жимого ячейки памяти по адресу,
который находится в HL.
Далее - команды ассемблера
CALL adr, JP adr и JR adr. Соот-
ветственно - GO SUB adr и GO TO
adr. Последние две команды раз-
личаются способом задачи адреса
- в JP он пишется напрямую, а в
JR - по смещению на определенное
кол-во байт. Это команды безус-
ловного перехода. Есть команды
условного перехода - т.е. пере-
ход произойдет, если соблюдено
определенное условие. Условием
является состояние соответствую-
щего бита регистра F -"флага".
Наиболее часто используют два
флага: Z - флаг "0" и C - флаг
переноса. Флаг нуля поднимается,
если в ходе расчета был получен
результат = 0. Флаг переноса -
если, например, большее число
вычитается из меньшего (0-1).
Команды выглядят соответственно
так: JP Z adr, JP C adr - если
переход происходит при поднятом
флаге и JP NZ adr, JP NC adr -
при сброшенном. Флаг определяет-
ся по результату последней опе-
рации, которая на него влияла.
Команды переходов на флаги не
влияют.
Запомнили? Тогда идем дальше.
Допустим, Вы хотите заморо-
зить параметр, который задается
конкретным числом, - количество
жизней, например (если параметр
показывается на экране полоской,
то его численное значение опре-
делить сложно). Запишите коли-
чество жизней и все остальные
числовые параметры, а также все
надписи, сохранив шрифт (заглав-
ные буквы имеют иные коды, неже-
ли строчные). Теперь загрузите
игру в ее рабочем виде и запус-
тите монитор. Все игры при стар-
те устанавливают свои начальные
параметры, т.е. кол-во жизней,
энергии, времени и т.д. Ввиду
этого нужно для начала поискать
процедуры стартовой настройки.
Самое простое: введите поиск
последовательности типа #3E NN
#32 - это переводится как LD
A, NN: LD (addr), A; здесь NN -
количество жизней. То есть по
адресу addr помещается коли-
чество жизней.
Возьмем для примера REX1. Там
имеется 4 жизни и 99 единиц за-
щитного поля. Комбинация #3E 04
#32 встречается там не один раз.
Найдя ее, нужно осмотреть ок-
рестности на предмет начальных
установок других параметров. Ос-
мотр показывает, что наиболее
подозрительным местом будет ад-
рес, по которому расположено
следующее:
LD A,#04
LD (#A063),A
LD A,#02
LD (#A06C),A
CALL #BA49
LD A,#63 <-- #63=99 !
LD (#A04D),A
Очевидно, что это начальная
установка, т.к. здесь выставля-
ется не только кол-во жизней, но
и энергия защиты (99 единиц).
Тогда задаем поиск ссылок на ад-
рес A063. Запомните один момент:
в кодах младший байт числа идет
первым (если число двухбайтное),
т.е. искать нужно комбинацию
#63,#A0. Ссылки на означенную
комбинацию встречаются раз 5.
Для нас имеют значение только
те, которые изменяют содержимое
памяти по этому адресу. Такой
фрагмент имеется только один:
LD A,(#A063)
DEC A <-адрес #9C79=40057
LD (#A063),A
CP #FF
JP Z,9C..
Здесь мы видим, что если ко-
личество запасных жизней станет
меньше 0, произойдет переход на
другой адрес. Это место уже нас-
только подозрительно, что можно
попробовать этот адрес (например
поставить в загрузчике, перед
последним RANDOMIZE USR, команду
POKE 40057,0). Для окончательно-
го приговора нужно посмотреть,
что находится там, куда идет пе-
реход под флагом Z. Там мы видим
такое:
LD HL,#AAED
LD B,1
CALL #A13E
Запомните, что комбинации по-
добного вида обычно используют
для печати сообщений. Смотрим
дамп по адресу #AAED. А там на-
ходятся 3 байта служебных симво-
лов и текст: "GAME OVER". Вывод:
подозреваемая процедура виновна
в лишении жизней и приговарива-
ется к коррекции путем замены
DEC A на NOP (т.е. 0). Все. Вы
бессмертны.
На эту процедуру можно было
выйти и по надписи GAME OVER.
Это делается так: находим адрес
надписи (т.е. адрес в памяти с
которого начинаются ASCII коды
надписи), затем ищем его упоми-
нания. Если ссылок на адрес не
найдено, то ищем упоминание ад-
реса на 1 меньше. В данном при-
мере адрес сдвинут на три байта
назад. Найдя ссылку (осмыслен-
ную) на адрес, ищем начало под-
программы, в которой есть эта
ссылка, затем ищем упоминание
адреса входа в эту подпрограмму.
Процедура вычитания жизней
должна иметь выход на печать со-
общения о том, что вычитать уже
нечего (для данного примера -
GAME OVER).
Если охота, то можно еще бо-
лее облегчить свою жизнь путем
установки бесконечной защиты.
Ищем упоминание адреса #A04D (4D
A0). Его упоминают также не еди-
ножды. Процедура, определенно
уменьшающая содержимое памяти по
данному адресу тоже только одна.
LD A,(#A04D)
SUB L
JP C,#99EF
LD (#A04D),A <-#99E8=39400
CALL #99FA
RET
SUB L - вычитание из А содер-
жимого регистра L. Опыт показы-
вает, что в данной ситуации
удобнее убрать занесение нового
значения в память - например за-
менить #32 на #3A (это не внесет
сбоев в работу программы). Тогда
по адресу #99E8 будет LD
A,(#A040). Либо можно заменить
адрес на адрес в области ПЗУ -
для этого достаточно стереть
старший байт адреса (POKE 39402,
0). Последнее займет меньше мес-
та в строке загрузчика, ввиду
этого оно предпочтительней. Для
наглядности посмотрим еще один
пример - ARCANOID-2. В этой игре
на первый взгляд дается три жиз-
ни, однако поиски 3E 03 32 дают
один подозрительный адрес:
#9DE4. Если поискать его упоми-
нания, то можно найти процедуры,
которые меняют содержимое ячейки
с данным адресом, однако делают
это весьма странно:
LD A,(#9DE4)
SRL A
INC A
LD (#9DE4),A
Это явно не уменьшение на 1,
к тому же - нет проверки усло-
вий. Остается предположить, что
количество жизней не 3. Рассмот-
рите внимательно игру: перед
каждым вбрасыванием мячика вычи-
тается одна попытка, а это зна-
чит, что так происходит и при
старте игры - т.е. на самом деле
жизней 4. Ищем 3E 04 32 - имеет-
ся два упоминания, и оба они по-
хожи на начальные установки. Под
подозрение попадают два адреса:
#7F86 и #7815. Далее ищем ссылки
на подозреваемых. #7F86 упомина-
ется 3 раза (начальное занесение
не считается), в числе упомина-
ний:
LD HL,#7F86;INC(HL) - похоже на
прибавление одной жизни.
LD HL,#7F86
DEC (HL) <-#926C=37484
JP NZ #82DC
JP #FC7B
Эта комбинация достаточно по-
дозрительна, можно попробовать.
Когда используется команда DEC
(HL), ее нужно заменять на OR
(HL) - код #B6=182. Проверка по-
казала, что адрес верен (про-
верьте сами).
Если Вам уже все понятно, то
сбрасывайте машину и - в бой.
Для оставшихся я дам несколько
практических советов:
При поиске ссылок на сообще-
ния будьте терпеливы - иногда
отступать приходится очень дале-
ко, например, в одной ленточной
версии HERO QUEST пришлось
отступить от надписи аж на 14
байт. Иногда сообщения печатают-
ся из таблицы - тогда при вызове
печати задается начальный адрес
таблицы и номер сообщения (пос-
мотрите внимательно REX1, там
сделано именно так). Иногда над-
пись выводит программка, которая
стоит прямо перед текстом, - в
этом случае адрес сообщения не
указывается, но тогда такая
программка должна стоять перед
любой отдельной фразой. Иногда
встречаются такие феноменально
безграмотные игры, которые имеют
множество почти одинаковых про-
цедур отъема энергии (STORM
HAWK, LICENSE TO KILL). Как пра-
вило, здесь одна процедура -
один вид опасности.
Не стесняйтесь пользоваться
методом перебора, - если дело не
движется, то отыщите все подоз-
рительные места и заморозьте их
по очереди.
Старайтесь искать легкий путь
- всегда просмотрите полный дамп
программы - так иногда попадают-
ся секретные коды и пароли. На
разных стадиях загрузки потыкай-
те в клавиши, - бывает, что ха-
керы, делавшие данную версию
ставят тайный CHEAT MODE, напри-
мер в 48 утюгов нужно при старте
нажать и держать до конца заг-
рузки клавиши, составляющие наз-
вание одного из альбомов группы
SEPULTURA, а в DIZZY Y (free
copy) - FCM при загрузке второй
части.
Когда для вычитания применяют
DEC A, то стирать лучше его. Ес-
ли DEC (HL) - лучше заменить ад-
рес, саму команду можно менять
только на OR (HL) (код #B6=182),
иначе будете получать GAME OVER
сразу. Когда используется SUB dd
(обычно SUB 1), нужно заменить
аргумент на 0 (получить SUB 0).
Если Вы не уверенны в коли-
честве жизней - пробуйте оба
числа. Иногда в программах при-
меняются защитные меры - напри-
мер проверка состояния основных
процедур или дублирующие проце-
дуры, которые выглядят иногда
достаточно мирно, в то время,
как "пустая" - буквально кричит
о себе.
Самое трудное - когда очевид-
ных процедур присвоения и печати
нет (например, Silk Worm). В та-
ком случае можно скинуть игру
при разных количествах жизней и
методом сравнения найти адрес
счетчика. Или, - только для ZS-
256, - использовать функции мо-
нитора move и ch. (перенести ку-
сок игры в дополнительное ОЗУ и
сравнивать значения в разных по-
ложениях).
Когда значение показывают по-
лоской на экране (скажем, уро-
вень топлива), то оно может из-
менятся совсем не так, как ка-
жется. Так в TRANTOR энергия не
вычитается, а прибавляется.
Пожалуй, последнее - помните,
что в ассемблере есть множество
команд, и занести значение в па-
мять можно разными способами
(это делается через индексные
регистры, через LDIR, через стек
и т.д.).
P.S. Вышеизложенная информа-
ция отнюдь не претендует на пол-
ноту, однако очень поможет Вам
сделать первые шаги на хакерской
тропе. Заниматься этим вслепую -
чрезвычайно сложно, знаю по сво-
ему опыту.
Мне не приходилось видеть
"Пособие для взломщиков", издан-
ное типографским способом, а это
- единственная книжка на данную
тему, которая мне попадалась.
Главный совет один: учите ас-
семблер и тогда ни одна програм-
ма не устоит перед Вами.
Кстати, возьмите на вооруже-
ние: игры одной фирмы имеют
обычно почти идентичную структу-
ру.
P.P.S. Пожалуй, самая инте-
ресная уловка сделана в XONIX (в
одном из наших), - там коли-
чество жизней определялось кодом
числа,напечатанного на экране
(ASCII код).
________________________________