Навигация по сайту
- Игры / Образы
- Игры на русском языке
- Коды / Советы / Секреты
- Наши переводы
- Наши проекты
- Игры на русском языке (OnLine)
- Эмуляторы
- Обзоры игр
- Информация
- Статьи
- Интервью
- Мануалы / Инструкции
Случайная игра
Вступай!!!
Облако тегов
Показать все теги
****************** Незаконченная (-демо) статья v02 *********************************************************
*************************************************************************************************************
Гайд по взлому игр Sega. Автор Ti.
В этом гайде будут рассмотрены методики взлома игр с приставки Sega Mega Drive. Взлом игр с других платформ может значительно отличаться, поэтому не рекомендуется использовать тут написанное, как шаблон, если только вы не понимаете что делаете. Гайд ориентирован на новичков, к тому же автор не является професcиональным программистои и программистом вообще, поэтому все определения и названия могут и будут отличаться. Под взломом понимается изучение и изменение самой игры, а не замена графики или звуков, это будет затронуто лишь вкратце.
Также автор не отвечает за причиненный вред психологическому состоянию, в случае неудачных попыток хакинга.
Важно:
Что необходимо знать:
16-ричная и двоичная система счисления и их отличия от десятичной.
Что такое ROM.
Что такое RAM.
Что такое байт(byte),бит.
Иметь общее представление о работе компьютера.
Если вы не знаете что это такое или не уверены лучше не читайте этот гайд!
Для взлома понадобятся следующие программы:
IDAPro v5.2 с sega loader'ом. (Альтернативы нет!)
WinHex или любой другой HEX-редактор. (В примерах будет рассмотрен WinHEX, но принцип работы у всех одинаков)
GENSVKNTrace - модификицая эмулятора GENS c расширенным дебаггером.
Gens-mk2 (с сайта шедевра) - эмулятор с безглючным поиском читов(значений в памяти).
Gens11/GensKMOD - также можно запастись и этими.
FixCheckSum.exe - программа исправления контрольной суммы рома, требуется для игр с защитой.
GGConv.exe - конвертер гейм гени кодов(читов) в формат Адресс:значение.
Goldwave - редактор звуков если вдруг решили заменить звук.(имеется ввиду речь).
Тайловый редактор - Он будет нужен чтобы узнать где именно в роме лежит графика. Примеры редакторов - YY-CHR V.098, djinn Tile mapper, tile molester, tile layer pro и т.д.
Если вы не смогли скачать("где это скачать", "у меня не работает ссылка" и т.д.) данные программы не переходите к
дальнейшим пунктам! Научитесь скачивать потом ломать ромы!
Многие ссылки можно найти тут:
romhacking
Форматы представления данных.
В сеге все значения можно поделить на 3-типа =
byte = значение в 1байт. (.b)
word = значение 2байта. (.w)
longword = значение из 4байтов. (.l)
Именно такими значениями оперирует процессор.
байт это число от 0 до $FF (0-255) (в бол-ве случаев от -128 до +127) \ это важно учитывать!.
ворд это число от 0 до $FFFF (0-65535) (в бол-ве случаев от -32768 до +32767) /
символ $ перед числом говорит о его 16-ричном представление.
ROM (read-only-memory)-память только чтения - пзу картиржа (картирдж) - то что на нем записано - ром-файл.
RAM (random access memory) -оперативная память (временная) - работает только при включение питания.
Процессор сеги (Motorola 68000) - выполняет операции между ram, rom и собственными регистрами и другими системными устройствами.
VDP (видеопроцессор),
Z80 (доп.процессор), используемый для звуковых программ.
Порты джойстиков.
YM2612 - звуковой чип.
PSG-еще один звуковой чип (шумогенератор).
Распакуйте его если он в архиве, также ром должен быть формата .BIN (или .GEN)
Что содержится в роме? В роме нет файлов. Все данные, расположенные в роме - графика, музыки, звуки, код (программа), могут быть расположены как угодно, а их точное располжение (адрес) определяется программой.
Для начала откроем РОМ с помощью WINHEX. (File-Open).
Откроется окно, где слева отображается некоторая информация о файле, чуть правее Offset - адрес текущего расположения, посередине большое окно с кучей цифр - 16ричное представление, и справа ASCII-представление. Обычно вначале картирджа располагается информация(заголовок) об игре, который можно прочитать в текстовом (ascii)-виде.
Можно прокрутить ползунок по всему рому, чтобы поискать нет ли еще где такого текста. Если есть его как правило можно безболезненно поменять. Не пытайтесь менять другие цифры в надежде получить хороший результат.
Важно:
Если нажать на колонку offset мышкой колонка адресов преставиться в 10-чной системе, это очень частая ошибка когда случайно так нажимают, мы будем использоваться только 16-ричную систему, если нажали надо нажать еще раз чтобы вернуть обратно, это станет заметно по наличию букв в адресах.
Итак, как же работает игра? Начальный адрес программы задается по адресу 4.
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00000000 00 FF FF 00 00 00 02 10
$00000210 - тип longword (полный адрес) в вашем случае адрес может отличаться (как правило $200)
Теперь если перейти к этому адресу (Position-go to offset-210-ok), мы окажемся вначале программы
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00000210 4A B9 00 A1 00 08 66 06 4A 79 00 A1 00 0C 66 7C
00000220 4B FA 00 7C 4C 9D 00 E0 4C DD 1F 00 10 29 EF 01
Эти цифры представляют собой машинные коды, которые читает и выполняет процессор, отображенные в 'удобном' 16-ричном виде.
К счастью любой такой код можно перевести в код языка Ассемблера, однако следует помнить что ром не состоит из одних кодов, цифры могут означать и что угодно (графика, данные и т.д.).
например данный код: 4A B9 00 A1 00 08
до компиляции (преобразовании из ассемблера в машинные коды) выглядит так:
Процессор начинает считывать и выполнять программу с картиджа сразу при включении. Все коды читаются один за другим непрерывно, также программа перейти из одного адреса в другой если это указано или условие перехода выполняется (переход, прыжок).
Самым лучшим способом отделения программной части игры от всего остального (графики, звуков) является дизассемблинг.
В этом нам поможет IDAPro. (используем IDAv5.2 с sega loader'ом(c) от HardwareMan'a)
Запускаем idag.exe
OK.
NEW-disassemble new file.
Выбираем РОМ-файл.
OK.
OK.
Появится окно IDA View-A.
Немного прокрутим ползунок до адресса $210. (в данном случае)
Увидим следующее (или похожее) :
Вот это и есть программа(код) игры на языка Ассемблера, точнее только ее маленькая часть (самое начало).
Рекомендуется включить сразу текстовый вид (правая кнопка - text view), иначе при прокрутке начнут вылезать графики.
Каждая строчка представляет собой команду для процессора, где слева - сама команда, а справа, то над чем её проводить (адрес, число, регистры). Также в среде программистов именуются инструкциями, опкодами и прочее.
Теперь если выделить любую команду мышью, а затем перейти во вторую вкладку (Hex view-A), мы увидим её отображение в РОМЕ в 16-ричном виде и место расположения. Команда будет выделена зеленым и может быть разной длины (от 2 до 10байт и более). Данная "фишка" позволит нам в дальнейшем с легкостью их находить и менять если нужно.
К сожалению IDA не может определить сама расположение всех частей программы (т.е. отделить весь игровой код, от всего остального), поэтому доделывать за неё это придётся нам.
В зависимости от игры и наших целей это можно делать, а можно и не делать.
Опция в IDA , Options-General-Kernel Options 1- Make final analysis pass (поставить галочку) и далее нажать Reanalyze Program позволяет отделить больше кода чем обычно, но это вызывает и излишки когда куски не кода, определяются тоже как код.
Это не страшно так как в IDA всегда можно преобразовывать данные в код и обратно. Используйте эту опцию (можно еще нажать её н-ко раз) если IDA отделила слишком мало кода (кол-во определяется по большой полосе сверху на вкладкой).
Есть два простых хоткея преобразования туда-обратно: это 'C' (code) и 'U' (undefine) - отмена.
Попробуйте сразу нажать 'U' на место где есть код, а потом снова 'C', чтобы понять как это работает.
Теперь прокрутим ползунок чуть дальше, до первого места где программа пропадет.
$0000029E - числа начиная с этого адреса не являются кодом. Это данные, ну или как можно назвать 'gamedata'.
Суда может входить что угодно (и графика и звуки, конфиги уровней, хар-ки персонажей, комбинации кнопок, ascii текст, архивы, цены игровых предметов и т.д.)
Однако можно 'насильно' попробовать их представить как код (нажав C).
Данные представились как код, но это неправильно, т.к. это просто совпадение. Поэтому надо сделать Undefine обратно.
Как точно определить данные это или же код, будет рассмотрено немного позже.
Однако скажу что любой код заканчивается на команды:
jmp (прыжок)
bra (прыжок)
rts (возврат)
rte (возврат из исключения)
Если же у вас участок кода закончился на любую другую, а далее идет 'разрыв' и 'C' не срабатывает, то это не КОД.
or.b d0,d0 - не код. жмем 'U'. следующий кусок тоже не код, т.к. заканчивается на ori.b #0,d0
Почему так? если бы процессор выполнял команду or.b d0, d0; следующая за ней шла бы 3FFF, а она не является командой процессор и игра бы просто повисла или перезапустилась. Именно поэтому нельзя в РОМ-файле менять цифры от 'балды', т.к. задевая программную часть мы портим последовательность действий.
Важно знать!, что хоть data и не является кодом, однако может представлять т.н. ссылки на код или ресурсы (offsets) - то есть адреса.(отделение адресов будет рассмотрено позже)
Так что же нам это всё дает? Наверное вы уже слышали понятия ASM-hacking и Data-hacking.
Так вот асм-хакинг это изменение(хакинг) кода, требует знания программирования (на самом деле можно хакать и не зная, достаточно запомнить парочку команд, а как я расскажу позже).
Дата-хакинг это изменение игровых данных, простой способ определить за что отвечали те или иные данные, заполнить эту область нулями (не задевая код), и посмотреть что изменилось.
Рекомендуется искать такие области начиная с адреса $1500 (но всё зависит от конкретной игры!), обычно вначале идут системные данные (связанные с информацией о регионах), которые менять ненужно или нельзя.
Чтож если вы поняли и вам уже захотелось попробовать, ищем в IDA-участки 'Data', переходим по этим же адресам в WinHex'e, выделяем область , жмем Edit-Fill block-Fill with hex values - 00, OK. Сохраняем и открываем ром в эмуляторе. Если РОМ не запускается, зайдите в опции эмулятора и поставьте галочку Auto Fix Chechsum / Править CRC Рома. Если РОМ все равно не запускается, отмените в WinHEx изменения (CTRL+Z) и пересохраните файл. Если игра теперь запускается значит, область была важной и просто так её изменять нельзя, попрбуйте найти другую область данных. Если игра от Electronic Arts**, то стоит
дополнительная защита, которую нужно предварительно снять, также доп. защита может быть и в других играх. Определить есть защита или нет просто - если игра не запускается при любом изменении - значит есть.
В случае удачных изменений, т.е. что-то изменилось и вы поняли что, следует изучать данный участок.(попробовать залить не 'нулями', редактировать цифры по одной и выявлять закономерности):
Пример области 'data':
И её отображение в HEX. (т.е. пробуем менять цифры с адреса 732E до 7369)
00007320 43 EC 51 9A 12 3B 00 1D D3 31 80 00 4E 75 01 00
00007330 01 00 00 01 01 10 10 00 00 10 00 10 00 08 08 08
00007340 00 00 08 00 00 00 01 01 01 01 00 03 00 02 00 03
00007350 00 04 00 00 00 04 00 03 01 00 08 00 01 00 08 00
00007360 02 00 04 00 02 00 04 00 08 00 FF FF E5 40 41 EC
Примечание: в IDA значения менять нельзя, это только просмотрщик. Меняем через WinHEx.
Если вы не поняли, или хотите перейти дальше к более совершенным методам читаем.
Карта памяти:
Также есть куча других системных адресов (порты и т.д.). Процессор имеет доступ ко всем этим адресам.
В Loader который мы используем уже прописаны все эти адреса. Теперь мы начнем заполнение базы IDA для конкретной игры, начав с этих системных адресов, это даст нам в дальнейшем много преимществ.
Жмем правой кнопкой на unk_0_C00000 - Rename(N) переименовываем в VDP_DATA_, OK.
Это нужно проделать со всеми этими адресами где есть ukn_0_ (они пойдут после области ROM). (в IDA черные области на полосе)
Теперь выделим наш переименованный адрес правой кнопкой, и найдем там строчку Jump to Xref to operand. Должен появится список из одной или нескольких строк. Можем перейти по любой - попадем в участок кода, где этот адрес запрашивается, (там тоже будет автоматически переименовано), это подскажет нам о том, что данный участок используется для чего-то связанного с выводом графики. (т.к. VDP-видеопроцессор). Участки с переходами к Z80, будут связаны со звуком. А IO_CT1_DATA - с опросом джойстиков.
Это главная 'фишка' IDA, засчет которой можно быстро разобраться в игре и переименовать не только системные адреса, но и любые другие. В дальнейшем мы будем часто пользоваться Jump to Xref to operand.
Я не рекомендую менять(да и не умеем ещё) участки кода с 'системными' адресами, т.к. ничего полезного вы в этом не найдете.
Мы их отделяли как раз для того, чтобы не 'задеть'.
В других участках (отвечающих за игровые 'фишки'), как правило нет этих запросов.
Так как же их найти? Конечно можно проверять всё подряд. Но мы еще не умеем правильно менять код. Да и конкретную вещь в данном случае найти непросто.
Есть два простых способа найти нужную вещь:
Дебаг (с установкой брейкпоинтов) на адрес (ROM или RAM).
Поиск адреса RAM (ID) конкретной вещи через поиск кодов.
Или оба сразу.
Если вы умеете искать читы (game genie), то для вас не составит проблему найти кучу адресов в RAM, отвечающих за что-либо.
Чем больше переменных мы найдем, тем лучше.
Какие это могут быть значения:
Номер (ID) персонажа.
Номер (ID) уровня, трассы,машины, мотоцикла.
Кол-во патронов.
Кол-во жизней, денег и т.д.
Таймер.
Координаты.
Всё что меняется и можно отследить.
Эмулятор который применяю для поиска я - Gens-mk2.
Подробное описание поиска 'читов' вы можете найти в интернете, таких описаний составлено очень много. Также вы можете попросить кого-то научить вас их искать (не меня).
Читы-это всего лишь значения в оперативной памяти, которые меняются. Само читерство заключается что мы можем залезть в память и заблокировать их (перезаписывая всё время своё значение) или просто один раз изменить.
Опишу простой способ поиска:
Выбираем первого персонажа, заходим cheats-search gg codes-reset.
в поле comparison type ставим больше > (greater than) и нажимаем OK.
Теперь выбираем второго персонажа , опять заходим в search gg codes и нажимаем reset.
Список адресов значительно уменьшится.
Теперь выбираем третьего , опять заходим и опять reset.
Еще меньше. Так делаем пока значений не останется по минимуму. это и будет искомый адрес. (адрес ID персонажа)
Почти всегда значение ID будет равен персонажу -1 , т.к. счет идет с 'нулевого' перса , а не первого.
Записываем эти значения (их может быть н-ко) , а также добавляем как чит.
add cheat - new value, в new value прописываем с любой из реальных ID и жмем ок.
Теперь включая чит, мы можем проверить какой-же именно адресс отвечал за порядковый номер персонажа.
Стоит попрбовать вписать другой 'несуществующий' ID, это позволит выбрать несуществующих или бажных персонажей (которые получаются 'случайно').
В случае если вы искали кол-во жизней или патронов то надо сравнивать на уменьшение char_id
Теперь если нажать правой кнопкой и выбрать Jump to Xref's, мы увидим переходы к участкам кода игры, связанные с данным параметром. Эти 'куски' кода и будут нас интересовать больше всего.
Если же ничего не нашлось (пусто по обоим адресам) - значит:
1) участок в котором запрашивается этот адрес не был дизасмнут.
2) этот адрес запрашивается относительно другого адреса. (относительная адресация)
3) вся игра использует относительный метод адресации к RAM.
(пример - Rock n' Roll Racing, все значения берутся от-но адреса FF8000,который записан в регистре A4 процессора)
4) 1+3 варианты сразу.
В этом случае на помощь приходит дебаг.
Эмулятор который мы будем использовать для дебага GENSVKNTrace.
Запускаем, открываем РОМ файл , потом переходим в опции Дебаг-Main 68k Debugger, откроется окно.
Находим брейкпоинты на ОЗУ. В первое или любое поле вписываем наш адрес FFxxxx. Ставим галочки 'чтение' или 'запись', или обе сразу и галочку 'установить брейкпоинт'. Нажимаем ОК.
Игра продолжается. теперь просто надо 'прокрутить' игру или поиграть до того момента , пока не срабатоет брейкпоинт (само откроется окно дебага с надписью 'сработал брейкопоинт на чтение (запись)!'
После того как окно откроется мы увидим код, по которому этот адрес запросился. (например чтение номера(ID) игрока), команда по которой он запросился находится в самой первой строчке. Запомним этот адрес и теперь перейдем к этому участку в базе IDA, и поставим там метку (rename_ read_char_id) или (write_char_id). Хоткей ренейма - 'N'.
Стоит отметить что таких участков может быть достаточно много. (т.е. нужно ждать другого брейкпоинта, при других игровых условиях, пробовать ставить на запись отдельно, на чтение отдельно и ждать.
Брейкпоинт для PC (program counter) - т.н. программный счетчик, необоходим для определения чтения исполняемого кода.
Несмотря на то, что в эмуляторе написано 'брейкпоинты на озу', можно спокойно использовать дебаг и на ROM (т.е. область кода и данных). Теперь если написать любой адрес ROM в поле дебага и поставить галочку 'PC', то если в этом находится программа, то сработает брекпоинт на PC (в случае если эта часть программы будет выполняться) - ну например код выполнения выстрела или спецприема. Если же поставить ROM-адресс на 'чтение' и сработает брейкпоинт значит в этом месте не код, а данные. На 'запись' для rom ставить не нужно, т.к. ни о какой запись в (read-only-memory) картидж не может идти и речи, это используется толко для RAM(ОЗУ), а 'pc', т.е код, практически не встречается в области RAM.
PC (program counter) - счетчик который определяет адресс текущего расположения выполняемой процессором команды. Очень часто применяется для относительной адресации. (от текущего места +$xxxx = итоговый адрес).
Примеры адресации:
move.w ($FFCECE).l,d0 - абсолютная полная (32битная запись, но сега 'держит' только 24)
move.w ($CECE).w,d0 или при этом два байта move.w ($FFFFCECE).w,d0 (но в hex 'FFFF' не будет) - абсолютный адрес но задается 2 байтами. трюк состоит в том что первые считаются $FFFF и мы попадаем тоже в RAM, но это соблюдается только для адресов >$8000, при меньших мы попадем в ROM. (это особенность 16-битной адресации)
move.w $4ECE(a4),d0 - адрес равняется $4ECE + число, в регистре a4 процессора. в данном случае a4=$FF8000+$4ECE=$FFCECE. В других случаях в a4 может быть что угодно, регистры могут быть от a0 до a6 и в них может быть записано что угодно, и может постоянно менятся в зависимости от программы. Что точно находиться в регистре в данный момент времени можно посмотреть в дебаггере.
Во всех трех случаях значение из памяти (RAM) читается и записывается в регистр d0 процессора.
Запись же выглядит 'наоборот': move.w d0,($FFCECE).l
Команда может быть не обязательно move, а другой (add, sub, и т.д.)
move.w unkn_00(pc,d1.w),d0 - чтение данных от текущего места + PC + d1. (IDA автоматически определяет расположение unkn_00 при условии что d1=0)
Подробнее о командах и регистрах будет рассмотрено позже.
Hot trick:
Используете GG-коды и GGConv.exe (game genie converter), чтобы найти уже найденные другими адреса в ROM и RAM, и допишите их в базу переименовав и поставив метки.
GG-коды можно найти в книге кодов codebook.exe, и на сайтах.
Запустим конвертер и выберем вкладку GEN (sega GENesis).
Вбиваем GG-code и получаем HEX-code.
Многие адреса уже представлены в виде HEX-code и их конвертировать не нужно.
HEX-code выглядит в формате adress:data.
пример FF1234:0005 (интересуемый адрес FF1234, значение вприцнипе нас не интересует), так если в описании чита указано что это жизни, следует переименовать, или начать с 5-ого (4-ого) уровня - значить это уровень, а значение его и определяет
его номер)
пример 00A6b0:6000 (интересуемый код находится в области ROM, суда следует перейти и тоже поставить метку.), также в этом случае число может являются только номером , но и кодом для процессора. (например, 6000, 4E75 или 4E71)
Теперь найдя интересующие участки кода мы будем их переделывать. Если с вышеописанными способами ничего не получилось, то мы их все равно будем переделывать, а что именно мы будем изменять узнаем по ходу дела. (сравнивая после и до изменения)
Перейдем к интересующему нас коду. (там где есть обращения к найденным переменным).
Весь код программы можно условно разделить на функции (процедуры), в IDA они разделяются строками ====SUBROUTINE====.
У любой такой подпрограммы есть начало и конец. в 95% случаях в конце находится команда .RTS (return from subroutine)- то есть возврат из этой подпрограммы к предыдущей.
HEX-код данной команды выглядит как 4E75. Запомните эту команду. в 97% случаях эта комбинация цифр и говорит, о том что тут находится имеенно код и конец подпрограммы.
Посмотрев ROM в 16-ричном виде в WinHexe, и вбив в поиск search-find hex values - 4e75, можно найти
огромное их кол-во. Следует отметить что адрес должен быть четным. То есть если 4e75 нашлась по адресу $251 (нечетн и т.д.), то это не Rts. Это полезно учитывать при нахождении кода в базе.
Теперь перейдем к началу подпрограммы (разделенной ====SUBROUTINE====), теперь надо заменить первую команду на RTS.
Что это даст? Мы полностью отключим данный участок. И таким образом сможем узнать за что, же эта часть кода отвечала.
Замена:
Просто пишем,использую в winhex, '4e75' по адресу который соотв. началу подпрограммы. (т.е. по адресу самой первой команды, то есть фактически мы ее заменим-т.е. уже asm-hacking)
Если ничего не изменилось или игра зависает, пробуйте тоже самое с другими участками.
Если получилось, и вы поняли что изменилось (напр. отключилась стрельба) переименовывайте (называйте) данную функцию.
Примеры названий и названных функций:
AI_weapon_nitro_using
car_model_gfx
weapon_moving
weapon_sprites
car1_life
car1_topspeed
xz_1
weap_table
Функции с code+data:
Если в функции есть следующие или похожие команды:
move.w unkn_1234(pc,d1.w),d0
lea unnk_5678,a1
И при переходе по адресам unnk_5678 в ROM, скорее всего содержится 'data'. Т.е. это могут быть игровые параметры такие как характерситики персонажа (скорость,сила и т.д.). Стоит попрбовать позаменять эти значения в РОМЕ через Winhex.
(заменять значения по этим адресам, как и случае data-хакинга, а не сами команды).
Особенно хорошо, если вы уже определили за что отвечает ваша функция).
Незабудьте что сама же функция должна быть при этом включена (т.е. никаких RTS вначале).
В данном примере команда загружает число с адреса 1234, от-но значения регистре d1 и записывает в d0.
В d1 например может быть ID (порядковый номер) персонажа, а по адресу хар-ка 'скорость'.
Функции только с code:
В этом случае стоит посмотреть на ту команду над которой происходит действия над нашим найденным и переименованным адресом.
Пример:
add.w #$14,($FFCECE).l
или
sub.w #1,($FFCECE).l
Адресс с назначенным именем (меткой):
add.w #$14,(LIFES).l
В данном случае это ADD (англ. прибавить), SUB (substract-вычесть). #1 - символ # говорит о том, чо это число. если # нет, значит это адрес. Результирующие действие проводится только над тем что,находится справа.
Т.е. в первом случае мы добавляем к значению в адресе $FFCECE число #$14.
Во-втором: вычитание из значения в адресе $FFCECE вычитаем 1. (значение в этом адресе памяти сразу же меняется, уменьшаясь на 1)
Например станет 13 жизней, а не 14.
Следующий код можно изменить следующим способом: вырезать (удалить) данную команду.
Для этого предусмотрена команда NOP (No Operate) - т.е. не проивозодить никаких действий. Данная команда записывается в HEx-виде как 4E71. Учитывая что команда nop занимает всего 2байта, а команда которую мы будет заменять может занимать значительно больше байт (для чего выделим ее в IDA и перейдем во-вторую вкладку), мы должны записать н-ко Nop'ов., чтобы не нарушить структуру программы.
Открываем ROM в Winhex, перейдем к адресу этой команды и впишем 4e71 4e71 4e71 4e71. (т.е. если ориентироваться по вкладке в IDA hex-view-A соотв. залить всю зеленую область nop'ами).
Таким способом можно вырезать любые команды и сравнивая результат до и после, и добиться каких-то 'эффектов', от положительных до зависания игры.
Также можно пробовать менять сами цифры в коде. Т.е. если в команде была операция с числом #$14, и выделив ее вы в hex-виде нашли 0014, можно попрбовать заменить на 0000 или 0028.
Можно ещё попрбовать поменять местами соседние команды.
Также если вы увидите команды beq или bne, пробуйте переделать их. (в hex начинаются на 67 и 66, т.е. нужно пробовать заменить 66 на 67, и наоборот- это превратит команду bne в beq).
Несмотря на простоту эти методы являются самыми эффективными, в случае если надо просто что-то 'хакнуть'.
Если же у вас есть конкретная цель, то без знания ассемблера или хотя бы н-ких команд не обойтись.
Вкратце рассмотрим что за ассемблер:
Несмотря на то, что у всех представление о ассемблере как о самом сложном языке, это не совсем так. Я бы даже сказал что ассемблер сеги самый простой.(достаточно знать десяток команд и можно написать что угодно). Другое дело что само написание дело долгое и трудоемкое. (т.к. все действия выполянются над числами и адресами).
Обзор регистров процессора:
Процессор MC68000 содержит 8 регистров данных (для чисел) - это регистры d0, d1, d2, d3, d4, d5, d6, d7 и 8 регистров для адресов - это регистры a0, a1, a2, a3, a4, a5, a6, a7
Регистры нужны для быстрых рассчетов, и бол-во операций выполняются между ними или между ними и памятью.
Также есть регистр SR (status registr), он меняется автоматически после каждого действия и отображает результат, который нужен для выполнения условий (напр.условие перехода).
Регистр a7 является железным 'stack pointer'ом и поэтому в коде его записывают как sp.
пример move.w d0,(sp)+. что это такое будет рассомтрено.
Основные команды ассемблера:
Буква после точки любой команды, означают что операция проводится с этим типом данных.
(.w - 2байта, .b 1 - байт, .l = 4 байта) , .s (short) также означает байт(но в случае переходов и прыжков).
Пример:
А буква после адреса может быть только .w или .l (это говорит лишь о виде адресации полная или 16-битная) - это не влияет, на тип заносимых данных. (т.к. некоторые новички думают что если move.w адрес надо писать тоже ($1234).w - это не так)
В результате выполнения команд всегда меняется только значение справа (в примере d1).Это справедливо для процессоров Motorola.
Теперь рассмотрим сами команды.
Команды которые мы уже знаем:
RTS (return from subroutine) - возврат из подпрограммы
NOP (no operate) - не произв.действий.(процессор выполняет команду, но ничего не меняется)
ADD - сложение
SUB - (substract) вычитание
Другие команды (эти команды необходмо знать!):
MOVE - копирование
CMP - (compare) сравнение
TST - (test) - сравнение с нулем.
CLR - (clear) очистка - то есть запись нуля.
LEA - (load effective adress) - загрузка адреса в указанный адресный регистр.
JMP (или BRA) - прыжок. (jump, branch)
JSR (или BSR) - переход в подпрограмму с последующим возвратом (после rts). (jump to subroutine, branch to subroutine)
если к команде добавлено 'i' (cmpi.b) это лишь значит что операция выполняется над числом+регистр.
если стоит 'a' (movea.w) , это говорит лишь о том что выполняется над адресным регистром.
а 'q' (addq.b), говорит об упрощенном варианте команды, которая отличается тем, что выполняется процессором быстрее, но имеет некоторые ограничения.
Команды переходов (используется в связке сравнения CMP. или TST.), также очень важные команды:
beq (branch if equialent) - переход (прыжок), если равно.
bne (not equialent) - переход(прыжок), если не равно.
bge (greater или equialent) - если больше или равно.
ble (lower or equialent) - меньше или равно
bpl (plus) - результат положительный.(число полученное в результате имеет знак +, т.е. если байт то от 0 до 127 ($7F).
bmi (minus) - отрицательный.
Логические команды: (частые команды, но чтобы их понять их логику надо считать число по битам)
or ('ИЛИ') - логическое 'сложение' 0+1 = 1, 0+0 = 0 , 1+1=1
and ('И') - логическое 'умножение' 0x1= 0 , 0x0= 0 , 1x1 =1
eor (' исключающее ИЛИ') - 'сложение' , но в этом варинате 1+1=0 (также назыв. xor)
not ('НЕТ') - инвертирует все биты.
lsr (logical shift right) - сдвиг битов вправо
lsl (logical shift left) - влево
asr (arithmetical shift right) - вариант сдвига.
asl (arithmetical shift left)
Сдвиги чаще всего используются для умножения или деления.
Чтобы представить число в двочином виде, откройте калькулятор наберите число в hex или dec, а потом поставьте точку где bin.
Калькулятор (WINDOWS) должен быть установлен в вид->инженерный. Тут же можно и проверить их действие.
Поначалу можно обойтись и без понимая этих команд.
Все остальные команды более редкие, и для начала изучения не требует. Вообщем если попадаются просто смотрим в мануалах.
Выполнение команд:
Рассмотрим пример выполнения и важную особенность команд add,sub и других.
Пример: addi.b #$C0,d0 (добавить C0 к числу в регисте d0)
Пусть в нашем пример до этого регистр был равен d0=002a00B0.
Что должно получится? то есть к числу $B0 прибавить $C0 (т.к. тип данных - байт), если вы используете калькулятор,то получите $170, но это будет неверно. особенность в том,что если вы производили операцию над типом BYTE, другие байты не будут затронуты!, т.е. 002A00 останется как и есть. Чтобы посчитать правильно надо выставить в калькуляторе 1байт.
Получается что все числа как-бы замкнуты по кругу ($FF+2 = 1).
результат d0=002a0070. (этим объясняется например замкнутость координат, т.е. если вспомнить tmnt2 и баг с выходом за экран, когда проходили появлялись сверху или снизу наполовину, после максимума координата 255 попадали в 0 и наоборот )
Eсли же мы будем использовать команду addi.w или addi.l мы получим d0=002a0170.
Команда move.
Обратно же если в команде используется word или longword мы изменим 2 или 4 байта:
Пример move.l #4,d0
Результат: d0=00000004. (т.е. мы скопировали не 4, а 00000004)
Команда clr.
clr.b запишет 00 (т.е обнулит 1 байт)
clr.w запишет 0000 (обнулит 2 байта)
clr.l обнулит весь регистр.
Теперь если вы скачивали эмулятор Gens11(gensmovie) или GensKMOD, запустите этот эмулятор , откройте ром , найдите в пунктах Trace. Включим trace на пару секунд и выключим. Получится файл trace.log. Если вы ждали долго файл может получится огромным. Открываем блокнотом и смотрим. Перед вами результат выполнения программы, т.е. весь текущийвыполненный за эти 2секунды код, а справа то, чтобы находилось в регистрах.
За счет trace.log мы можем:
Отследить как работают команды.
Как от их выполнения меняются регистры.
Отследить последовательность выполнения программы.
Какие участки кода использовались в этот раз, и где они находятся. (что тоже полезно при дизасме в базе IDA).
Буквы xnzvc соотв. состоянию регистра состояния SR.
Операции с адресными регистрами:
случай 1) в этом случае меняется сам регистр a0.
случаи 2-5) 'скобки' - так как в регистре содержится адрес, например FF1000, поменяется содержимое памяти по этому адресу. то есть число из d0, запишется в FF1000. это и есть от-ная адресация. (относительно адреса в регистре a0).
случай 3) (a0)+ - в этом случае адрес в регистре a0 еще и автоматически увеличится (станет FF1002), то есть меняется и регистр и значение в памяти.
случай 4) запись в память по адресу FF1000+1234 = FF2234, сам a0 при этом остается = FF1000.
от-ная адресация для них работает как word. то есть максимум до $7FFF(a0), а минимум -$8000(a0). если укажете число $8500, то оно будет считаться как отрицательное. Однако если a4=FF8000 как в rock n' roll racing, мы получаем как раз доступ ко всей RAM, от-но этого одного регистра. Однако чаще встречаются 1(a0) или -2(a0), с небольшим смещением.
5) тоже что 3, только уменьшение адреса.
6) прыжок (переход программы) к адресу, который содержится в регистре a0.
загрузка адреса $FF8000 в a4.
Stack pointer и Stack.
Как уже упоминалось a7 является stack pointer'ом и записывается как sp.
Он нужен, т.к. в нем записываются точки возврата , необходимые для команды JSR (ответ на вопрос откуда процессор знает, куда ему вернуться после команды rts).
stack - это как бы системная память (часть ram), stack pointer - адрес стека задается вначале, далее может сменен программой, в эту память автоматически и записываются адреса возрврата.
stack устроен по принципу стопки книг.(то есть вначале записывается одно, потом сверху другое, и разбирается вначале сверху потом вниз.), поэтому чаще всего стек находится в самом конце области RAM. ($FFFF00)
Кроме того в стек , можно записывать данные и самому, используя как временную память.
Чаще всего туда заталкивают регистры (содержимое регистров), если его надо 'сохранить'.
Очень часто подпрограмма как раз и начинается с сейва регистра одного или н-ких. Это объясняется тем что нужно сохранить их значения для предыдущей более главной программы. А заканчивается как раз взятием их 'обратно ', прямо перед rts.
Пример:
cейв всех регистров от d0 до a6 (сохраняют в стек), bsr.w - переходы к другим подрограммам.
movem означает (move multiply)- множественное копирование, дополнительный вариант команды move.
сохраняет регистры от d0 до d2, d7 до a1 (т,е. еще и a0).
Обращаю внимание в этом участке , не rts , а rte (т.н. возврат из исключения). VBLANK -кадровое прерывание, которое происходит само 50 или 60 раз в секунду. (PAL или NTSC сега). Поэтому к нему нет переходов. Текущая выполняем процессором программа в любой момент может остановиться и начнет выполенения кода отсуда, к нему нет переходв (это происходит на уровне железа), однако адрес VBLANK задается в заголовке картриджа. (IDA определяет автоматически).
Этот код связан в основном с выводом графики для следующего кадра, поэтому трогать его не советую.
rte вернет вас назад к вашей программе.
Кроме сохранения регистров, стек может быть использован и в других целях. Зависит от конретной игры, в некоторых доходит до того что его используют по 4 строчки подряд. (что не совсем удобно для хакинга).
Также важно если будете менять код, сохраняйте принцип стакинга, (т.е. на затрите с команды sp+ или -sp), иначе нарушится последовательность, программа вернется не в то место и в 90% случаях будет зависание или баги.
* Если вы отключаете функцию (то есть через 4e75 вначале, а там находился сейв в sp), то это как раз нормально, так как мы сразу возвращаемся, а если вписать как раз после сейва, то зависнет (т.к. не 'заберем' из стека обратно).
Ну вот и весь ассемблер.
На вопрос, а что же мне с ними делать? Куда сувать команды и регистры? Ответ - изучите как работает чужая программа (участок кода), от и до (пусть он будет хоть 10строчек), тогда вы сможете понять как его можно изменить с желаемым результатом или написать по-своему.
Для написания вашего собственного участка кода я рекомендую ассембелер ASM68K.exe, который надо запускать с ключом /p.
работает из командой строки (консоли виндовс).
asm68k /p test.asm, test.bin
где test.asm - текстовый файл с вашим кодом, test.bin - готовый hex-код. test.bin надо открыть в WINHEX'e и полученный hex-cod вставить на место старого. если он не влез - используйте команду JSR и найдите пустое место в Rome.
Команда JSR выглядит как 4EB9 00 xx xx xx, где xxxxxx - абсолютный адрес в РОМе.
Пример: 4E B9 00 00 B8 2E - прыжок к подрограмме по адресу B82E.
Эту команду надо Запомнить также как RTS(4e75) и NOP(4e71), то есть если раньше вы вписывали вручную 4e75- теперь вписывайте 4eb9 00 0F A0 00 (где FA000 - адрес найднного вами пустого места, куда вы скоптируете свой код).
* В WINHEX копирование - CTRL+B (то есть запись поверх старого) , не путайте с CTRL+V - это сдвинет весь ром разрушив структуру.
Не советую использовать sega-asm, т.к. в нем есть определенные баги с некоторыми командами и баг c "org".
Что же касается SNASM68K.exe, можете попробовать и его (в нем на мой взгляд тоже есть неясность с полурабочим 'org', к тому же он у меня закидывал свои 'копирайты' в бинарник, что может мешать при копировании кода)
Что делать если вы не нашли пустого места в РОМЕ? SEGA позволяет безболезенно 'расширять' РОМ-файл до 4 мегабайт.
Модифицированные эмуляторы позволят запускать и до 13 мегабайт ром. (но такой ром не будет работать на железной сеге), также не приветствуется многими пользвателями.
Расширение рома:
Для увелечиния размера рома, достаточно приклеить к нему пустое место (нули) к концу файла.
Идем к winhex последнему байту в РОМЕ, выделяем его , заходим Edit->Paste Zero bytes. Появится надпись append to end of file? жмем YES. Добавляем 1 048 576 байт (1 мегабайт). Если ром был 1 мегабайт станет 2 мегабайта.
Теперь проверим запускается ли игра. Если игра перестала запускаться, и игра была с проверкой контрольной суммы (вы выставляли fix checksum), используйте программу FIXCHECKSUM.exe, она автоматически исправляет и сумму и размер рома, которые записываются в начале ром-файла. Эмуляторы умеют исправлять только сумму (но не размер).
Code+Data hacking. Часть2.
Ключевым аспектом является использование(чтение) данных кодом и с последующей их обработкой и/или записью в память.
Впринципе все что не является кодом, является данными. Отдельно можно расположить лищь оффсеты(ссылки на адреса).
Обычно все данные расположены в РОМЕ таблицами, т.н. 'массивы' данных.
Т.е. графика, хар-ки персонажей, пос-ти нажатий кнопок, игровые цены, палитры, конфиги уровней, текст и прочее.
Пример чтения данных:
Если вы уже занимались data-hacking'ом (где мы 'заливали' эти данные, т.е. массивы данными нулями для проверки), вы бы уже скорее всего знали что они отвечают.
В примере move.b считывает (копирует) значение с адреса 732E (адрес в программе от-ный, но IDA считает его автоматически - т.к. относительно pc (текущего положения)). Также дополнительно считывает и от-но значения в регистре d0.
Что это значит?
Если в регистре d0 значение = 00000000, то в d1 запишется значение с адреса 732E, то есть 1.
Если в регистре d0 = 00000001, то в d1 запишется значение с адреса 732E+1, т.е. с 732F, то есть 0.
Для объяснения открою секрет - по адресу $732E, находится таблица хар-ки + скорость, а в d0 порядковый номер (ID) персонажа.
Что же происходит? Если у нас персонаж номер 1 (то есть с id=0, т.к. счет идет с нуля), то прочитается 1, если второй то 0, если третий то 1., т.е. таблица хар-ки + скорость.
То есть целиком куска 'персонажа' не существует. А все его параметры определяются от-но ID (порядкового номера), т.е. такие как таблицы спецприемов и т.д.
По адресу $7335 расположена таблица хар-ки +ускорение. Как видно они в примере они состоят из 7 значений (т.к. всего семь персонажей). Если же ID персонажа = будет 8-ой (id=07), то для первого случая (+скорость) прочитается значение с адреса $7335 (732E+7), т.е. не из рассчитаного места.
(если вы играли в RRR за 'невидимку', теперь вам ясно откуда у него такая завышенная скорость).
То есть если вы хотите добавлять персонажей, то нужно смещать адреса и расширять эти таблицы. Если адрес абсолютный то это сделать несложно, если же от-ный намного сложнее, т.к. придется либо перемещать весь участок в новое место, либо делать какие-то вставки через JSR. Но это пока не рассматривается, т.к. сложность заключается в том, что если вы хотите что-то добавить, то нужно найти и расширить ВСЕ эти 'таблицы', коих может быть от 10 до 100. (и даже после этого никакой персонаж не появится, т.к. нужно указать что персонажей не 7, а 8.) Засчет паролей в RRR получается что задается
не рассчитаный 8-ой персонаж, и результат его обработки. (читаются другие данные), вместо графики все черное и т.д.
Однако может встретить и 'классический' вариант - когда область 'data' отвечает за многие хар-ки одного персонажа.
(пример dune 2), для каждого здания и юнита есть 'data' конфиг. Но при этом все конфиги аналогичны. (т.е. в конфиге не прописывает dmg=100, скорость=20., там есть только числа 100 и 20., а то что за что оно отвечает определяется, в зависимости от его расположения (т.е. например во всех конфигах юнитов первое число будет отвечать за скорость, второе за цену и т.д.)
Программа не читает все сразу (она читает нужное число,) т.е., в программе при чтении цены будет указано смещение +1, от-но начала конфига. (если первое значение типа байт, если же word то +2)
Команда lea.
Самой частой командой загрузки data, является команда lea (load effective adress). Т.е. фактически команда только загружает адрес расположения 'data' в адресный регистр , а в дальнейшем читать уже будет команда move или add.
Пример чтения (ukn_000 переименованы, в найденные опытным путем параметры):
Таблица физ. хар-к для пяти машин:
Код:
Данные:
Как видно в этом примере код и данные располжены далековато друг от друга, но чаще всего они бывают рядом.
Для нахождения кода (одного или н-ких участков) , который читает 'data' , надо выделять метку правой кнопкой, т.е. в пример car_topspeed: и выбирать Jump To Xref to Operand, покажет список всех участков кода и также позволит туда перейти. Как уже упоминалось это главная особенность IDAPro.
В этом примере адресация тоже относительная, хоть это и не написано мы можем посмотреть, выделив команду lea и перейдя во вторую вкладку мы увидим 43FA 0242, где 0242 -от-ный адрес (от-но pc-program counter) , который нужно счиать по формуле DF0C(текущий)+242(указанный от-ный в hex)+2(длина команды) (Ida считает автоматически).
Примеры 43FA xxxx, 41FA xxxx, 45FA xxx, 47FA xxxx. - от-ные.
Абсолютные: в данном варианте полный адрес в виде longword.
в HEx выглядит так: 41F9 00 00 55 20, загрузка адреса $00005520, по которому располагаются данные. Такие адреса гораздо проще менять. (т.к ненадо считать и мы можем указать любое новое место, без изменения в коде).
41F9 xx xx xx xx
43F9 xx xx xx xx и т.д.
Как уже упоминалось все данные являются либо byte, либо word, либо longword.
данные типа byte = dc.b
2 байта word = dc.w
longword = dc.l
Тип н-кых данных IDA определяет автоматически. Остальные вы должны определить сами. Менять типы данных можно нажимая хот-кей 'D'. Какой именно тип узнать можно по команде которая пойдет после lea, (т.е. команде чтения данных), если это будет move.w значит надо данные перевести в dc.w.
Пример переназченного типа:
Offsets.
Кроме кода и данных в роме также есть и оффсеты, это так называемые 'ссылки' на адреса. А уже по этим ссылкам могут располагаться как данные, так и код , и даже другие ссылки.
Ссылки почти всегда расположены массивами, (т.е. как таблицы статов).
Пример массива ссылок на подпрограммы:
Оффсеты определяются не хоткеем 'D', а хоткеем 'O'.
До нажатия 'O', это место выглядело так:
Т.е. если можно легко определить на 'глаз'.
Массив оффсетов на участки 'data'.
Как видно все оффсеты имеют тип longword. Однако в некоторых играх есть и двух-байтовые оффсеты, это не очень удобно, т.к. такие базы очень плохо сама дизасмит IDA (нужно определять самому), да и сами оффсеты от-ные. (эти оффсеты нельзя определить хоткеем 'O', только 'd')
Пример golden-axe 3:
Массив от-ных оффсетов на код с последующим JMP по этим ссылкам.
Как считать: обычно считаем от первого + значение: т.е. 3E26+E = 4134
3E26+12 = 3e38
3e26+22 = 3e48
По этим адресам расположились подпрограммы. (причем фактически они расположены в другом месте, тут расположен только код прыжка к ним (bra, jmp)-прыжки
Данная организация хоть и неудобна (для дизасма), но достаточно часто встречается, поэтому надо ее понять.
Отмечу, если вы читали какие-то доки где упоминается понятие поинтер, то под поинтерами понимают команды lea и оффсеты.
Некоторые ромхакеры считают поинтерами только оффсеты. Н-кые вообще понимают под ними любые адреса.
LEA и offsets могут быть как на ROM, так и на RAM.
Продолжаем работу с базой.
Правильным подходом в работе с базой IDA , перед её полным дизасмом и заполнением, является отделение стандартных данных, которые присутсвуют во всех играх. (таким образом нам не нужно будет проверять весь ром на код,данные или оффсеты).
К таким данным относятся: код процессора Z80, звуки и графика.
Процессор Z80 и его код.
Я уже упоминал что в сеге содержится второй процессор - ZILOG Z80. Процессор 8-битный и в 2 раза меньше по частоте, но это удачное решение, т.к. его использовали для проигрывания звуков и музыки.
Мы не будем его изучать, т.к. звуки можно менять и без этого, а изменение музыки достаточно сложная вещь, (т.к. музыка 'трекерная', вроде midi).
Но мы должны отделить его код.
Чтобы найти его мы должны перейти в IDA вначале к адресу A00000. Если вы уже сделали переименование системных адресов как описано в статье это место будет выглядеть так:
Z80_RAM:00A00000; Segment type: Pure data
Z80_RAM:00A00000; segment "Z80_RAM"
Z80_RAM:00A00000 Z80_RAM_: ds.b 1 ; DATA XREF: sub_0_12AAC
Делаем Jump to Xref to Operand:
Единственный переход и попадаем в сегмент:
(unk_0_19000) в этом случае адрес ROM, где находится код Z80. Подпрограмма выполняет копирование кода для процессора Z80 из картиджа (ROM) в RAM Z80, который имеет свою собственную память(отдельную микросхему), но она всего 8кб, против 65к основной.
Процессор MC68000 имеет сводобный доступ к этой микросхеме (т.е. к памяти z80), если вы смотрели карту памяти, адресное пространство выглядит для него A00000-A1FFFF. Копирование проводят так как z80 не читает программу с картриджа, а из собственной памяти (имеет ограниченный доступ к картриджу). Это соблюдается почти во всех ромах (если не во всех.)
В дальнейшем в эту память процессором mc68000 просто так 'лазить' нельзя, так как предварительно необоходимо делать 'захват шин'. (но в ходе программ это используется часто, т.к. если бы этого не было музыка и звуки играли независимо от игры, а приходится каждый раз указаывать z80, что ему играть.)
адреса вроде
Переходим к 19000:
В базе его нельзя дизасмнуть, т.к. это другой процессор и его команды другие. (можно открыть файл заного, и указать тип процессора Z80), но можно ли в одной базе дизассемблить 2 процессора я не знаю, скорее всего нельзя.
Код z80 представляет собой лишь один кусок, (т.е. в роме его больше нигде нет), теперь надо на глаз определить размер этого куска , выделить и сделать 'hide':
примерно тут конец:
(пошли нули).
выделяем область и заходим в view - hide. OK.
Результат:
Т.е. нам не пришлось ломать этот участок. (пытаясь понять, что же там).
Звук.
Теперь стоит выделить звуки. К тем звукам что можно открыть через редактор относится лишь оцифрованная речь,
пример озвучка larry в RRR, озвучка действия юнитов в Dune. Остальные звуки и музыку можно взломать лишь зная программирование.
Если ром содержит такую речь, открываем ром-файл в редакторе goldwave.
Следует использовать следующие настройки:
Требуемый рейт можно определить на слух, т.к. он определяет скорость проигрывания. Т.е. нужно подобрать, если проигрывается слишком медленно или слишком быстро.
Теперь прослушаем РОМ, наличие звука можно увидеть также на графике, в виде характерной синусоиды. Остальные области просто 'залиты зеленым', скрипы и писки говорят о том что мы просто слушаем код, данные, графику (т.е. читаем их как будто бы они бы звук).
Теперь найдем и выделим эту же область и сделаем в базе IDA 'hide' аналогично как с случае с Z80. Типичное представление звука в 16-ричном виде:
80 - говорит о тишине (начало звука), т.к. 8 битный звук (1 байт). где 80 как бы середина , а 0 и FF максимальный значения амлитуды колебаний.
Звук PCM (pulse code modulation), соотв. звукам типа WAV, т.е. и те и те 'несжатые' в отиличи от mp3.(mp3-сжатый WAV).
WAV отличается наличием заголвка в котором содержится информация о битности и размере.
В роме размер определяется программой.
Поскольку звук cчитывается процессором z80, мы не найдем на 'lea' на начальный адрес массива звуков. Однако могут быть массивы оффсетов на адреса для каждого звука. (абсолютные или от-ные).
Оффсеты могут быть и на музыку.
Пример 'взломанных' относительных оффсетов:
$36CC адрес начала звука, от-но адреса $20000.
$1A70 - размер (длительность) звука.
Это требует доли смекалки, т.е. сразу так догадаться ни у кого не получается.
Хайд:
* Вы можете заменять звуки как угодно через goldwave. (т.е. это можно делать и без изучения рома через IDA и WINHEX)
Графика:
Для нахождения и изменения графики в роме используются т.н. тайловые редакторы.
Откроем ROM с помощь тайлового редактора:
YY-CHR V0.98
File->open
Во вкладах выставим 4Bpp MSX/GENESIS.
Теперь используя стрелки найдем нечто похожее на графику. 'Каша' означает что это не графика (а данные, код, звук).
Т.е. как в goldwave мы слышли скрипы, тут видим кашу.
В случае нахождения графики (например машины или персонажа), стоит прокрутить все опции (вместо Normal другие), это выбирает порядок расположения тайлов. (блоков графики).
Нужный порядок(карта тайлов) задается в программе игры. Сама карта является 'data'ой.
Также палитра (набор цветов) задается в программе. Палитры расположены в других, отедельных от графики местах.
в YY-CHR на глаз можно подобрать нужную палитру.
Пример в роме Rock n' Roll Racing машины (их части) можно увидеть в конце рома.
Конец их графики уже известен, теперь надо определить начало, адрес с которого примерно начинается графика машин BF400.
(это видно в YY-CHR) сверху на вкладке на file open и т.д.
yy-CHR (BF400/100000).
Теперь идем к этому адресу в IDA.
Теперь будем искать переход (запрос) на чтение графики программой.
XREF нашелся по адресу BF500
код после jump to xref.
В этом случае использовалось не lea или move, а addi. Это более редкий вариант. Также Xref может идти к оффсету (а от него уже к программе).
Если вы ничего не нашли кроме 'каши', значит графика сжата. (т.е. заархивирона как winrar). Также часть графики может быть сжата, а часть не сжата . Пример RRR - (cжата графика планет и аватары).
Это сделано для экономии места, т.к. картирджная память была дорогая и место было ограничено.
Сжата может быть не только графика, (в RRR сжаты также конфиги трасс, и палитры планет).
Графика 'расжимается' программно подпрограммой-распаковщиком, переносясь в RAM. Расжимается только что-то одно конкретное (графика одной планеты), т.к. место в RAM еще более ограничено.
С помощью winrar или zip, эти архивы открыть нельзя. В каждой игре использовались свои аглоритмы архивирования, но тем не менее есть многих похожих (напр. LZSS).
Без специальных программ распаковки их вскрыть нельзя. Для бол-ва форматов и игр можно найти соотв. программы распаковщики.
Также в редких случаях может использоваться 2 или 3 разных способа сжатия.
Чтобы вскрыть архивы, если программа-распаковщик открывает только их, а не ром целиком, надо найти их точные адреса.
Адреса и размеры могут быть заданы оффсетами:
Пример организации архивов в RRR, от-ные ссылки на архивы:
6B000 + 37C = первый архив по адресу 6b000+37c = 6b37c второй 6B000+688 = 6b688, размер архива не задан - высчитывается разницей между соседними архивами.
Размер также может быть указан рядом, быть задан в программе, находится в самом архиве, быть заданным (фиксированным) - для однотипных архивов.
цифра $20 в данном случае не используется, видимо в н-кых писали как пробел вместо 00.
Чтобы понять как именно устроено надо изучать программу.
"Хайд":
"Отрезали солидные куски", Во всех остальных частях РОМа находятся код, данные и пустое место, которые нужно отделить друг от друга.
Пустое место может быть не только 'Нулями' '00', может быть 'залито' 'FF'.
Замечу что в несжатой графике тоже много нулей, но это не пустое место. (т.е. если мы начнем туда что-то совать,
например свой код, мы получим подпорченную графику - модели машин с 'артефактами'.). Чтобы не гадать просто расширяйте РОМ как описано в гайде. К тому же при расширении вы будет знать, что записывали в новую облсть.
(а не сунули там куда-то в середину , а куда забыли.)
Data hacking. часть3.
Кроме описанных данных в РОМе содержатся 'типичные' данные (т.е. содержатся в любой игре) :
К этим данным можно отнести:
Палитры (наборы цветов)
Комбинации кнопок (игры с комбо-ударами или пос-ти на читы)
Значения от нажатий кнопок в RAM.
Ascii - текст, если игра использует данный вид текста.
Палитры.
Это наборы цветов которые необходимы для 'раскраски' графики.
в HEX-виде палитры выглдят следующим образом:
0EEE, 0AC8, 0246, 0E00, 000A. (тип данных word).
разобраться в них достаточно просто - '0BGR' , (blue green red) т.е. первая цифра соотв. кол-ву синего, вторая зеленего, третья - красный.
Комбинируя 3 составляющие можно получить любой цвет 000 - черный 0EEE (белый) 0888 - (серый)
Цифры могут быть только четными (0,2,4,6,8,a,c,e) - это говорит о 9 битности цвета. 8^3=512 цветов.
(но одновременно железо сеги позволяет отображать только от 16 до 61 (в лучшем случаем)) цветов.
Поэтому и используются палитры.
Типичный вид палитр: (в примере палитры уже переведены в вид word - кнопка 'D' , если забыли)
Палитра в RRR для синих машин:
В некоторых случаях палитры могут быть сжаты (запакованы).
Некоторые ромхакеры для быстрого поиска палитры используют сейв-файлы эмулятора. (в них хранится текущая палитра).
Скопировав через WINHEX и вбив в поиск соотв. цифры можно найти эту палитру.
Можно просто поискать в ром-файле популярные цвета (0EEE), в winhex search-find-hex values - 0EEE, ok.
Текст в формате ascii. (это обычный текст на английском).
Его можно найти в winhex в правой вкладке, о чем упоминалось вначале.
в IDA текст по умолчанию выглядит так:
Для преобразования в строку, выделите нужное слово и нажмите хоткей 'a'.
Итог:
Рекомендуется сразу же удалить, образовавшиеся в результате метки. (aPlayer) , т.е. делаем rename и оставляем пустое поле.
Иначе ваша база меток (вкладка NAMES в IDA) , окажется забитой ненужной кучей ссылок на текст.
Кроме того если строка получилась длинной, и метка тоже, это может вызвать баг.
Как я уже упоминал в названиях следует использовать короткие имена - не более 14 символов.
Если текста много можно скрыть область ('hide').
Последовательности кнопок.
Каждому нажатию кнопки соотв. определенный код. Этот код записывается в RAM.
Самый частый вариант комбинации 'нажатие - код'.
ВВЕРХ - 0100
ВНИЗ - 0200
ВЛЕВО - 0400
ВПРАВО - 0800
A - 4000
B - 1000
C - 2000
start - 8000
Если игра использует 3-кнопчный контроллер, значения скорее всего будут 1-байтные. т.е. 01, 02, 04, 40, 20 и т.д.
Второй байт нужен для кнопок X Y Z MODE.
при нажатии A+B получается 'сумма битов' нажатий , т.е 5000.
Где находятся значения в RAM следует искать с помощью поиска читов. (зажимайте вверх + нажмайте esc для паузы эмуляции, теперь можно искать это значение в памяти не удерживая 'вверх' :) )
Если вы нашли верное значение, то при нажатии кнопок оно будет меняться в соотв. с этими кодами.
Значение может быть в нескольких адресах (на нажатие, отжатие и т.д.).
в IDA эти значения можно переименовать как Joy_data. Т.е. также как мы искали и переименовывали другие переменные.
Также их можно найти через IDA, по xrefs'y от адреса 00A10002 (порты), попав к программе-драйверу джойстика.
(может еще быть a10005). И изучив эту программу (куда в RAM она записывает значения).
Заданные последовательности кнопок: (эти последовательности прописаны в ROM) .
Программа устроена так что сверяет значения из RAM cо значениям из ROM. (и если всё совпало - условие выполнено - идет переход к коду спецудара или включению чита).
RRR - Секретный код выбор 'Олафа'.
$FFFF в этом случае означает 'конец'. Данные комбинации можно найти и без IDA, (как и в случае с палитрами).
Однако если значения были 1-байтные , обычным поиском через hex это будет практически невозможно.
Подводные камни и прочие трюки.
** игры от EA и другие игры которые не запускаются при любом изменении.
Снятие 'защиты'. Hot trick.
Используйте 'MASTER' code из книги гейм-гени кодов Codebook.exe или с сайтов где описаны гейм-гени коды.
Этот код описывается как необходимый для того,чтобы работали все остальные коды.
На самом деле он является кодом отключения защиты.
Переведя этот код в формат Adress:data, и вписав это значение через WINHEX в ром-файл мы отключим код проверки дополнительной чексуммы.
Прежде чем продолжать дальше дизасмить базу (определять данные и код).
Важно знать следующие баги в IDA:
"-1(a0) bug"
При дизасме IDA автоматически определяет отрицательные от-но регистров (a0), (a1) и т.д. смещения как адрес RAM FFFFxxxx. На самом деле это не так, так произойдет только в том, случае если в регистр был равен a0=00000000. А как мы уже знаем, он может быть равен чему угодно.
a4 не обязательно равен 00000000.
Исрпавляем (нажав хоткей 'q') :
В случаях если игра не использует данный метод обращения к 'копии' RAM (FFFFxxxx), можно вообще удалить этот сегмент.
Вы должны быть уверены что вы делаете, и что точно не использует прежде чем удалять. Dune использует все три варианта обращения к RAM.
* сегмент RAM FFFF0000 - FFFFFFFF, можно удалить в базе Rock n' Roll Racing.
"offset bug"
IDA автоматически определяет многие адреса как оффсеты, хотя они ими не являются.
Пример (dune):
Из идущих вслед значений нельзя получить нормальные оффсеты (нельзя продолжить массив - таблицу адресов).
Исправление:
Провести undefine на данные значение (хоткей 'U')
В большом кол-ве этот вид бага можно получить если вы делали 'final analisys pass'.
"move.w #loc_ bug. "
Баг - число принимается за адрес (метку).
Пример:
Исправление (нажать q на число):
# - говорит о том что, это число, а не адрес. В некоторых случаях число все же может являются адресом (или его частью).
Это можно понять лишь значительно изучив программу и ассемблер. в 90% случаях это является багом.
Поэтому его нужно фиксить. Этот вид 'бага' может присутсвовать в огромном кол-ве. Поэтому не старайтесь сразу его исправить.
"Баг строк"
Этот баг может возникнуть в случае использования длинных ascii строк или создания такой без выделения, а также если вы делали 'final analysis pass'. Баг состоит в том, что начинает глючить список имен (+забивается ненужными именами).
Также можно схватить и 'too many lines' баг.
Баг too many lines' в Dune. (IDA определила как строку автоматически при final analysis).
Решение:
Сделать undefine на всю область.
А также удалить названия(имя метки ascii).
Также если вы не заполняли базу, создайте новую с нуля и не делайте final analysis.
Дизасм данных как кода:
Баг когда IDA автоматически дизасмит данные как код.
Как мы уже помним любой код заканчивается на rts, jmp, bra или rte.
Решение - сделать undefine.
Трюки:
Исправление адреса от-но регистра. Это очень важный трюк. Он позволит получить абсолютный доступ к RAM в IDA, даже для от-ного метода адресации. (а значит мы сможем задать и метки и видеть точный адрес).
Этот способ я использовал для фикса адресов в Rock n' Roll Racing.
ДО:
ПОСЛЕ:
Получил доступ к меткам и абсолютным адресам в RAM, где подписаны найденные мною переменные.
В данном случае я знал a4=FF8000, т.к. в RRR он всегда равен FF8000.
Если я нажму на метку я перейду в IDA в абсолютный адрес: $FFB95E. (395E+FF800)., т.е. реальный адрес RAM куда пишется значение.
Во всех остальных случаях регистр быть равен чему угодно, но и там его можно 'отследить'. Для этого надо изучить код, или использовать дебаг на pc на этот ром-адрес. Регистр может быть равен всегда чему-то одному, а может принимать разные значения. (во-втором случае исправление 'неточное', т.к. даст переход только к одному адресу, но это тоже бывает полезно).
Dune:
Трюк выполняется следующим способом:
Выделяем нужный адрес (цифру $395E) и нажимаем CTRL+R. В поле Base adress вписываем адресс который находится в регистре.
Ставим галочку treat base adress as plain number. OK.
Некоторые могут заявить что это не трюк, однако многие известные мне ромхакеры этого не знали, поэтому назыв. так.
Трюк с созданием таблиц:
Допустим вы нашли какие-то данные, знаете за что, они отвечают и хотите их упорядочить.
Для этого выделяем область и жмем правой кнопкой->array. Тут указывается что-то вроде длины и ширины таблицы.
Таблица порядка номеров трасс в RRR данным способом:
(для первой планеты по 4, для второй по 5 и т.д.)
Трюки и хоткеи в winhex.
Простой поиск данных.
Например вы ищите точное значение (конретное число), и это число достаточно длинное, т.е. например цена машины.
Число может быть представлено как в 10-чной системе, так и 16-ричной.
в RRR для цен используется десятичная система. цена 24000$.
в поиск вбиваем '00240000', если значений нашлось н-ко следует проверить по группам, или каждое по очереди.
используйте 'replace hex values' для замещения и поиска всех сразу. (для поиска например в части рома выделите область и используйте поиск только в блоке - галочка search in block only.)
Если число 16-ричное (в бол-ве игр именно такое), его надо перевести на калькуляторе и потом искать.
24000= $5DC0, т.е. следовательно надо было вбивать в поиск '5dc0' или '00005dc0'
Если игра содержит много таблиц, (как например rock-n-roll racing - таблица порядка трасс, хар-ки тачек, игроков, список цен, таблицы хар-к для AI (уровни сложности).
в WinHEx в ascii-виде (правая колонка) эти таблицы выглядит в виде точек. Либо других повторяющихся последовательностей
Пример (таблица бонусов игрока + комбо на чит) - точки в ascii. (правая колонка).
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00007320 43 EC 51 9A 12 3B 00 1D D3 31 80 00 4E 75 01 00 C?Q?.;..?1€.Nu..
00007330 01 00 00 01 01 10 10 00 00 10 00 10 00 08 08 08 ................
00007340 00 00 08 00 00 00 01 01 01 01 00 03 00 02 00 03 ................
00007350 00 04 00 00 00 04 00 03 01 00 08 00 01 00 08 00 ................
00007360 02 00 04 00 02 00 04 00 08 00 FF FF E5 40 41 EC ..........???@A?
То есть 'data'-hacking возможен в чистом хекс. Но все зависит от конретной игры. Я например нашел эти 'gamedata' таблицы используя только winhex, также в dune2 я разобрался в конфиге карты, без изучения кода. (т.е. каждое значение соотв. в карте номеру юнита, его координатам на карте и жизням) - что легче определить опытным путем., чем взламывать код.
Хоткеи WINHEX:
CTRL+C - копировать
CTRL+B - 'вставить' (записать), не следует использовать CTRL+V, иначе мы сдвинем все данные.
CTRL+SHIFT+C и ALT+SHIFT+C - копировать значения, для переноса в текстовый файл. (.txt). например на форум.
ctrl -копирует только сами значения, alt - все отображение (ненадо делать скриншот)
ctrl+s - сейв файла.
ctrl+z - отмена последних изменений (очень полезный хоткей, когда игра после изменений зависла, и надо отменить, позволяет обходится без бек-апов).
ALT+G - прыжок к нужному адресу.
Также можно включить режим мнговенного редактирования (ненадо будет делать сейв):
Нажать F6, и выбрать Default Edit Mode (editable).
Также в winhex есть опция открытия жестого диска, и можно восстановить удаленные н-кые файлы.(и ненадо применять программы для восстановления). Хотя это и выходит за рамки гайда (но считаю полезным), т.к. если что-то 'полетит' вы сможете восстанавить базу с помощью winhex (но не 100%) - так что делайте бекап баз на CD-диск.
Трюки с ромами:
Используйте total commander для сравнения двух файлов. Например оригинал и пиратский хак, или просто хак.
Таким образом вы можете узнать где, и что менять, чтобы получить такой же результат. Также это поможет взломать защиту, если другие методы не помогли.
Также сравнивайте свой хак с оригиналом, если забыли где и что меняли, а также на наличие ошибок (когда забыли отменить изменения и они остались).
Заключение:
Таким методом можно взломать любую игру на Sega, также можно использовать некоторые подходы и для других платформ.
В случае если вы ничего не поняли из сего гайда, Вам остается курить бамбук. Так как понятнее может быть лишь с
картинками, а автору это пока что не под силам, т.к. сам мануал получился немаленьким.
Если вы всё поняли, и вам этого недостаточно, то стоит искать более сложные мануалы, ориентированные на что-то одно (например тех. документация на сегу, или руководство программиста по ассемблеру mc68000), т.е. не надейтесь что всё сделают за вас. Если Вы с чем-то несогласны это остается с вами. Если Вы нашли ошибку вы можете написать ее в ПМ автору.
Также не следует задавать вопросов автору (он не обучает хакингу, а только предоставляет сей мануал). Также не следует спорить, о том как нужно писать мануал и что в нем надо переделать. А также запрещается копировать текст из мануала и куда-то его заливать.
Удачного ромхакинга!
Hack guide by Ti. (с) 2010.
*********************************************************************************************************************
****************** demo (not finished) version of guide *************************************************************
*************************************************************************************************************
Ромхакинг для начинающих. Sega Mega Drive.
Гайд по взлому игр Sega. Автор Ti.
В этом гайде будут рассмотрены методики взлома игр с приставки Sega Mega Drive. Взлом игр с других платформ может значительно отличаться, поэтому не рекомендуется использовать тут написанное, как шаблон, если только вы не понимаете что делаете. Гайд ориентирован на новичков, к тому же автор не является професcиональным программистои и программистом вообще, поэтому все определения и названия могут и будут отличаться. Под взломом понимается изучение и изменение самой игры, а не замена графики или звуков, это будет затронуто лишь вкратце.
Также автор не отвечает за причиненный вред психологическому состоянию, в случае неудачных попыток хакинга.
Важно:
Что необходимо знать:
16-ричная и двоичная система счисления и их отличия от десятичной.
Что такое ROM.
Что такое RAM.
Что такое байт(byte),бит.
Иметь общее представление о работе компьютера.
Если вы не знаете что это такое или не уверены лучше не читайте этот гайд!
Для взлома понадобятся следующие программы:
IDAPro v5.2 с sega loader'ом. (Альтернативы нет!)
WinHex или любой другой HEX-редактор. (В примерах будет рассмотрен WinHEX, но принцип работы у всех одинаков)
GENSVKNTrace - модификицая эмулятора GENS c расширенным дебаггером.
Gens-mk2 (с сайта шедевра) - эмулятор с безглючным поиском читов(значений в памяти).
Gens11/GensKMOD - также можно запастись и этими.
FixCheckSum.exe - программа исправления контрольной суммы рома, требуется для игр с защитой.
GGConv.exe - конвертер гейм гени кодов(читов) в формат Адресс:значение.
Goldwave - редактор звуков если вдруг решили заменить звук.(имеется ввиду речь).
Тайловый редактор - Он будет нужен чтобы узнать где именно в роме лежит графика. Примеры редакторов - YY-CHR V.098, djinn Tile mapper, tile molester, tile layer pro и т.д.
Если вы не смогли скачать("где это скачать", "у меня не работает ссылка" и т.д.) данные программы не переходите к
дальнейшим пунктам! Научитесь скачивать потом ломать ромы!
Многие ссылки можно найти тут:
romhacking
Введение.
Форматы представления данных.
В сеге все значения можно поделить на 3-типа =
byte = значение в 1байт. (.b)
word = значение 2байта. (.w)
longword = значение из 4байтов. (.l)
Именно такими значениями оперирует процессор.
байт это число от 0 до $FF (0-255) (в бол-ве случаев от -128 до +127) \ это важно учитывать!.
ворд это число от 0 до $FFFF (0-65535) (в бол-ве случаев от -32768 до +32767) /
символ $ перед числом говорит о его 16-ричном представление.
Железо сеги.
ROM (read-only-memory)-память только чтения - пзу картиржа (картирдж) - то что на нем записано - ром-файл.
RAM (random access memory) -оперативная память (временная) - работает только при включение питания.
Процессор сеги (Motorola 68000) - выполняет операции между ram, rom и собственными регистрами и другими системными устройствами.
VDP (видеопроцессор),
Z80 (доп.процессор), используемый для звуковых программ.
Порты джойстиков.
YM2612 - звуковой чип.
PSG-еще один звуковой чип (шумогенератор).
Прежде чем вскрыть ром.
Распакуйте его если он в архиве, также ром должен быть формата .BIN (или .GEN)
Что содержится в роме? В роме нет файлов. Все данные, расположенные в роме - графика, музыки, звуки, код (программа), могут быть расположены как угодно, а их точное располжение (адрес) определяется программой.
Вскрытие рома.
Для начала откроем РОМ с помощью WINHEX. (File-Open).
Откроется окно, где слева отображается некоторая информация о файле, чуть правее Offset - адрес текущего расположения, посередине большое окно с кучей цифр - 16ричное представление, и справа ASCII-представление. Обычно вначале картирджа располагается информация(заголовок) об игре, который можно прочитать в текстовом (ascii)-виде.
Можно прокрутить ползунок по всему рому, чтобы поискать нет ли еще где такого текста. Если есть его как правило можно безболезненно поменять. Не пытайтесь менять другие цифры в надежде получить хороший результат.
Важно:
Если нажать на колонку offset мышкой колонка адресов преставиться в 10-чной системе, это очень частая ошибка когда случайно так нажимают, мы будем использоваться только 16-ричную систему, если нажали надо нажать еще раз чтобы вернуть обратно, это станет заметно по наличию букв в адресах.
Итак, как же работает игра? Начальный адрес программы задается по адресу 4.
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00000000 00 FF FF 00 00 00 02 10
$00000210 - тип longword (полный адрес) в вашем случае адрес может отличаться (как правило $200)
Теперь если перейти к этому адресу (Position-go to offset-210-ok), мы окажемся вначале программы
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00000210 4A B9 00 A1 00 08 66 06 4A 79 00 A1 00 0C 66 7C
00000220 4B FA 00 7C 4C 9D 00 E0 4C DD 1F 00 10 29 EF 01
Эти цифры представляют собой машинные коды, которые читает и выполняет процессор, отображенные в 'удобном' 16-ричном виде.
К счастью любой такой код можно перевести в код языка Ассемблера, однако следует помнить что ром не состоит из одних кодов, цифры могут означать и что угодно (графика, данные и т.д.).
например данный код: 4A B9 00 A1 00 08
до компиляции (преобразовании из ассемблера в машинные коды) выглядит так:
tst.l ($A10008).l
Процессор начинает считывать и выполнять программу с картиджа сразу при включении. Все коды читаются один за другим непрерывно, также программа перейти из одного адреса в другой если это указано или условие перехода выполняется (переход, прыжок).
Самым лучшим способом отделения программной части игры от всего остального (графики, звуков) является дизассемблинг.
В этом нам поможет IDAPro. (используем IDAv5.2 с sega loader'ом(c) от HardwareMan'a)
Запускаем idag.exe
OK.
NEW-disassemble new file.
Выбираем РОМ-файл.
OK.
OK.
Появится окно IDA View-A.
Немного прокрутим ползунок до адресса $210. (в данном случае)
Увидим следующее (или похожее) :
ROM:00000210; =============== S U B R O U T I N E =======================================
ROM:00000210
ROM:00000210
ROM:00000210 global RESET
ROM:00000210 RESET:
ROM:00000210 tst.l (unk_0_A10008).l
ROM:00000216 bne.s loc_0_21E
ROM:00000218 tst.w (word_0_A1000C).l
ROM:0000021E
ROM:0000021E loc_0_21E: ; CODE XREF: RESET+6j
ROM:0000021E bne.s loc_0_29C
ROM:00000220 lea unk_0_29E,a5
ROM:00000224 movem.w (a5)+,d5-d7
ROM:00000228 movem.l (a5)+,a0-a4
ROM:0000022C move.b byte_0_FFFFEF01(a1),d0
ROM:00000230 andi.b #$F,d0
ROM:00000234 beq.s loc_0_23E
ROM:00000236 move.l #$53454741,$2F00(a1)
ROM:00000210
ROM:00000210
ROM:00000210 global RESET
ROM:00000210 RESET:
ROM:00000210 tst.l (unk_0_A10008).l
ROM:00000216 bne.s loc_0_21E
ROM:00000218 tst.w (word_0_A1000C).l
ROM:0000021E
ROM:0000021E loc_0_21E: ; CODE XREF: RESET+6j
ROM:0000021E bne.s loc_0_29C
ROM:00000220 lea unk_0_29E,a5
ROM:00000224 movem.w (a5)+,d5-d7
ROM:00000228 movem.l (a5)+,a0-a4
ROM:0000022C move.b byte_0_FFFFEF01(a1),d0
ROM:00000230 andi.b #$F,d0
ROM:00000234 beq.s loc_0_23E
ROM:00000236 move.l #$53454741,$2F00(a1)
Вот это и есть программа(код) игры на языка Ассемблера, точнее только ее маленькая часть (самое начало).
Рекомендуется включить сразу текстовый вид (правая кнопка - text view), иначе при прокрутке начнут вылезать графики.
Каждая строчка представляет собой команду для процессора, где слева - сама команда, а справа, то над чем её проводить (адрес, число, регистры). Также в среде программистов именуются инструкциями, опкодами и прочее.
Теперь если выделить любую команду мышью, а затем перейти во вторую вкладку (Hex view-A), мы увидим её отображение в РОМЕ в 16-ричном виде и место расположения. Команда будет выделена зеленым и может быть разной длины (от 2 до 10байт и более). Данная "фишка" позволит нам в дальнейшем с легкостью их находить и менять если нужно.
К сожалению IDA не может определить сама расположение всех частей программы (т.е. отделить весь игровой код, от всего остального), поэтому доделывать за неё это придётся нам.
В зависимости от игры и наших целей это можно делать, а можно и не делать.
Опция в IDA , Options-General-Kernel Options 1- Make final analysis pass (поставить галочку) и далее нажать Reanalyze Program позволяет отделить больше кода чем обычно, но это вызывает и излишки когда куски не кода, определяются тоже как код.
Это не страшно так как в IDA всегда можно преобразовывать данные в код и обратно. Используйте эту опцию (можно еще нажать её н-ко раз) если IDA отделила слишком мало кода (кол-во определяется по большой полосе сверху на вкладкой).
Есть два простых хоткея преобразования туда-обратно: это 'C' (code) и 'U' (undefine) - отмена.
Попробуйте сразу нажать 'U' на место где есть код, а потом снова 'C', чтобы понять как это работает.
Теперь прокрутим ползунок чуть дальше, до первого места где программа пропадет.
ROM:00000298 move #$2700,sr
ROM:0000029C
ROM:0000029C loc_0_29C: ; CODE XREF: RESET:loc_0_21Ej
ROM:0000029C bra.s loc_0_30A
ROM:0000029C; ---------------------------------------------------------------------------
ROM:0000029E unk_0_29E: dc.b $80; ? ; DATA XREF: RESET+10o
ROM:0000029F dc.b 0
ROM:000002A0 dc.b $3F; ?
ROM:000002A1 dc.b $FF
ROM:000002A2 dc.b 1
ROM:000002A3 dc.b 0
ROM:000002A4 dc.b 0
ROM:000002A5 dc.b $A0; ?
ROM:000002A6 dc.b 0
ROM:000002A7 dc.b 0
ROM:000002A8 dc.b 0
ROM:0000029C
ROM:0000029C loc_0_29C: ; CODE XREF: RESET:loc_0_21Ej
ROM:0000029C bra.s loc_0_30A
ROM:0000029C; ---------------------------------------------------------------------------
ROM:0000029E unk_0_29E: dc.b $80; ? ; DATA XREF: RESET+10o
ROM:0000029F dc.b 0
ROM:000002A0 dc.b $3F; ?
ROM:000002A1 dc.b $FF
ROM:000002A2 dc.b 1
ROM:000002A3 dc.b 0
ROM:000002A4 dc.b 0
ROM:000002A5 dc.b $A0; ?
ROM:000002A6 dc.b 0
ROM:000002A7 dc.b 0
ROM:000002A8 dc.b 0
$0000029E - числа начиная с этого адреса не являются кодом. Это данные, ну или как можно назвать 'gamedata'.
Суда может входить что угодно (и графика и звуки, конфиги уровней, хар-ки персонажей, комбинации кнопок, ascii текст, архивы, цены игровых предметов и т.д.)
Однако можно 'насильно' попробовать их представить как код (нажав C).
ROM:0000029E loc_0_29E: ; DATA XREF: RESET+10o
ROM:0000029E or.b d0,d0
ROM:0000029E; ---------------------------------------------------------------------------
ROM:000002A0 dc.b $3F; ?
ROM:000002A1 dc.b $FF
ROM:000002A2; ---------------------------------------------------------------------------
ROM:000002A2 btst d0,d0
ROM:000002A4 ori.l #$A1,-(a0); '?'
ROM:000002AA move.b d0,-(a0)
ROM:000002AC ori.l #$120000C0,-(a1)
ROM:000002B2 ori.b #(dword_0_0+$C0),d0
ROM:000002B6 ori.b #$14,d4
ROM:000002BA move.w #$76C,d0
ROM:000002BE ori.b #0,d0
ROM:000002BE; -------------------------------------------------------------------
ROM:0000029E or.b d0,d0
ROM:0000029E; ---------------------------------------------------------------------------
ROM:000002A0 dc.b $3F; ?
ROM:000002A1 dc.b $FF
ROM:000002A2; ---------------------------------------------------------------------------
ROM:000002A2 btst d0,d0
ROM:000002A4 ori.l #$A1,-(a0); '?'
ROM:000002AA move.b d0,-(a0)
ROM:000002AC ori.l #$120000C0,-(a1)
ROM:000002B2 ori.b #(dword_0_0+$C0),d0
ROM:000002B6 ori.b #$14,d4
ROM:000002BA move.w #$76C,d0
ROM:000002BE ori.b #0,d0
ROM:000002BE; -------------------------------------------------------------------
Данные представились как код, но это неправильно, т.к. это просто совпадение. Поэтому надо сделать Undefine обратно.
Как точно определить данные это или же код, будет рассмотрено немного позже.
Однако скажу что любой код заканчивается на команды:
jmp (прыжок)
bra (прыжок)
rts (возврат)
rte (возврат из исключения)
Если же у вас участок кода закончился на любую другую, а далее идет 'разрыв' и 'C' не срабатывает, то это не КОД.
ROM:0000029E or.b d0,d0
ROM:0000029E; ---------------------------------------------------------------------------
ROM:000002A0 dc.b $3F; ?
ROM:000002A1 dc.b $FF
ROM:0000029E; ---------------------------------------------------------------------------
ROM:000002A0 dc.b $3F; ?
ROM:000002A1 dc.b $FF
or.b d0,d0 - не код. жмем 'U'. следующий кусок тоже не код, т.к. заканчивается на ori.b #0,d0
Почему так? если бы процессор выполнял команду or.b d0, d0; следующая за ней шла бы 3FFF, а она не является командой процессор и игра бы просто повисла или перезапустилась. Именно поэтому нельзя в РОМ-файле менять цифры от 'балды', т.к. задевая программную часть мы портим последовательность действий.
Важно знать!, что хоть data и не является кодом, однако может представлять т.н. ссылки на код или ресурсы (offsets) - то есть адреса.(отделение адресов будет рассмотрено позже)
Так что же нам это всё дает? Наверное вы уже слышали понятия ASM-hacking и Data-hacking.
Так вот асм-хакинг это изменение(хакинг) кода, требует знания программирования (на самом деле можно хакать и не зная, достаточно запомнить парочку команд, а как я расскажу позже).
Дата-хакинг это изменение игровых данных, простой способ определить за что отвечали те или иные данные, заполнить эту область нулями (не задевая код), и посмотреть что изменилось.
Рекомендуется искать такие области начиная с адреса $1500 (но всё зависит от конкретной игры!), обычно вначале идут системные данные (связанные с информацией о регионах), которые менять ненужно или нельзя.
Чтож если вы поняли и вам уже захотелось попробовать, ищем в IDA-участки 'Data', переходим по этим же адресам в WinHex'e, выделяем область , жмем Edit-Fill block-Fill with hex values - 00, OK. Сохраняем и открываем ром в эмуляторе. Если РОМ не запускается, зайдите в опции эмулятора и поставьте галочку Auto Fix Chechsum / Править CRC Рома. Если РОМ все равно не запускается, отмените в WinHEx изменения (CTRL+Z) и пересохраните файл. Если игра теперь запускается значит, область была важной и просто так её изменять нельзя, попрбуйте найти другую область данных. Если игра от Electronic Arts**, то стоит
дополнительная защита, которую нужно предварительно снять, также доп. защита может быть и в других играх. Определить есть защита или нет просто - если игра не запускается при любом изменении - значит есть.
В случае удачных изменений, т.е. что-то изменилось и вы поняли что, следует изучать данный участок.(попробовать залить не 'нулями', редактировать цифры по одной и выявлять закономерности):
Пример области 'data':
ROM:00007328 add.b d1,(a1,a0.w)
ROM:0000732C rts
ROM:0000732C; ---------------------------------------------------------------------------
ROM:0000732E unk_0_732E: dc.b 1
ROM:0000732F dc.b 0
ROM:00007330 dc.b 1
ROM:00007331 dc.b 0
ROM:00007332 dc.b 0
ROM:00007333 dc.b 1
ROM:00007334 dc.b 1
ROM:00007335 unk_0_7335: dc.b $10
ROM:00007336 dc.b $10
ROM:00007337 dc.b 0
ROM:00007338 dc.b 0
ROM:00007339 dc.b $10
ROM:0000732C rts
ROM:0000732C; ---------------------------------------------------------------------------
ROM:0000732E unk_0_732E: dc.b 1
ROM:0000732F dc.b 0
ROM:00007330 dc.b 1
ROM:00007331 dc.b 0
ROM:00007332 dc.b 0
ROM:00007333 dc.b 1
ROM:00007334 dc.b 1
ROM:00007335 unk_0_7335: dc.b $10
ROM:00007336 dc.b $10
ROM:00007337 dc.b 0
ROM:00007338 dc.b 0
ROM:00007339 dc.b $10
И её отображение в HEX. (т.е. пробуем менять цифры с адреса 732E до 7369)
00007320 43 EC 51 9A 12 3B 00 1D D3 31 80 00 4E 75 01 00
00007330 01 00 00 01 01 10 10 00 00 10 00 10 00 08 08 08
00007340 00 00 08 00 00 00 01 01 01 01 00 03 00 02 00 03
00007350 00 04 00 00 00 04 00 03 01 00 08 00 01 00 08 00
00007360 02 00 04 00 02 00 04 00 08 00 FF FF E5 40 41 EC
Примечание: в IDA значения менять нельзя, это только просмотрщик. Меняем через WinHEx.
Если вы не поняли, или хотите перейти дальше к более совершенным методам читаем.
Карта памяти:
ROM:0000000 - ROM:003FFFFF (размера РОМа до 4мб)
Z80_RAM:00A00000 - Z80_RAM:00A01FFF (память процессора Z80)
VDP_data:00C000002 (видеопроцессор)
VDP_CONTROL:00C00004
RAM_:00FF0000 (ОЗУ (RAM))
RAM_:00FFFFFF
RAM:FFFF0000 (ОЗУ (RAM)) *в данном случае 00FF0000 тоже самое, что FFFF0000. (и то, и то является памятью и одним
RAM:FFFFFFFF и тем же адресом, это происходит потому что первый байт не читается, т.к. процессор
имеет лишь 24битную шину адресации. (до 16мегабайт)
Z80_RAM:00A00000 - Z80_RAM:00A01FFF (память процессора Z80)
VDP_data:00C000002 (видеопроцессор)
VDP_CONTROL:00C00004
RAM_:00FF0000 (ОЗУ (RAM))
RAM_:00FFFFFF
RAM:FFFF0000 (ОЗУ (RAM)) *в данном случае 00FF0000 тоже самое, что FFFF0000. (и то, и то является памятью и одним
RAM:FFFFFFFF и тем же адресом, это происходит потому что первый байт не читается, т.к. процессор
имеет лишь 24битную шину адресации. (до 16мегабайт)
Также есть куча других системных адресов (порты и т.д.). Процессор имеет доступ ко всем этим адресам.
В Loader который мы используем уже прописаны все эти адреса. Теперь мы начнем заполнение базы IDA для конкретной игры, начав с этих системных адресов, это даст нам в дальнейшем много преимществ.
VDP_data:00C00000; Segment type: Pure data
VDP_data:00C00000; segment "VDP_DATA"
VDP_data:00C00000 unk_0_C00000: ds.b 1 ; DATA XREF: sub_0_7D0:loc_0_7D6w
VDP_data:00C00000 ; sub_0_7E2+4o ...
VDP_data:00C00001 ds.b 1
VDP_data:00C00001; end of 'VDP_DATA'
VDP_data:00C00000; segment "VDP_DATA"
VDP_data:00C00000 unk_0_C00000: ds.b 1 ; DATA XREF: sub_0_7D0:loc_0_7D6w
VDP_data:00C00000 ; sub_0_7E2+4o ...
VDP_data:00C00001 ds.b 1
VDP_data:00C00001; end of 'VDP_DATA'
Жмем правой кнопкой на unk_0_C00000 - Rename(N) переименовываем в VDP_DATA_, OK.
Это нужно проделать со всеми этими адресами где есть ukn_0_ (они пойдут после области ROM). (в IDA черные области на полосе)
Теперь выделим наш переименованный адрес правой кнопкой, и найдем там строчку Jump to Xref to operand. Должен появится список из одной или нескольких строк. Можем перейти по любой - попадем в участок кода, где этот адрес запрашивается, (там тоже будет автоматически переименовано), это подскажет нам о том, что данный участок используется для чего-то связанного с выводом графики. (т.к. VDP-видеопроцессор). Участки с переходами к Z80, будут связаны со звуком. А IO_CT1_DATA - с опросом джойстиков.
Это главная 'фишка' IDA, засчет которой можно быстро разобраться в игре и переименовать не только системные адреса, но и любые другие. В дальнейшем мы будем часто пользоваться Jump to Xref to operand.
Я не рекомендую менять(да и не умеем ещё) участки кода с 'системными' адресами, т.к. ничего полезного вы в этом не найдете.
Мы их отделяли как раз для того, чтобы не 'задеть'.
В других участках (отвечающих за игровые 'фишки'), как правило нет этих запросов.
Так как же их найти? Конечно можно проверять всё подряд. Но мы еще не умеем правильно менять код. Да и конкретную вещь в данном случае найти непросто.
Есть два простых способа найти нужную вещь:
Дебаг (с установкой брейкпоинтов) на адрес (ROM или RAM).
Поиск адреса RAM (ID) конкретной вещи через поиск кодов.
Или оба сразу.
Если вы умеете искать читы (game genie), то для вас не составит проблему найти кучу адресов в RAM, отвечающих за что-либо.
Чем больше переменных мы найдем, тем лучше.
Какие это могут быть значения:
Номер (ID) персонажа.
Номер (ID) уровня, трассы,машины, мотоцикла.
Кол-во патронов.
Кол-во жизней, денег и т.д.
Таймер.
Координаты.
Всё что меняется и можно отследить.
Эмулятор который применяю для поиска я - Gens-mk2.
Подробное описание поиска 'читов' вы можете найти в интернете, таких описаний составлено очень много. Также вы можете попросить кого-то научить вас их искать (не меня).
Читы-это всего лишь значения в оперативной памяти, которые меняются. Само читерство заключается что мы можем залезть в память и заблокировать их (перезаписывая всё время своё значение) или просто один раз изменить.
Опишу простой способ поиска:
Выбираем первого персонажа, заходим cheats-search gg codes-reset.
в поле comparison type ставим больше > (greater than) и нажимаем OK.
Теперь выбираем второго персонажа , опять заходим в search gg codes и нажимаем reset.
Список адресов значительно уменьшится.
Теперь выбираем третьего , опять заходим и опять reset.
Еще меньше. Так делаем пока значений не останется по минимуму. это и будет искомый адрес. (адрес ID персонажа)
Почти всегда значение ID будет равен персонажу -1 , т.к. счет идет с 'нулевого' перса , а не первого.
Записываем эти значения (их может быть н-ко) , а также добавляем как чит.
add cheat - new value, в new value прописываем с любой из реальных ID и жмем ок.
Теперь включая чит, мы можем проверить какой-же именно адресс отвечал за порядковый номер персонажа.
Стоит попрбовать вписать другой 'несуществующий' ID, это позволит выбрать несуществующих или бажных персонажей (которые получаются 'случайно').
В случае если вы искали кол-во жизней или патронов то надо сравнивать на уменьшение char_id
Теперь если нажать правой кнопкой и выбрать Jump to Xref's, мы увидим переходы к участкам кода игры, связанные с данным параметром. Эти 'куски' кода и будут нас интересовать больше всего.
Если же ничего не нашлось (пусто по обоим адресам) - значит:
1) участок в котором запрашивается этот адрес не был дизасмнут.
2) этот адрес запрашивается относительно другого адреса. (относительная адресация)
3) вся игра использует относительный метод адресации к RAM.
(пример - Rock n' Roll Racing, все значения берутся от-но адреса FF8000,который записан в регистре A4 процессора)
4) 1+3 варианты сразу.
В этом случае на помощь приходит дебаг.
Эмулятор который мы будем использовать для дебага GENSVKNTrace.
Запускаем, открываем РОМ файл , потом переходим в опции Дебаг-Main 68k Debugger, откроется окно.
Находим брейкпоинты на ОЗУ. В первое или любое поле вписываем наш адрес FFxxxx. Ставим галочки 'чтение' или 'запись', или обе сразу и галочку 'установить брейкпоинт'. Нажимаем ОК.
Игра продолжается. теперь просто надо 'прокрутить' игру или поиграть до того момента , пока не срабатоет брейкпоинт (само откроется окно дебага с надписью 'сработал брейкопоинт на чтение (запись)!'
После того как окно откроется мы увидим код, по которому этот адрес запросился. (например чтение номера(ID) игрока), команда по которой он запросился находится в самой первой строчке. Запомним этот адрес и теперь перейдем к этому участку в базе IDA, и поставим там метку (rename_ read_char_id) или (write_char_id). Хоткей ренейма - 'N'.
Стоит отметить что таких участков может быть достаточно много. (т.е. нужно ждать другого брейкпоинта, при других игровых условиях, пробовать ставить на запись отдельно, на чтение отдельно и ждать.
Брейкпоинт для PC (program counter) - т.н. программный счетчик, необоходим для определения чтения исполняемого кода.
Несмотря на то, что в эмуляторе написано 'брейкпоинты на озу', можно спокойно использовать дебаг и на ROM (т.е. область кода и данных). Теперь если написать любой адрес ROM в поле дебага и поставить галочку 'PC', то если в этом находится программа, то сработает брекпоинт на PC (в случае если эта часть программы будет выполняться) - ну например код выполнения выстрела или спецприема. Если же поставить ROM-адресс на 'чтение' и сработает брейкпоинт значит в этом месте не код, а данные. На 'запись' для rom ставить не нужно, т.к. ни о какой запись в (read-only-memory) картидж не может идти и речи, это используется толко для RAM(ОЗУ), а 'pc', т.е код, практически не встречается в области RAM.
PC (program counter) - счетчик который определяет адресс текущего расположения выполняемой процессором команды. Очень часто применяется для относительной адресации. (от текущего места +$xxxx = итоговый адрес).
Примеры адресации:
move.w ($FFCECE).l,d0 - абсолютная полная (32битная запись, но сега 'держит' только 24)
move.w ($CECE).w,d0 или при этом два байта move.w ($FFFFCECE).w,d0 (но в hex 'FFFF' не будет) - абсолютный адрес но задается 2 байтами. трюк состоит в том что первые считаются $FFFF и мы попадаем тоже в RAM, но это соблюдается только для адресов >$8000, при меньших мы попадем в ROM. (это особенность 16-битной адресации)
move.w $4ECE(a4),d0 - адрес равняется $4ECE + число, в регистре a4 процессора. в данном случае a4=$FF8000+$4ECE=$FFCECE. В других случаях в a4 может быть что угодно, регистры могут быть от a0 до a6 и в них может быть записано что угодно, и может постоянно менятся в зависимости от программы. Что точно находиться в регистре в данный момент времени можно посмотреть в дебаггере.
Во всех трех случаях значение из памяти (RAM) читается и записывается в регистр d0 процессора.
Запись же выглядит 'наоборот': move.w d0,($FFCECE).l
Команда может быть не обязательно move, а другой (add, sub, и т.д.)
move.w unkn_00(pc,d1.w),d0 - чтение данных от текущего места + PC + d1. (IDA автоматически определяет расположение unkn_00 при условии что d1=0)
Подробнее о командах и регистрах будет рассмотрено позже.
Hot trick:
Используете GG-коды и GGConv.exe (game genie converter), чтобы найти уже найденные другими адреса в ROM и RAM, и допишите их в базу переименовав и поставив метки.
GG-коды можно найти в книге кодов codebook.exe, и на сайтах.
Запустим конвертер и выберем вкладку GEN (sega GENesis).
Вбиваем GG-code и получаем HEX-code.
Многие адреса уже представлены в виде HEX-code и их конвертировать не нужно.
HEX-code выглядит в формате adress:data.
пример FF1234:0005 (интересуемый адрес FF1234, значение вприцнипе нас не интересует), так если в описании чита указано что это жизни, следует переименовать, или начать с 5-ого (4-ого) уровня - значить это уровень, а значение его и определяет
его номер)
пример 00A6b0:6000 (интересуемый код находится в области ROM, суда следует перейти и тоже поставить метку.), также в этом случае число может являются только номером , но и кодом для процессора. (например, 6000, 4E75 или 4E71)
Модификация(хакинг) участков кода:
Теперь найдя интересующие участки кода мы будем их переделывать. Если с вышеописанными способами ничего не получилось, то мы их все равно будем переделывать, а что именно мы будем изменять узнаем по ходу дела. (сравнивая после и до изменения)
Перейдем к интересующему нас коду. (там где есть обращения к найденным переменным).
Весь код программы можно условно разделить на функции (процедуры), в IDA они разделяются строками ====SUBROUTINE====.
У любой такой подпрограммы есть начало и конец. в 95% случаях в конце находится команда .RTS (return from subroutine)- то есть возврат из этой подпрограммы к предыдущей.
HEX-код данной команды выглядит как 4E75. Запомните эту команду. в 97% случаях эта комбинация цифр и говорит, о том что тут находится имеенно код и конец подпрограммы.
Посмотрев ROM в 16-ричном виде в WinHexe, и вбив в поиск search-find hex values - 4e75, можно найти
огромное их кол-во. Следует отметить что адрес должен быть четным. То есть если 4e75 нашлась по адресу $251 (нечетн и т.д.), то это не Rts. Это полезно учитывать при нахождении кода в базе.
Теперь перейдем к началу подпрограммы (разделенной ====SUBROUTINE====), теперь надо заменить первую команду на RTS.
Что это даст? Мы полностью отключим данный участок. И таким образом сможем узнать за что, же эта часть кода отвечала.
Замена:
Просто пишем,использую в winhex, '4e75' по адресу который соотв. началу подпрограммы. (т.е. по адресу самой первой команды, то есть фактически мы ее заменим-т.е. уже asm-hacking)
Если ничего не изменилось или игра зависает, пробуйте тоже самое с другими участками.
Если получилось, и вы поняли что изменилось (напр. отключилась стрельба) переименовывайте (называйте) данную функцию.
Примеры названий и названных функций:
AI_weapon_nitro_using
car_model_gfx
weapon_moving
weapon_sprites
car1_life
car1_topspeed
xz_1
weap_table
Функции с code+data:
Если в функции есть следующие или похожие команды:
move.w unkn_1234(pc,d1.w),d0
lea unnk_5678,a1
И при переходе по адресам unnk_5678 в ROM, скорее всего содержится 'data'. Т.е. это могут быть игровые параметры такие как характерситики персонажа (скорость,сила и т.д.). Стоит попрбовать позаменять эти значения в РОМЕ через Winhex.
(заменять значения по этим адресам, как и случае data-хакинга, а не сами команды).
Особенно хорошо, если вы уже определили за что отвечает ваша функция).
Незабудьте что сама же функция должна быть при этом включена (т.е. никаких RTS вначале).
В данном примере команда загружает число с адреса 1234, от-но значения регистре d1 и записывает в d0.
В d1 например может быть ID (порядковый номер) персонажа, а по адресу хар-ка 'скорость'.
Функции только с code:
В этом случае стоит посмотреть на ту команду над которой происходит действия над нашим найденным и переименованным адресом.
Пример:
add.w #$14,($FFCECE).l
или
sub.w #1,($FFCECE).l
Адресс с назначенным именем (меткой):
add.w #$14,(LIFES).l
В данном случае это ADD (англ. прибавить), SUB (substract-вычесть). #1 - символ # говорит о том, чо это число. если # нет, значит это адрес. Результирующие действие проводится только над тем что,находится справа.
Т.е. в первом случае мы добавляем к значению в адресе $FFCECE число #$14.
Во-втором: вычитание из значения в адресе $FFCECE вычитаем 1. (значение в этом адресе памяти сразу же меняется, уменьшаясь на 1)
Например станет 13 жизней, а не 14.
Следующий код можно изменить следующим способом: вырезать (удалить) данную команду.
Для этого предусмотрена команда NOP (No Operate) - т.е. не проивозодить никаких действий. Данная команда записывается в HEx-виде как 4E71. Учитывая что команда nop занимает всего 2байта, а команда которую мы будет заменять может занимать значительно больше байт (для чего выделим ее в IDA и перейдем во-вторую вкладку), мы должны записать н-ко Nop'ов., чтобы не нарушить структуру программы.
Открываем ROM в Winhex, перейдем к адресу этой команды и впишем 4e71 4e71 4e71 4e71. (т.е. если ориентироваться по вкладке в IDA hex-view-A соотв. залить всю зеленую область nop'ами).
Таким способом можно вырезать любые команды и сравнивая результат до и после, и добиться каких-то 'эффектов', от положительных до зависания игры.
Также можно пробовать менять сами цифры в коде. Т.е. если в команде была операция с числом #$14, и выделив ее вы в hex-виде нашли 0014, можно попрбовать заменить на 0000 или 0028.
Можно ещё попрбовать поменять местами соседние команды.
Также если вы увидите команды beq или bne, пробуйте переделать их. (в hex начинаются на 67 и 66, т.е. нужно пробовать заменить 66 на 67, и наоборот- это превратит команду bne в beq).
Несмотря на простоту эти методы являются самыми эффективными, в случае если надо просто что-то 'хакнуть'.
Если же у вас есть конкретная цель, то без знания ассемблера или хотя бы н-ких команд не обойтись.
Вкратце рассмотрим что за ассемблер:
Несмотря на то, что у всех представление о ассемблере как о самом сложном языке, это не совсем так. Я бы даже сказал что ассемблер сеги самый простой.(достаточно знать десяток команд и можно написать что угодно). Другое дело что само написание дело долгое и трудоемкое. (т.к. все действия выполянются над числами и адресами).
Обзор регистров процессора:
Процессор MC68000 содержит 8 регистров данных (для чисел) - это регистры d0, d1, d2, d3, d4, d5, d6, d7 и 8 регистров для адресов - это регистры a0, a1, a2, a3, a4, a5, a6, a7
Регистры нужны для быстрых рассчетов, и бол-во операций выполняются между ними или между ними и памятью.
Также есть регистр SR (status registr), он меняется автоматически после каждого действия и отображает результат, который нужен для выполнения условий (напр.условие перехода).
Регистр a7 является железным 'stack pointer'ом и поэтому в коде его записывают как sp.
пример move.w d0,(sp)+. что это такое будет рассомтрено.
Основные команды ассемблера:
Буква после точки любой команды, означают что операция проводится с этим типом данных.
(.w - 2байта, .b 1 - байт, .l = 4 байта) , .s (short) также означает байт(но в случае переходов и прыжков).
Пример:
move.b d0,d1
move.w d0,d1
move.l d0,d1
bra.s loc_100
bra.w loc_100
move.b ($FFCABA).l
move.l ($FFFFCECE).w
move.w d0,d1
move.l d0,d1
bra.s loc_100
bra.w loc_100
move.b ($FFCABA).l
move.l ($FFFFCECE).w
А буква после адреса может быть только .w или .l (это говорит лишь о виде адресации полная или 16-битная) - это не влияет, на тип заносимых данных. (т.к. некоторые новички думают что если move.w адрес надо писать тоже ($1234).w - это не так)
В результате выполнения команд всегда меняется только значение справа (в примере d1).Это справедливо для процессоров Motorola.
Теперь рассмотрим сами команды.
Команды которые мы уже знаем:
RTS (return from subroutine) - возврат из подпрограммы
NOP (no operate) - не произв.действий.(процессор выполняет команду, но ничего не меняется)
ADD - сложение
SUB - (substract) вычитание
Другие команды (эти команды необходмо знать!):
MOVE - копирование
CMP - (compare) сравнение
TST - (test) - сравнение с нулем.
CLR - (clear) очистка - то есть запись нуля.
LEA - (load effective adress) - загрузка адреса в указанный адресный регистр.
JMP (или BRA) - прыжок. (jump, branch)
JSR (или BSR) - переход в подпрограмму с последующим возвратом (после rts). (jump to subroutine, branch to subroutine)
если к команде добавлено 'i' (cmpi.b) это лишь значит что операция выполняется над числом+регистр.
если стоит 'a' (movea.w) , это говорит лишь о том что выполняется над адресным регистром.
а 'q' (addq.b), говорит об упрощенном варианте команды, которая отличается тем, что выполняется процессором быстрее, но имеет некоторые ограничения.
Команды переходов (используется в связке сравнения CMP. или TST.), также очень важные команды:
beq (branch if equialent) - переход (прыжок), если равно.
bne (not equialent) - переход(прыжок), если не равно.
bge (greater или equialent) - если больше или равно.
ble (lower or equialent) - меньше или равно
bpl (plus) - результат положительный.(число полученное в результате имеет знак +, т.е. если байт то от 0 до 127 ($7F).
bmi (minus) - отрицательный.
Логические команды: (частые команды, но чтобы их понять их логику надо считать число по битам)
or ('ИЛИ') - логическое 'сложение' 0+1 = 1, 0+0 = 0 , 1+1=1
and ('И') - логическое 'умножение' 0x1= 0 , 0x0= 0 , 1x1 =1
eor (' исключающее ИЛИ') - 'сложение' , но в этом варинате 1+1=0 (также назыв. xor)
not ('НЕТ') - инвертирует все биты.
lsr (logical shift right) - сдвиг битов вправо
lsl (logical shift left) - влево
asr (arithmetical shift right) - вариант сдвига.
asl (arithmetical shift left)
Сдвиги чаще всего используются для умножения или деления.
Чтобы представить число в двочином виде, откройте калькулятор наберите число в hex или dec, а потом поставьте точку где bin.
Калькулятор (WINDOWS) должен быть установлен в вид->инженерный. Тут же можно и проверить их действие.
Поначалу можно обойтись и без понимая этих команд.
Все остальные команды более редкие, и для начала изучения не требует. Вообщем если попадаются просто смотрим в мануалах.
Выполнение команд:
Рассмотрим пример выполнения и важную особенность команд add,sub и других.
Пример: addi.b #$C0,d0 (добавить C0 к числу в регисте d0)
Пусть в нашем пример до этого регистр был равен d0=002a00B0.
Что должно получится? то есть к числу $B0 прибавить $C0 (т.к. тип данных - байт), если вы используете калькулятор,то получите $170, но это будет неверно. особенность в том,что если вы производили операцию над типом BYTE, другие байты не будут затронуты!, т.е. 002A00 останется как и есть. Чтобы посчитать правильно надо выставить в калькуляторе 1байт.
Получается что все числа как-бы замкнуты по кругу ($FF+2 = 1).
результат d0=002a0070. (этим объясняется например замкнутость координат, т.е. если вспомнить tmnt2 и баг с выходом за экран, когда проходили появлялись сверху или снизу наполовину, после максимума координата 255 попадали в 0 и наоборот )
Eсли же мы будем использовать команду addi.w или addi.l мы получим d0=002a0170.
Команда move.
Обратно же если в команде используется word или longword мы изменим 2 или 4 байта:
Пример move.l #4,d0
Результат: d0=00000004. (т.е. мы скопировали не 4, а 00000004)
Команда clr.
clr.b запишет 00 (т.е обнулит 1 байт)
clr.w запишет 0000 (обнулит 2 байта)
clr.l обнулит весь регистр.
Теперь если вы скачивали эмулятор Gens11(gensmovie) или GensKMOD, запустите этот эмулятор , откройте ром , найдите в пунктах Trace. Включим trace на пару секунд и выключим. Получится файл trace.log. Если вы ждали долго файл может получится огромным. Открываем блокнотом и смотрим. Перед вами результат выполнения программы, т.е. весь текущийвыполненный за эти 2секунды код, а справа то, чтобы находилось в регистрах.
За счет trace.log мы можем:
Отследить как работают команды.
Как от их выполнения меняются регистры.
Отследить последовательность выполнения программы.
Какие участки кода использовались в этот раз, и где они находятся. (что тоже полезно при дизасме в базе IDA).
Буквы xnzvc соотв. состоянию регистра состояния SR.
Операции с адресными регистрами:
movea.w d0,a0
move.w d0,(a0)
move.w d0,(a0)+
move.w d0,$1234(a0)
move.w d0,-(a0)
jmp (a0)
move.w d0,(a0)
move.w d0,(a0)+
move.w d0,$1234(a0)
move.w d0,-(a0)
jmp (a0)
случай 1) в этом случае меняется сам регистр a0.
случаи 2-5) 'скобки' - так как в регистре содержится адрес, например FF1000, поменяется содержимое памяти по этому адресу. то есть число из d0, запишется в FF1000. это и есть от-ная адресация. (относительно адреса в регистре a0).
случай 3) (a0)+ - в этом случае адрес в регистре a0 еще и автоматически увеличится (станет FF1002), то есть меняется и регистр и значение в памяти.
случай 4) запись в память по адресу FF1000+1234 = FF2234, сам a0 при этом остается = FF1000.
от-ная адресация для них работает как word. то есть максимум до $7FFF(a0), а минимум -$8000(a0). если укажете число $8500, то оно будет считаться как отрицательное. Однако если a4=FF8000 как в rock n' roll racing, мы получаем как раз доступ ко всей RAM, от-но этого одного регистра. Однако чаще встречаются 1(a0) или -2(a0), с небольшим смещением.
5) тоже что 3, только уменьшение адреса.
6) прыжок (переход программы) к адресу, который содержится в регистре a0.
ROM:000006C2 lea ($FF8000).l,a4
загрузка адреса $FF8000 в a4.
Stack pointer и Stack.
Как уже упоминалось a7 является stack pointer'ом и записывается как sp.
Он нужен, т.к. в нем записываются точки возврата , необходимые для команды JSR (ответ на вопрос откуда процессор знает, куда ему вернуться после команды rts).
stack - это как бы системная память (часть ram), stack pointer - адрес стека задается вначале, далее может сменен программой, в эту память автоматически и записываются адреса возрврата.
stack устроен по принципу стопки книг.(то есть вначале записывается одно, потом сверху другое, и разбирается вначале сверху потом вниз.), поэтому чаще всего стек находится в самом конце области RAM. ($FFFF00)
Кроме того в стек , можно записывать данные и самому, используя как временную память.
Чаще всего туда заталкивают регистры (содержимое регистров), если его надо 'сохранить'.
Очень часто подпрограмма как раз и начинается с сейва регистра одного или н-ких. Это объясняется тем что нужно сохранить их значения для предыдущей более главной программы. А заканчивается как раз взятием их 'обратно ', прямо перед rts.
Пример:
ROM:00000A10 sub_0_A10: ; CODE XREF: sub_0_A22:loc_0_A28p
ROM:00000A10 ; sub_0_A22:loc_0_A4Cp ...
ROM:00000A10 movem.l d0-a6,-(sp)
ROM:00000A14 bsr.w sub_0_10C8
ROM:00000A18 bsr.w sub_0_10B8
ROM:00000A1C movem.l (sp)+,d0-a6
ROM:00000A20 rts
ROM:00000A10 ; sub_0_A22:loc_0_A4Cp ...
ROM:00000A10 movem.l d0-a6,-(sp)
ROM:00000A14 bsr.w sub_0_10C8
ROM:00000A18 bsr.w sub_0_10B8
ROM:00000A1C movem.l (sp)+,d0-a6
ROM:00000A20 rts
cейв всех регистров от d0 до a6 (сохраняют в стек), bsr.w - переходы к другим подрограммам.
movem означает (move multiply)- множественное копирование, дополнительный вариант команды move.
ROM:0000154E global VBLANK
ROM:0000154E VBLANK:
ROM:0000154E movem.l d0-d2/d7-a1,-(sp)
ROM:00001552 addq.w #1,$425E(a4)
ROM:00001556 tst.w $38D8(a4)
ROM:0000155A beq.s loc_0_1570
ROM:0000155C move.w $4256(a4),d0
ROM:00001560 add.w d0,d0
ROM:00001562 lea off_0_1576,a0
ROM:00001566 movea.l (a0,d0.w),a0
ROM:0000156A jsr (a0)
ROM:0000156C bsr.w sub_0_6F8
ROM:00001570
ROM:00001570 loc_0_1570: ; CODE XREF: VBLANK+Cj
ROM:00001570 movem.l (sp)+,d0-d2/d7-a1
ROM:00001574 rte
ROM:0000154E VBLANK:
ROM:0000154E movem.l d0-d2/d7-a1,-(sp)
ROM:00001552 addq.w #1,$425E(a4)
ROM:00001556 tst.w $38D8(a4)
ROM:0000155A beq.s loc_0_1570
ROM:0000155C move.w $4256(a4),d0
ROM:00001560 add.w d0,d0
ROM:00001562 lea off_0_1576,a0
ROM:00001566 movea.l (a0,d0.w),a0
ROM:0000156A jsr (a0)
ROM:0000156C bsr.w sub_0_6F8
ROM:00001570
ROM:00001570 loc_0_1570: ; CODE XREF: VBLANK+Cj
ROM:00001570 movem.l (sp)+,d0-d2/d7-a1
ROM:00001574 rte
сохраняет регистры от d0 до d2, d7 до a1 (т,е. еще и a0).
Обращаю внимание в этом участке , не rts , а rte (т.н. возврат из исключения). VBLANK -кадровое прерывание, которое происходит само 50 или 60 раз в секунду. (PAL или NTSC сега). Поэтому к нему нет переходов. Текущая выполняем процессором программа в любой момент может остановиться и начнет выполенения кода отсуда, к нему нет переходв (это происходит на уровне железа), однако адрес VBLANK задается в заголовке картриджа. (IDA определяет автоматически).
Этот код связан в основном с выводом графики для следующего кадра, поэтому трогать его не советую.
rte вернет вас назад к вашей программе.
Кроме сохранения регистров, стек может быть использован и в других целях. Зависит от конретной игры, в некоторых доходит до того что его используют по 4 строчки подряд. (что не совсем удобно для хакинга).
Также важно если будете менять код, сохраняйте принцип стакинга, (т.е. на затрите с команды sp+ или -sp), иначе нарушится последовательность, программа вернется не в то место и в 90% случаях будет зависание или баги.
* Если вы отключаете функцию (то есть через 4e75 вначале, а там находился сейв в sp), то это как раз нормально, так как мы сразу возвращаемся, а если вписать как раз после сейва, то зависнет (т.к. не 'заберем' из стека обратно).
Ну вот и весь ассемблер.
На вопрос, а что же мне с ними делать? Куда сувать команды и регистры? Ответ - изучите как работает чужая программа (участок кода), от и до (пусть он будет хоть 10строчек), тогда вы сможете понять как его можно изменить с желаемым результатом или написать по-своему.
Для написания вашего собственного участка кода я рекомендую ассембелер ASM68K.exe, который надо запускать с ключом /p.
работает из командой строки (консоли виндовс).
asm68k /p test.asm, test.bin
где test.asm - текстовый файл с вашим кодом, test.bin - готовый hex-код. test.bin надо открыть в WINHEX'e и полученный hex-cod вставить на место старого. если он не влез - используйте команду JSR и найдите пустое место в Rome.
Команда JSR выглядит как 4EB9 00 xx xx xx, где xxxxxx - абсолютный адрес в РОМе.
Пример: 4E B9 00 00 B8 2E - прыжок к подрограмме по адресу B82E.
Эту команду надо Запомнить также как RTS(4e75) и NOP(4e71), то есть если раньше вы вписывали вручную 4e75- теперь вписывайте 4eb9 00 0F A0 00 (где FA000 - адрес найднного вами пустого места, куда вы скоптируете свой код).
* В WINHEX копирование - CTRL+B (то есть запись поверх старого) , не путайте с CTRL+V - это сдвинет весь ром разрушив структуру.
Не советую использовать sega-asm, т.к. в нем есть определенные баги с некоторыми командами и баг c "org".
Что же касается SNASM68K.exe, можете попробовать и его (в нем на мой взгляд тоже есть неясность с полурабочим 'org', к тому же он у меня закидывал свои 'копирайты' в бинарник, что может мешать при копировании кода)
Что делать если вы не нашли пустого места в РОМЕ? SEGA позволяет безболезенно 'расширять' РОМ-файл до 4 мегабайт.
Модифицированные эмуляторы позволят запускать и до 13 мегабайт ром. (но такой ром не будет работать на железной сеге), также не приветствуется многими пользвателями.
Расширение рома:
Для увелечиния размера рома, достаточно приклеить к нему пустое место (нули) к концу файла.
Идем к winhex последнему байту в РОМЕ, выделяем его , заходим Edit->Paste Zero bytes. Появится надпись append to end of file? жмем YES. Добавляем 1 048 576 байт (1 мегабайт). Если ром был 1 мегабайт станет 2 мегабайта.
Теперь проверим запускается ли игра. Если игра перестала запускаться, и игра была с проверкой контрольной суммы (вы выставляли fix checksum), используйте программу FIXCHECKSUM.exe, она автоматически исправляет и сумму и размер рома, которые записываются в начале ром-файла. Эмуляторы умеют исправлять только сумму (но не размер).
Code+Data hacking. Часть2.
Ключевым аспектом является использование(чтение) данных кодом и с последующей их обработкой и/или записью в память.
Впринципе все что не является кодом, является данными. Отдельно можно расположить лищь оффсеты(ссылки на адреса).
Обычно все данные расположены в РОМЕ таблицами, т.н. 'массивы' данных.
Т.е. графика, хар-ки персонажей, пос-ти нажатий кнопок, игровые цены, палитры, конфиги уровней, текст и прочее.
Пример чтения данных:
ROM:00007300 move.b unk_0_732E(pc,d0.w),d1
ROM:00007304 add.b d1,(a1,a0.w)
ROM:00007308 lea $51A8(a4),a1
ROM:0000730C move.b unk_0_7335(pc,d0.w),d1
ROM:00007310 add.b d1,(a1,a0.w)
ROM:00007314 lea $51AC(a4),a1
ROM:00007318 move.b unk_0_733C(pc,d0.w),d1
ROM:0000731C add.b d1,(a1,a0.w)
ROM:00007320 lea $519A(a4),a1
ROM:00007324 move.b unk_0_7343(pc,d0.w),d1
ROM:00007328 add.b d1,(a1,a0.w)
ROM:0000732C rts
ROM:0000732C; ---------------------------------------------------------------------------
ROM:0000732E unk_0_732E: dc.b 1
ROM:0000732F dc.b 0
ROM:00007330 dc.b 1
ROM:00007331 dc.b 0
ROM:00007332 dc.b 0
ROM:00007333 dc.b 1
ROM:00007334 dc.b 1
ROM:00007335 unk_0_7335: dc.b $10
ROM:00007336 dc.b $10
ROM:00007337 dc.b 0
ROM:00007338 dc.b 0
ROM:00007304 add.b d1,(a1,a0.w)
ROM:00007308 lea $51A8(a4),a1
ROM:0000730C move.b unk_0_7335(pc,d0.w),d1
ROM:00007310 add.b d1,(a1,a0.w)
ROM:00007314 lea $51AC(a4),a1
ROM:00007318 move.b unk_0_733C(pc,d0.w),d1
ROM:0000731C add.b d1,(a1,a0.w)
ROM:00007320 lea $519A(a4),a1
ROM:00007324 move.b unk_0_7343(pc,d0.w),d1
ROM:00007328 add.b d1,(a1,a0.w)
ROM:0000732C rts
ROM:0000732C; ---------------------------------------------------------------------------
ROM:0000732E unk_0_732E: dc.b 1
ROM:0000732F dc.b 0
ROM:00007330 dc.b 1
ROM:00007331 dc.b 0
ROM:00007332 dc.b 0
ROM:00007333 dc.b 1
ROM:00007334 dc.b 1
ROM:00007335 unk_0_7335: dc.b $10
ROM:00007336 dc.b $10
ROM:00007337 dc.b 0
ROM:00007338 dc.b 0
Если вы уже занимались data-hacking'ом (где мы 'заливали' эти данные, т.е. массивы данными нулями для проверки), вы бы уже скорее всего знали что они отвечают.
В примере move.b считывает (копирует) значение с адреса 732E (адрес в программе от-ный, но IDA считает его автоматически - т.к. относительно pc (текущего положения)). Также дополнительно считывает и от-но значения в регистре d0.
Что это значит?
Если в регистре d0 значение = 00000000, то в d1 запишется значение с адреса 732E, то есть 1.
Если в регистре d0 = 00000001, то в d1 запишется значение с адреса 732E+1, т.е. с 732F, то есть 0.
Для объяснения открою секрет - по адресу $732E, находится таблица хар-ки + скорость, а в d0 порядковый номер (ID) персонажа.
Что же происходит? Если у нас персонаж номер 1 (то есть с id=0, т.к. счет идет с нуля), то прочитается 1, если второй то 0, если третий то 1., т.е. таблица хар-ки + скорость.
То есть целиком куска 'персонажа' не существует. А все его параметры определяются от-но ID (порядкового номера), т.е. такие как таблицы спецприемов и т.д.
По адресу $7335 расположена таблица хар-ки +ускорение. Как видно они в примере они состоят из 7 значений (т.к. всего семь персонажей). Если же ID персонажа = будет 8-ой (id=07), то для первого случая (+скорость) прочитается значение с адреса $7335 (732E+7), т.е. не из рассчитаного места.
(если вы играли в RRR за 'невидимку', теперь вам ясно откуда у него такая завышенная скорость).
То есть если вы хотите добавлять персонажей, то нужно смещать адреса и расширять эти таблицы. Если адрес абсолютный то это сделать несложно, если же от-ный намного сложнее, т.к. придется либо перемещать весь участок в новое место, либо делать какие-то вставки через JSR. Но это пока не рассматривается, т.к. сложность заключается в том, что если вы хотите что-то добавить, то нужно найти и расширить ВСЕ эти 'таблицы', коих может быть от 10 до 100. (и даже после этого никакой персонаж не появится, т.к. нужно указать что персонажей не 7, а 8.) Засчет паролей в RRR получается что задается
не рассчитаный 8-ой персонаж, и результат его обработки. (читаются другие данные), вместо графики все черное и т.д.
Однако может встретить и 'классический' вариант - когда область 'data' отвечает за многие хар-ки одного персонажа.
(пример dune 2), для каждого здания и юнита есть 'data' конфиг. Но при этом все конфиги аналогичны. (т.е. в конфиге не прописывает dmg=100, скорость=20., там есть только числа 100 и 20., а то что за что оно отвечает определяется, в зависимости от его расположения (т.е. например во всех конфигах юнитов первое число будет отвечать за скорость, второе за цену и т.д.)
Программа не читает все сразу (она читает нужное число,) т.е., в программе при чтении цены будет указано смещение +1, от-но начала конфига. (если первое значение типа байт, если же word то +2)
Команда lea.
Самой частой командой загрузки data, является команда lea (load effective adress). Т.е. фактически команда только загружает адрес расположения 'data' в адресный регистр , а в дальнейшем читать уже будет команда move или add.
Пример чтения (ukn_000 переименованы, в найденные опытным путем параметры):
Таблица физ. хар-к для пяти машин:
Код:
ROM:0000DF0C lea car_topspeed,a1
ROM:0000DF10 lea $51A4(a4),a2
ROM:0000DF14 move.b (a1,d1.w),(a2,a0.w)
ROM:0000DF1A lea car_accelerat,a1
ROM:0000DF1E lea $51A8(a4),a2
ROM:0000DF22 move.b (a1,d1.w),(a2,a0.w)
ROM:0000DF10 lea $51A4(a4),a2
ROM:0000DF14 move.b (a1,d1.w),(a2,a0.w)
ROM:0000DF1A lea car_accelerat,a1
ROM:0000DF1E lea $51A8(a4),a2
ROM:0000DF22 move.b (a1,d1.w),(a2,a0.w)
Данные:
ROM:0000E150 car_topspeed: dc.b $28 ; DATA XREF: CARS_STATS+Co
ROM:0000E151 dc.b $2A
ROM:0000E152 dc.b $24
ROM:0000E153 dc.b $24
ROM:0000E154 dc.b $26
ROM:0000E155 car_accelerat: dc.b $C0 ; DATA XREF: CARS_STATS+1Ao
ROM:0000E156 dc.b $D0
ROM:0000E157 dc.b $A0
ROM:0000E158 dc.b $A0
ROM:0000E159 dc.b $B0
ROM:0000E151 dc.b $2A
ROM:0000E152 dc.b $24
ROM:0000E153 dc.b $24
ROM:0000E154 dc.b $26
ROM:0000E155 car_accelerat: dc.b $C0 ; DATA XREF: CARS_STATS+1Ao
ROM:0000E156 dc.b $D0
ROM:0000E157 dc.b $A0
ROM:0000E158 dc.b $A0
ROM:0000E159 dc.b $B0
Как видно в этом примере код и данные располжены далековато друг от друга, но чаще всего они бывают рядом.
Для нахождения кода (одного или н-ких участков) , который читает 'data' , надо выделять метку правой кнопкой, т.е. в пример car_topspeed: и выбирать Jump To Xref to Operand, покажет список всех участков кода и также позволит туда перейти. Как уже упоминалось это главная особенность IDAPro.
В этом примере адресация тоже относительная, хоть это и не написано мы можем посмотреть, выделив команду lea и перейдя во вторую вкладку мы увидим 43FA 0242, где 0242 -от-ный адрес (от-но pc-program counter) , который нужно счиать по формуле DF0C(текущий)+242(указанный от-ный в hex)+2(длина команды) (Ida считает автоматически).
Примеры 43FA xxxx, 41FA xxxx, 45FA xxx, 47FA xxxx. - от-ные.
Абсолютные: в данном варианте полный адрес в виде longword.
ROM:000051FA lea (cars_costs_pla).l,a0
в HEx выглядит так: 41F9 00 00 55 20, загрузка адреса $00005520, по которому располагаются данные. Такие адреса гораздо проще менять. (т.к ненадо считать и мы можем указать любое новое место, без изменения в коде).
41F9 xx xx xx xx
43F9 xx xx xx xx и т.д.
Как уже упоминалось все данные являются либо byte, либо word, либо longword.
данные типа byte = dc.b
2 байта word = dc.w
longword = dc.l
Тип н-кых данных IDA определяет автоматически. Остальные вы должны определить сами. Менять типы данных можно нажимая хот-кей 'D'. Какой именно тип узнать можно по команде которая пойдет после lea, (т.е. команде чтения данных), если это будет move.w значит надо данные перевести в dc.w.
Пример переназченного типа:
ROM:00005520 cars_costs_pla: dc.l $70000 ; DATA XREF: sub_0_507E+76o
ROM:00005520 ; sub_0_51CE:cars_costso
ROM:00005524 dc.l $70000
ROM:00005528 dc.l $110000
ROM:0000552C dc.l $110000
ROM:00005530 dc.l $130000
ROM:00005520 ; sub_0_51CE:cars_costso
ROM:00005524 dc.l $70000
ROM:00005528 dc.l $110000
ROM:0000552C dc.l $110000
ROM:00005530 dc.l $130000
Offsets.
Кроме кода и данных в роме также есть и оффсеты, это так называемые 'ссылки' на адреса. А уже по этим ссылкам могут располагаться как данные, так и код , и даже другие ссылки.
Ссылки почти всегда расположены массивами, (т.е. как таблицы статов).
Пример массива ссылок на подпрограммы:
ROM:00001576 off_0_1576: dc.l locret_0_15BE ; DATA XREF: VBLANK+14o
ROM:0000157A dc.l loc_0_B66C
ROM:0000157E dc.l unk_0_829C
ROM:00001582 dc.l unk_0_535A
ROM:00001586 dc.l sub_0_93C6
ROM:0000158A dc.l sub_0_3146
ROM:0000158E dc.l sub_0_8888
ROM:00001592 dc.l sub_0_13B60
ROM:00001596 dc.l sub_0_13B88
ROM:0000159A dc.l sub_0_9C44
ROM:0000159E dc.l sub_0_1A42
ROM:000015A2 dc.l sub_0_7996
ROM:000015A6 dc.l sub_0_7210
ROM:000015AA dc.l sub_0_B666
ROM:000015AE dc.l sub_0_B672
ROM:000015B2 dc.l sub_0_B68A
ROM:000015B6 dc.l sub_0_B6FA
ROM:000015BA dc.l sub_0_15600
ROM:0000157A dc.l loc_0_B66C
ROM:0000157E dc.l unk_0_829C
ROM:00001582 dc.l unk_0_535A
ROM:00001586 dc.l sub_0_93C6
ROM:0000158A dc.l sub_0_3146
ROM:0000158E dc.l sub_0_8888
ROM:00001592 dc.l sub_0_13B60
ROM:00001596 dc.l sub_0_13B88
ROM:0000159A dc.l sub_0_9C44
ROM:0000159E dc.l sub_0_1A42
ROM:000015A2 dc.l sub_0_7996
ROM:000015A6 dc.l sub_0_7210
ROM:000015AA dc.l sub_0_B666
ROM:000015AE dc.l sub_0_B672
ROM:000015B2 dc.l sub_0_B68A
ROM:000015B6 dc.l sub_0_B6FA
ROM:000015BA dc.l sub_0_15600
Оффсеты определяются не хоткеем 'D', а хоткеем 'O'.
До нажатия 'O', это место выглядело так:
ROM:00001576 unk_0_1576: dc.b 0 ; DATA XREF: VBLANK+14o
ROM:00001577 dc.b 0
ROM:00001578 dc.b $15
ROM:00001579 dc.b $BE; -
ROM:0000157A dc.b 0
ROM:0000157B dc.b 0
ROM:0000157C dc.b $B6; ¦
ROM:0000157D dc.b $6C; l
ROM:0000157E dc.b 0
ROM:0000157F dc.b 0
ROM:00001580 dc.b $82; ?
ROM:00001581 dc.b $9C; ?
ROM:00001582 dc.b 0
ROM:00001583 dc.b 0
ROM:00001584 dc.b $53; S
ROM:00001585 dc.b $5A; Z
ROM:00001586 dc.b 0
ROM:00001587 dc.b 0
ROM:00001577 dc.b 0
ROM:00001578 dc.b $15
ROM:00001579 dc.b $BE; -
ROM:0000157A dc.b 0
ROM:0000157B dc.b 0
ROM:0000157C dc.b $B6; ¦
ROM:0000157D dc.b $6C; l
ROM:0000157E dc.b 0
ROM:0000157F dc.b 0
ROM:00001580 dc.b $82; ?
ROM:00001581 dc.b $9C; ?
ROM:00001582 dc.b 0
ROM:00001583 dc.b 0
ROM:00001584 dc.b $53; S
ROM:00001585 dc.b $5A; Z
ROM:00001586 dc.b 0
ROM:00001587 dc.b 0
Т.е. если можно легко определить на 'глаз'.
Массив оффсетов на участки 'data'.
ROM:00002124 off_0_2124: dc.l unk_0_2148 ; DATA XREF: sub_0_2064+20o
ROM:00002128 dc.l unk_0_2182
ROM:0000212C dc.l unk_0_2194
ROM:00002130 dc.l unk_0_21A2
ROM:00002134 dc.l unk_0_21B0
ROM:00002138 dc.l unk_0_2156
ROM:0000213C dc.l unk_0_2160
ROM:00002140 dc.l unk_0_216A
ROM:00002144 dc.l unk_0_2176
ROM:00002148 unk_0_2148: dc.b $B ; DATA XREF: ROM:off_0_2124o
ROM:00002149 dc.b $F
ROM:0000214A dc.b 8
ROM:0000214B dc.b 1
ROM:0000214C dc.b 4
ROM:00002128 dc.l unk_0_2182
ROM:0000212C dc.l unk_0_2194
ROM:00002130 dc.l unk_0_21A2
ROM:00002134 dc.l unk_0_21B0
ROM:00002138 dc.l unk_0_2156
ROM:0000213C dc.l unk_0_2160
ROM:00002140 dc.l unk_0_216A
ROM:00002144 dc.l unk_0_2176
ROM:00002148 unk_0_2148: dc.b $B ; DATA XREF: ROM:off_0_2124o
ROM:00002149 dc.b $F
ROM:0000214A dc.b 8
ROM:0000214B dc.b 1
ROM:0000214C dc.b 4
Как видно все оффсеты имеют тип longword. Однако в некоторых играх есть и двух-байтовые оффсеты, это не очень удобно, т.к. такие базы очень плохо сама дизасмит IDA (нужно определять самому), да и сами оффсеты от-ные. (эти оффсеты нельзя определить хоткеем 'O', только 'd')
Пример golden-axe 3:
ROM:00003E18 lea (word_0_3E26).l,a4
ROM:00003E1E move.b $6D(a0),d0
ROM:00003E22 bra.w sub_0_41CC
ROM:00003E22; End of function sub_0_3DF8
ROM:00003E22
ROM:00003E22; ---------------------------------------------------------------------------
ROM:00003E26 word_0_3E26: dc.w $E ; DATA XREF: sub_0_3DF8+20o
ROM:00003E28 dc.w $12
ROM:00003E2A dc.w $22
ROM:00003E2C dc.w $22
ROM:00003E2E dc.w $3A
ROM:00003E30 dc.w $6C
ROM:00003E32 dc.w $6A
ROM:000041CC sub_0_41CC: ; CODE XREF: sub_0_12AA+2Aj
ROM:000041CC ; ROM:0000136Ej ...
ROM:000041CC ext.w d0
ROM:000041CE add.w d0,d0
ROM:000041D0 adda.w (a4,d0.w),a4
ROM:000041D4 jmp (a4)
ROM:00003E1E move.b $6D(a0),d0
ROM:00003E22 bra.w sub_0_41CC
ROM:00003E22; End of function sub_0_3DF8
ROM:00003E22
ROM:00003E22; ---------------------------------------------------------------------------
ROM:00003E26 word_0_3E26: dc.w $E ; DATA XREF: sub_0_3DF8+20o
ROM:00003E28 dc.w $12
ROM:00003E2A dc.w $22
ROM:00003E2C dc.w $22
ROM:00003E2E dc.w $3A
ROM:00003E30 dc.w $6C
ROM:00003E32 dc.w $6A
ROM:000041CC sub_0_41CC: ; CODE XREF: sub_0_12AA+2Aj
ROM:000041CC ; ROM:0000136Ej ...
ROM:000041CC ext.w d0
ROM:000041CE add.w d0,d0
ROM:000041D0 adda.w (a4,d0.w),a4
ROM:000041D4 jmp (a4)
Массив от-ных оффсетов на код с последующим JMP по этим ссылкам.
Как считать: обычно считаем от первого + значение: т.е. 3E26+E = 4134
3E26+12 = 3e38
3e26+22 = 3e48
По этим адресам расположились подпрограммы. (причем фактически они расположены в другом месте, тут расположен только код прыжка к ним (bra, jmp)-прыжки
ROM:00003E34; ---------------------------------------------------------------------------
ROM:00003E34 bra.w loc_0_3EDA
ROM:00003E38; ---------------------------------------------------------------------------
ROM:00003E38 move.b #2,$6D(a0)
ROM:00003E3E moveq #$E,d0
ROM:00003E40 clr.b $135(a0)
ROM:00003E44 bra.w loc_0_3EF6
ROM:00003E48; ---------------------------------------------------------------------------
ROM:00003E48 bra.w loc_0_3EDA
ROM:00003E34 bra.w loc_0_3EDA
ROM:00003E38; ---------------------------------------------------------------------------
ROM:00003E38 move.b #2,$6D(a0)
ROM:00003E3E moveq #$E,d0
ROM:00003E40 clr.b $135(a0)
ROM:00003E44 bra.w loc_0_3EF6
ROM:00003E48; ---------------------------------------------------------------------------
ROM:00003E48 bra.w loc_0_3EDA
Данная организация хоть и неудобна (для дизасма), но достаточно часто встречается, поэтому надо ее понять.
Отмечу, если вы читали какие-то доки где упоминается понятие поинтер, то под поинтерами понимают команды lea и оффсеты.
Некоторые ромхакеры считают поинтерами только оффсеты. Н-кые вообще понимают под ними любые адреса.
LEA и offsets могут быть как на ROM, так и на RAM.
Продолжаем работу с базой.
Правильным подходом в работе с базой IDA , перед её полным дизасмом и заполнением, является отделение стандартных данных, которые присутсвуют во всех играх. (таким образом нам не нужно будет проверять весь ром на код,данные или оффсеты).
К таким данным относятся: код процессора Z80, звуки и графика.
Процессор Z80 и его код.
Я уже упоминал что в сеге содержится второй процессор - ZILOG Z80. Процессор 8-битный и в 2 раза меньше по частоте, но это удачное решение, т.к. его использовали для проигрывания звуков и музыки.
Мы не будем его изучать, т.к. звуки можно менять и без этого, а изменение музыки достаточно сложная вещь, (т.к. музыка 'трекерная', вроде midi).
Но мы должны отделить его код.
Чтобы найти его мы должны перейти в IDA вначале к адресу A00000. Если вы уже сделали переименование системных адресов как описано в статье это место будет выглядеть так:
Z80_RAM:00A00000; Segment type: Pure data
Z80_RAM:00A00000; segment "Z80_RAM"
Z80_RAM:00A00000 Z80_RAM_: ds.b 1 ; DATA XREF: sub_0_12AAC
Делаем Jump to Xref to Operand:
Единственный переход и попадаем в сегмент:
ROM:00012AAC sub_0_12AAC: ; CODE XREF: sub_0_12980p
ROM:00012AAC move.w #$100,(word_0_A11200).l
ROM:00012AB4 bsr.w sub_0_12D36
ROM:00012AB8 lea (unk_0_19000).l,a0
ROM:00012ABE lea (Z80_RAM_).l,a1
ROM:00012AC4 move.w #$1FFF,d7
ROM:00012AC8
ROM:00012AC8 loc_0_12AC8: ; CODE XREF: sub_0_12AAC+1Ej
ROM:00012AC8 move.b (a0)+,(a1)+
ROM:00012ACA dbf d7,loc_0_12AC8
ROM:00012AAC move.w #$100,(word_0_A11200).l
ROM:00012AB4 bsr.w sub_0_12D36
ROM:00012AB8 lea (unk_0_19000).l,a0
ROM:00012ABE lea (Z80_RAM_).l,a1
ROM:00012AC4 move.w #$1FFF,d7
ROM:00012AC8
ROM:00012AC8 loc_0_12AC8: ; CODE XREF: sub_0_12AAC+1Ej
ROM:00012AC8 move.b (a0)+,(a1)+
ROM:00012ACA dbf d7,loc_0_12AC8
(unk_0_19000) в этом случае адрес ROM, где находится код Z80. Подпрограмма выполняет копирование кода для процессора Z80 из картиджа (ROM) в RAM Z80, который имеет свою собственную память(отдельную микросхему), но она всего 8кб, против 65к основной.
Процессор MC68000 имеет сводобный доступ к этой микросхеме (т.е. к памяти z80), если вы смотрели карту памяти, адресное пространство выглядит для него A00000-A1FFFF. Копирование проводят так как z80 не читает программу с картриджа, а из собственной памяти (имеет ограниченный доступ к картриджу). Это соблюдается почти во всех ромах (если не во всех.)
В дальнейшем в эту память процессором mc68000 просто так 'лазить' нельзя, так как предварительно необоходимо делать 'захват шин'. (но в ходе программ это используется часто, т.к. если бы этого не было музыка и звуки играли независимо от игры, а приходится каждый раз указаывать z80, что ему играть.)
адреса вроде
ROM:00000C00 move.w #$100,(word_0_A11100).l
ROM:00000C08 move.w #$100,(word_0_A11200).l
и говорят об этом 'захвате' , а также говорит , о том что данный код связан со звуком.
ROM:00000C00 move.w #$100,(IO_Z80BUS_).l
ROM:00000C08 move.w #$100,(IO_Z80RES_).l
ROM:00000C08 move.w #$100,(word_0_A11200).l
и говорят об этом 'захвате' , а также говорит , о том что данный код связан со звуком.
ROM:00000C00 move.w #$100,(IO_Z80BUS_).l
ROM:00000C08 move.w #$100,(IO_Z80RES_).l
Переходим к 19000:
ROM:00019000 Z80_code: dc.b $F3; ? ; DATA XREF: sub_0_12AAC+Co
ROM:00019001 dc.b $31; 1
ROM:00019002 dc.b $F0; ?
ROM:00019003 dc.b $13
ROM:00019004 dc.b $ED; ?
ROM:00019001 dc.b $31; 1
ROM:00019002 dc.b $F0; ?
ROM:00019003 dc.b $13
ROM:00019004 dc.b $ED; ?
В базе его нельзя дизасмнуть, т.к. это другой процессор и его команды другие. (можно открыть файл заного, и указать тип процессора Z80), но можно ли в одной базе дизассемблить 2 процессора я не знаю, скорее всего нельзя.
Код z80 представляет собой лишь один кусок, (т.е. в роме его больше нигде нет), теперь надо на глаз определить размер этого куска , выделить и сделать 'hide':
примерно тут конец:
ROM:0001A1E9 dc.b 1
ROM:0001A1EA dc.b 5
ROM:0001A1EB dc.b 0
ROM:0001A1EC dc.b 0
ROM:0001A1ED dc.b 0
ROM:0001A1EE dc.b 0
ROM:0001A1EF dc.b 0
ROM:0001A1F0 dc.b 0
ROM:0001A1F1 dc.b 0
ROM:0001A1F2 dc.b 0
ROM:0001A1F3 dc.b 0
ROM:0001A1EA dc.b 5
ROM:0001A1EB dc.b 0
ROM:0001A1EC dc.b 0
ROM:0001A1ED dc.b 0
ROM:0001A1EE dc.b 0
ROM:0001A1EF dc.b 0
ROM:0001A1F0 dc.b 0
ROM:0001A1F1 dc.b 0
ROM:0001A1F2 dc.b 0
ROM:0001A1F3 dc.b 0
(пошли нули).
выделяем область и заходим в view - hide. OK.
Результат:
ROM:00018FFC dc.b 0
ROM:00018FFD dc.b 0
ROM:00018FFE dc.b 0
ROM:00018FFF dc.b 0
ROM:00019000; Z80_code
ROM:0001A1EC dc.b 0
ROM:0001A1ED dc.b 0
ROM:0001A1EE dc.b 0
ROM:0001A1EF dc.b 0
ROM:0001A1F0 dc.b 0
ROM:0001A1F1 dc.b 0
ROM:00018FFD dc.b 0
ROM:00018FFE dc.b 0
ROM:00018FFF dc.b 0
ROM:00019000; Z80_code
ROM:0001A1EC dc.b 0
ROM:0001A1ED dc.b 0
ROM:0001A1EE dc.b 0
ROM:0001A1EF dc.b 0
ROM:0001A1F0 dc.b 0
ROM:0001A1F1 dc.b 0
Т.е. нам не пришлось ломать этот участок. (пытаясь понять, что же там).
Звук.
Теперь стоит выделить звуки. К тем звукам что можно открыть через редактор относится лишь оцифрованная речь,
пример озвучка larry в RRR, озвучка действия юнитов в Dune. Остальные звуки и музыку можно взломать лишь зная программирование.
Если ром содержит такую речь, открываем ром-файл в редакторе goldwave.
Следует использовать следующие настройки:
File type: Raw (snd,raw)
Attributes: PCM, unsigned 8bit,mono
Rate(HZ) : от 8000 до 16000.
Attributes: PCM, unsigned 8bit,mono
Rate(HZ) : от 8000 до 16000.
Требуемый рейт можно определить на слух, т.к. он определяет скорость проигрывания. Т.е. нужно подобрать, если проигрывается слишком медленно или слишком быстро.
Теперь прослушаем РОМ, наличие звука можно увидеть также на графике, в виде характерной синусоиды. Остальные области просто 'залиты зеленым', скрипы и писки говорят о том что мы просто слушаем код, данные, графику (т.е. читаем их как будто бы они бы звук).
Теперь найдем и выделим эту же область и сделаем в базе IDA 'hide' аналогично как с случае с Z80. Типичное представление звука в 16-ричном виде:
ROM:000236D4 dc.b $80; ?
ROM:000236D5 dc.b $80; ?
ROM:000236D6 dc.b $80; ?
ROM:000236D7 dc.b $80; ?
ROM:000236D8 dc.b $80; ?
ROM:000236D9 dc.b $80; ?
ROM:000236DA dc.b $80; ?
ROM:000236DB dc.b $80; ?
ROM:000236DC dc.b $80; ?
ROM:000236DD dc.b $7F;
ROM:000236DE dc.b $81; ?
ROM:000236DF dc.b $90; ?
ROM:000236E0 dc.b $93; ?
ROM:000236D5 dc.b $80; ?
ROM:000236D6 dc.b $80; ?
ROM:000236D7 dc.b $80; ?
ROM:000236D8 dc.b $80; ?
ROM:000236D9 dc.b $80; ?
ROM:000236DA dc.b $80; ?
ROM:000236DB dc.b $80; ?
ROM:000236DC dc.b $80; ?
ROM:000236DD dc.b $7F;
ROM:000236DE dc.b $81; ?
ROM:000236DF dc.b $90; ?
ROM:000236E0 dc.b $93; ?
80 - говорит о тишине (начало звука), т.к. 8 битный звук (1 байт). где 80 как бы середина , а 0 и FF максимальный значения амлитуды колебаний.
Звук PCM (pulse code modulation), соотв. звукам типа WAV, т.е. и те и те 'несжатые' в отиличи от mp3.(mp3-сжатый WAV).
WAV отличается наличием заголвка в котором содержится информация о битности и размере.
В роме размер определяется программой.
Поскольку звук cчитывается процессором z80, мы не найдем на 'lea' на начальный адрес массива звуков. Однако могут быть массивы оффсетов на адреса для каждого звука. (абсолютные или от-ные).
Оффсеты могут быть и на музыку.
Пример 'взломанных' относительных оффсетов:
ROM:000234D2 dc.w $2A ; 42sounds
ROM:000234D4 larry_adr_lngt: dc.l $36CC
ROM:000234D8 dc.w $1A70
ROM:000234DA dc.w 0
ROM:000234DC dc.l 0
ROM:000234E0 dc.l $513C
ROM:000234E4 dc.w $309F
ROM:000234E6 dc.l 0
ROM:000234D4 larry_adr_lngt: dc.l $36CC
ROM:000234D8 dc.w $1A70
ROM:000234DA dc.w 0
ROM:000234DC dc.l 0
ROM:000234E0 dc.l $513C
ROM:000234E4 dc.w $309F
ROM:000234E6 dc.l 0
$36CC адрес начала звука, от-но адреса $20000.
ROM:00020000 SOUND_MUSIC:
ROM:00012ACE move.l #SOUND_MUSIC,d0
ROM:00012AD4 move.b d0,(z80_xz_5).l
ROM:00012ACE move.l #SOUND_MUSIC,d0
ROM:00012AD4 move.b d0,(z80_xz_5).l
$1A70 - размер (длительность) звука.
Это требует доли смекалки, т.е. сразу так догадаться ни у кого не получается.
Хайд:
ROM:00020000; snd_music
ROM:0006B000 unk_0_6B000: dc.b $20 ; DATA XREF: sub_0_E38:loc_0_E3Co
ROM:0006B000 ; sub_0_E74+4o ...
ROM:0006B000 unk_0_6B000: dc.b $20 ; DATA XREF: sub_0_E38:loc_0_E3Co
ROM:0006B000 ; sub_0_E74+4o ...
* Вы можете заменять звуки как угодно через goldwave. (т.е. это можно делать и без изучения рома через IDA и WINHEX)
Графика:
Для нахождения и изменения графики в роме используются т.н. тайловые редакторы.
Откроем ROM с помощь тайлового редактора:
YY-CHR V0.98
File->open
Во вкладах выставим 4Bpp MSX/GENESIS.
Теперь используя стрелки найдем нечто похожее на графику. 'Каша' означает что это не графика (а данные, код, звук).
Т.е. как в goldwave мы слышли скрипы, тут видим кашу.
В случае нахождения графики (например машины или персонажа), стоит прокрутить все опции (вместо Normal другие), это выбирает порядок расположения тайлов. (блоков графики).
Нужный порядок(карта тайлов) задается в программе игры. Сама карта является 'data'ой.
Также палитра (набор цветов) задается в программе. Палитры расположены в других, отедельных от графики местах.
в YY-CHR на глаз можно подобрать нужную палитру.
Пример в роме Rock n' Roll Racing машины (их части) можно увидеть в конце рома.
Конец их графики уже известен, теперь надо определить начало, адрес с которого примерно начинается графика машин BF400.
(это видно в YY-CHR) сверху на вкладке на file open и т.д.
yy-CHR (BF400/100000).
Теперь идем к этому адресу в IDA.
Теперь будем искать переход (запрос) на чтение графики программой.
XREF нашелся по адресу BF500
ROM:000BF500 unk_0_BF500: dc.b 0 ; DATA XREF: sub_0_6394+Eo
ROM:000BF501 dc.b 0
ROM:000BF502 dc.b 0
ROM:000BF503 dc.b 0
ROM:000BF504 dc.b 0
ROM:000BF505 dc.b 0
ROM:000BF506 dc.b 0
ROM:000BF501 dc.b 0
ROM:000BF502 dc.b 0
ROM:000BF503 dc.b 0
ROM:000BF504 dc.b 0
ROM:000BF505 dc.b 0
ROM:000BF506 dc.b 0
код после jump to xref.
ROM:000063A2 addi.l #unk_0_BF500,d0
ROM:000063A8 movea.l d0,a0
ROM:000063A8 movea.l d0,a0
В этом случае использовалось не lea или move, а addi. Это более редкий вариант. Также Xref может идти к оффсету (а от него уже к программе).
Если вы ничего не нашли кроме 'каши', значит графика сжата. (т.е. заархивирона как winrar). Также часть графики может быть сжата, а часть не сжата . Пример RRR - (cжата графика планет и аватары).
Это сделано для экономии места, т.к. картирджная память была дорогая и место было ограничено.
Сжата может быть не только графика, (в RRR сжаты также конфиги трасс, и палитры планет).
Графика 'расжимается' программно подпрограммой-распаковщиком, переносясь в RAM. Расжимается только что-то одно конкретное (графика одной планеты), т.к. место в RAM еще более ограничено.
С помощью winrar или zip, эти архивы открыть нельзя. В каждой игре использовались свои аглоритмы архивирования, но тем не менее есть многих похожих (напр. LZSS).
Без специальных программ распаковки их вскрыть нельзя. Для бол-ва форматов и игр можно найти соотв. программы распаковщики.
Также в редких случаях может использоваться 2 или 3 разных способа сжатия.
Чтобы вскрыть архивы, если программа-распаковщик открывает только их, а не ром целиком, надо найти их точные адреса.
Адреса и размеры могут быть заданы оффсетами:
Пример организации архивов в RRR, от-ные ссылки на архивы:
ROM:0006B000 dword_0_6B000: dc.l $2000037C ; DATA XREF: sub_0_E38:loc_0_E3Co
ROM:0006B000 ; sub_0_E74+4o ...
ROM:0006B004 dc.l $20000688
ROM:0006B008 dc.l $B2A
ROM:0006B00C dc.l $20000B50
ROM:0006B010 dc.l $2F30
ROM:0006B014 dc.w $2000
ROM:0006B016 dc.w $2F7A
ROM:0006B000 ; sub_0_E74+4o ...
ROM:0006B004 dc.l $20000688
ROM:0006B008 dc.l $B2A
ROM:0006B00C dc.l $20000B50
ROM:0006B010 dc.l $2F30
ROM:0006B014 dc.w $2000
ROM:0006B016 dc.w $2F7A
6B000 + 37C = первый архив по адресу 6b000+37c = 6b37c второй 6B000+688 = 6b688, размер архива не задан - высчитывается разницей между соседними архивами.
Размер также может быть указан рядом, быть задан в программе, находится в самом архиве, быть заданным (фиксированным) - для однотипных архивов.
цифра $20 в данном случае не используется, видимо в н-кых писали как пробел вместо 00.
Чтобы понять как именно устроено надо изучать программу.
"Хайд":
ROM:0001FFFE dc.b 0
ROM:0001FFFF dc.b 0
ROM:00020000; sound_music
ROM:0006B000; archives
ROM:000BF500; cars_gfx
ROM:0001FFFF dc.b 0
ROM:00020000; sound_music
ROM:0006B000; archives
ROM:000BF500; cars_gfx
"Отрезали солидные куски", Во всех остальных частях РОМа находятся код, данные и пустое место, которые нужно отделить друг от друга.
Пустое место может быть не только 'Нулями' '00', может быть 'залито' 'FF'.
Замечу что в несжатой графике тоже много нулей, но это не пустое место. (т.е. если мы начнем туда что-то совать,
например свой код, мы получим подпорченную графику - модели машин с 'артефактами'.). Чтобы не гадать просто расширяйте РОМ как описано в гайде. К тому же при расширении вы будет знать, что записывали в новую облсть.
(а не сунули там куда-то в середину , а куда забыли.)
Data hacking. часть3.
Кроме описанных данных в РОМе содержатся 'типичные' данные (т.е. содержатся в любой игре) :
К этим данным можно отнести:
Палитры (наборы цветов)
Комбинации кнопок (игры с комбо-ударами или пос-ти на читы)
Значения от нажатий кнопок в RAM.
Ascii - текст, если игра использует данный вид текста.
Палитры.
Это наборы цветов которые необходимы для 'раскраски' графики.
в HEX-виде палитры выглдят следующим образом:
0EEE, 0AC8, 0246, 0E00, 000A. (тип данных word).
разобраться в них достаточно просто - '0BGR' , (blue green red) т.е. первая цифра соотв. кол-ву синего, вторая зеленего, третья - красный.
Комбинируя 3 составляющие можно получить любой цвет 000 - черный 0EEE (белый) 0888 - (серый)
Цифры могут быть только четными (0,2,4,6,8,a,c,e) - это говорит о 9 битности цвета. 8^3=512 цветов.
(но одновременно железо сеги позволяет отображать только от 16 до 61 (в лучшем случаем)) цветов.
Поэтому и используются палитры.
Типичный вид палитр: (в примере палитры уже переведены в вид word - кнопка 'D' , если забыли)
Палитра в RRR для синих машин:
ROM:00006776 word_0_6776: dc.w 0 ; DATA XREF: sub_0_5DAE:loc_0_5DE0o
ROM:00006778 dc.w $C86
ROM:0000677A dc.w $C44
ROM:0000677C dc.w $A22
ROM:0000677E dc.w $444
ROM:00006780 dc.w $222
ROM:00006782 dc.w $460
ROM:00006784 dc.w $460
ROM:00006786 dc.w $460
ROM:00006788 dc.w $460
ROM:0000678A dc.w $460
ROM:0000678C dc.w $EEE
ROM:0000678E dc.w $AAA
ROM:00006778 dc.w $C86
ROM:0000677A dc.w $C44
ROM:0000677C dc.w $A22
ROM:0000677E dc.w $444
ROM:00006780 dc.w $222
ROM:00006782 dc.w $460
ROM:00006784 dc.w $460
ROM:00006786 dc.w $460
ROM:00006788 dc.w $460
ROM:0000678A dc.w $460
ROM:0000678C dc.w $EEE
ROM:0000678E dc.w $AAA
В некоторых случаях палитры могут быть сжаты (запакованы).
Некоторые ромхакеры для быстрого поиска палитры используют сейв-файлы эмулятора. (в них хранится текущая палитра).
Скопировав через WINHEX и вбив в поиск соотв. цифры можно найти эту палитру.
Можно просто поискать в ром-файле популярные цвета (0EEE), в winhex search-find-hex values - 0EEE, ok.
Текст в формате ascii. (это обычный текст на английском).
Его можно найти в winhex в правой вкладке, о чем упоминалось вначале.
в IDA текст по умолчанию выглядит так:
ROM:0000398C unk_0_398C: dc.b $50; P ; DATA XREF: text_string+10o
ROM:0000398D dc.b $4C; L
ROM:0000398E dc.b $41; A
ROM:0000398F dc.b $59; Y
ROM:00003990 dc.b $45; E
ROM:00003991 dc.b $52; R
ROM:00003992 dc.b 0
ROM:00003993 dc.b $54; T
ROM:00003994 dc.b $52; R
ROM:00003995 dc.b $41; A
ROM:00003996 dc.b $43; C
ROM:00003997 dc.b $4B; K
ROM:00003998 dc.b $3A; :
ROM:00003999 dc.b 0
ROM:0000399A dc.b $52; R
ROM:0000399B dc.b $41; A
ROM:0000399C dc.b $43; C
ROM:0000399D dc.b $45; E
ROM:0000399E dc.b $53; S
ROM:0000398D dc.b $4C; L
ROM:0000398E dc.b $41; A
ROM:0000398F dc.b $59; Y
ROM:00003990 dc.b $45; E
ROM:00003991 dc.b $52; R
ROM:00003992 dc.b 0
ROM:00003993 dc.b $54; T
ROM:00003994 dc.b $52; R
ROM:00003995 dc.b $41; A
ROM:00003996 dc.b $43; C
ROM:00003997 dc.b $4B; K
ROM:00003998 dc.b $3A; :
ROM:00003999 dc.b 0
ROM:0000399A dc.b $52; R
ROM:0000399B dc.b $41; A
ROM:0000399C dc.b $43; C
ROM:0000399D dc.b $45; E
ROM:0000399E dc.b $53; S
Для преобразования в строку, выделите нужное слово и нажмите хоткей 'a'.
Итог:
ROM:0000398C aPlayer: dc.b 'PLAYER' ; DATA XREF: text_string+10o
ROM:00003992 dc.b 0
ROM:00003993 aTrack: dc.b 'TRACK:'
ROM:00003999 dc.b 0
ROM:0000399A aRaces: dc.b 'RACES'
ROM:00003992 dc.b 0
ROM:00003993 aTrack: dc.b 'TRACK:'
ROM:00003999 dc.b 0
ROM:0000399A aRaces: dc.b 'RACES'
Рекомендуется сразу же удалить, образовавшиеся в результате метки. (aPlayer) , т.е. делаем rename и оставляем пустое поле.
Иначе ваша база меток (вкладка NAMES в IDA) , окажется забитой ненужной кучей ссылок на текст.
Кроме того если строка получилась длинной, и метка тоже, это может вызвать баг.
Как я уже упоминал в названиях следует использовать короткие имена - не более 14 символов.
Если текста много можно скрыть область ('hide').
Последовательности кнопок.
Каждому нажатию кнопки соотв. определенный код. Этот код записывается в RAM.
Самый частый вариант комбинации 'нажатие - код'.
ВВЕРХ - 0100
ВНИЗ - 0200
ВЛЕВО - 0400
ВПРАВО - 0800
A - 4000
B - 1000
C - 2000
start - 8000
Если игра использует 3-кнопчный контроллер, значения скорее всего будут 1-байтные. т.е. 01, 02, 04, 40, 20 и т.д.
Второй байт нужен для кнопок X Y Z MODE.
при нажатии A+B получается 'сумма битов' нажатий , т.е 5000.
Где находятся значения в RAM следует искать с помощью поиска читов. (зажимайте вверх + нажмайте esc для паузы эмуляции, теперь можно искать это значение в памяти не удерживая 'вверх' :) )
Если вы нашли верное значение, то при нажатии кнопок оно будет меняться в соотв. с этими кодами.
Значение может быть в нескольких адресах (на нажатие, отжатие и т.д.).
в IDA эти значения можно переименовать как Joy_data. Т.е. также как мы искали и переименовывали другие переменные.
Также их можно найти через IDA, по xrefs'y от адреса 00A10002 (порты), попав к программе-драйверу джойстика.
(может еще быть a10005). И изучив эту программу (куда в RAM она записывает значения).
IO_CT1_data:00A10002; Segment type: Pure data
IO_CT1_data:00A10002; segment "IO_CT1_DATA"
IO_CT1_data:00A10002 ds.b 1
IO_CT1_data:00A10003 IO_CT1_DATA_: ds.b 1 ; DATA XREF: JOYSTICKS_DRV_1+2Ao
IO_CT1_data:00A10002; segment "IO_CT1_DATA"
IO_CT1_data:00A10002 ds.b 1
IO_CT1_data:00A10003 IO_CT1_DATA_: ds.b 1 ; DATA XREF: JOYSTICKS_DRV_1+2Ao
Заданные последовательности кнопок: (эти последовательности прописаны в ROM) .
Программа устроена так что сверяет значения из RAM cо значениям из ROM. (и если всё совпало - условие выполнено - идет переход к коду спецудара или включению чита).
RRR - Секретный код выбор 'Олафа'.
ROM:00007358 char_secr_code: dc.w $100 ; DATA XREF: char_select_frameo
ROM:0000735A dc.w $800
ROM:0000735C dc.w $100
ROM:0000735E dc.w $800
ROM:00007360 dc.w $200
ROM:00007362 dc.w $400
ROM:00007364 dc.w $200
ROM:00007366 dc.w $400
ROM:00007368 dc.w $800
ROM:0000736A dc.w $FFFF
ROM:0000735A dc.w $800
ROM:0000735C dc.w $100
ROM:0000735E dc.w $800
ROM:00007360 dc.w $200
ROM:00007362 dc.w $400
ROM:00007364 dc.w $200
ROM:00007366 dc.w $400
ROM:00007368 dc.w $800
ROM:0000736A dc.w $FFFF
$FFFF в этом случае означает 'конец'. Данные комбинации можно найти и без IDA, (как и в случае с палитрами).
Однако если значения были 1-байтные , обычным поиском через hex это будет практически невозможно.
Подводные камни и прочие трюки.
** игры от EA и другие игры которые не запускаются при любом изменении.
Снятие 'защиты'. Hot trick.
Используйте 'MASTER' code из книги гейм-гени кодов Codebook.exe или с сайтов где описаны гейм-гени коды.
Этот код описывается как необходимый для того,чтобы работали все остальные коды.
На самом деле он является кодом отключения защиты.
Переведя этот код в формат Adress:data, и вписав это значение через WINHEX в ром-файл мы отключим код проверки дополнительной чексуммы.
Прежде чем продолжать дальше дизасмить базу (определять данные и код).
Важно знать следующие баги в IDA:
"-1(a0) bug"
При дизасме IDA автоматически определяет отрицательные от-но регистров (a0), (a1) и т.д. смещения как адрес RAM FFFFxxxx. На самом деле это не так, так произойдет только в том, случае если в регистр был равен a0=00000000. А как мы уже знаем, он может быть равен чему угодно.
Пример(dune):
ROM:00025708 move.w (word_0_FFFFF3BE).w,d1
ROM:0002570C sub.w dword_0_FFFFFFF4(a4),d1
ROM:00025710 move.w d1,(word_0_FFFFF3BE).w
ROM:00025708 move.w (word_0_FFFFF3BE).w,d1
ROM:0002570C sub.w dword_0_FFFFFFF4(a4),d1
ROM:00025710 move.w d1,(word_0_FFFFF3BE).w
a4 не обязательно равен 00000000.
Исрпавляем (нажав хоткей 'q') :
ROM:00025708 move.w (word_0_FFFFF3BE).w,d1
ROM:0002570C sub.w -$C(a4),d1
ROM:00025710 move.w d1,(word_0_FFFFF3BE).w
ROM:0002570C sub.w -$C(a4),d1
ROM:00025710 move.w d1,(word_0_FFFFF3BE).w
В случаях если игра не использует данный метод обращения к 'копии' RAM (FFFFxxxx), можно вообще удалить этот сегмент.
Вы должны быть уверены что вы делаете, и что точно не использует прежде чем удалять. Dune использует все три варианта обращения к RAM.
* сегмент RAM FFFF0000 - FFFFFFFF, можно удалить в базе Rock n' Roll Racing.
"offset bug"
IDA автоматически определяет многие адреса как оффсеты, хотя они ими не являются.
Пример (dune):
ROM:0002EC7A off_0_2EC7A: dc.l off_0_10018 ; DATA XREF: sub_0_2EBFCo
ROM:0002EC7E dc.b 0
ROM:0002EC7F dc.b $18
ROM:0002EC80 dc.b $FF
ROM:0002EC81 dc.b $F4; ?
ROM:0002EC82 dc.b $A
ROM:0002EC83 dc.b 0
ROM:00009DB6 off_0_9DB6: dc.l loc_0_20016+2 ; DATA XREF: ROM:00009D94o
ROM:00009DBA dc.b 0
ROM:00009DBB dc.b $20
ROM:00009DBC dc.b 0
ROM:00009DBD dc.b 0
ROM:00009DBE dc.b $A
ROM:0002EC7E dc.b 0
ROM:0002EC7F dc.b $18
ROM:0002EC80 dc.b $FF
ROM:0002EC81 dc.b $F4; ?
ROM:0002EC82 dc.b $A
ROM:0002EC83 dc.b 0
ROM:00009DB6 off_0_9DB6: dc.l loc_0_20016+2 ; DATA XREF: ROM:00009D94o
ROM:00009DBA dc.b 0
ROM:00009DBB dc.b $20
ROM:00009DBC dc.b 0
ROM:00009DBD dc.b 0
ROM:00009DBE dc.b $A
Из идущих вслед значений нельзя получить нормальные оффсеты (нельзя продолжить массив - таблицу адресов).
Исправление:
Провести undefine на данные значение (хоткей 'U')
ROM:00009DB6 unk_0_9DB6: dc.b 0 ; DATA XREF: ROM:00009D94o
ROM:00009DB7 dc.b 2
ROM:00009DB8 dc.b 0
ROM:00009DB9 dc.b $18
ROM:00009DB7 dc.b 2
ROM:00009DB8 dc.b 0
ROM:00009DB9 dc.b $18
В большом кол-ве этот вид бага можно получить если вы делали 'final analisys pass'.
"move.w #loc_ bug. "
Баг - число принимается за адрес (метку).
Пример:
ROM:00000D6A move.w #loc_0_8124,(word_0_C00004).l
ROM:00000D72 move.w #loc_0_8124,(word_0_FFFFE00C).w
ROM:00000D78 bsr.w sub_0_4E8
ROM:00000D7C bsr.w sub_0_536
ROM:00000D80 bsr.w sub_0_41C
ROM:00000D84 move.w #unk_0_8004,(a5)
ROM:00000D88 move.w #unk_0_8700,(a5)
ROM:00000D8C
ROM:00000D8C loc_0_D8C: ; DATA XREF: ROM:000198C8o
ROM:00000D8C move.w #loc_0_8B08,(a5)
ROM:00000D90 move.b #(dword_0_0+$80),(word_0_A1000C+1).l
ROM:00000D98 move.w #(loc_0_8FFC+5),(a5)
ROM:00000D72 move.w #loc_0_8124,(word_0_FFFFE00C).w
ROM:00000D78 bsr.w sub_0_4E8
ROM:00000D7C bsr.w sub_0_536
ROM:00000D80 bsr.w sub_0_41C
ROM:00000D84 move.w #unk_0_8004,(a5)
ROM:00000D88 move.w #unk_0_8700,(a5)
ROM:00000D8C
ROM:00000D8C loc_0_D8C: ; DATA XREF: ROM:000198C8o
ROM:00000D8C move.w #loc_0_8B08,(a5)
ROM:00000D90 move.b #(dword_0_0+$80),(word_0_A1000C+1).l
ROM:00000D98 move.w #(loc_0_8FFC+5),(a5)
Исправление (нажать q на число):
ROM:00000D6A move.w #$8124,(word_0_C00004).l
ROM:00000D72 move.w #$8124,(word_0_FFFFE00C).w
ROM:00000D78 bsr.w sub_0_4E8
ROM:00000D7C bsr.w sub_0_536
ROM:00000D80 bsr.w sub_0_41C
ROM:00000D84 move.w #$8004,(a5)
ROM:00000D88 move.w #$8700,(a5)
ROM:00000D8C
ROM:00000D8C loc_0_D8C: ; DATA XREF: ROM:000198C8o
ROM:00000D8C move.w #$8B08,(a5)
ROM:00000D90 move.b #$80,(word_0_A1000C+1).l
ROM:00000D72 move.w #$8124,(word_0_FFFFE00C).w
ROM:00000D78 bsr.w sub_0_4E8
ROM:00000D7C bsr.w sub_0_536
ROM:00000D80 bsr.w sub_0_41C
ROM:00000D84 move.w #$8004,(a5)
ROM:00000D88 move.w #$8700,(a5)
ROM:00000D8C
ROM:00000D8C loc_0_D8C: ; DATA XREF: ROM:000198C8o
ROM:00000D8C move.w #$8B08,(a5)
ROM:00000D90 move.b #$80,(word_0_A1000C+1).l
# - говорит о том что, это число, а не адрес. В некоторых случаях число все же может являются адресом (или его частью).
Это можно понять лишь значительно изучив программу и ассемблер. в 90% случаях это является багом.
Поэтому его нужно фиксить. Этот вид 'бага' может присутсвовать в огромном кол-ве. Поэтому не старайтесь сразу его исправить.
"Баг строк"
Этот баг может возникнуть в случае использования длинных ascii строк или создания такой без выделения, а также если вы делали 'final analysis pass'. Баг состоит в том, что начинает глючить список имен (+забивается ненужными именами).
Также можно схватить и 'too many lines' баг.
Баг too many lines' в Dune. (IDA определила как строку автоматически при final analysis).
ROM:000E0000 aTPqkleqamiompfdMoLkklepHvm9$:dc.b '}?-L------+=+¬??????????????¦L¦+¬T-LT¦??¬¦??kleP;HVM9//$ !$ (2@NYd|?shu?????¦-??????ztx}???-???¬T-+¦T¦¦T-TL+¦---¬????'
ROM:000E0000 ; DATA XREF: ROM:000061C4o
ROM:000E0000 ; ROM:000483BAo ...
ROM:000E0000 dc.b '}^NFA7# #,>V[SS\kqkrzw_RV[djbSSJ?>MY\VYm???????--¦????????????????????????????-L+T+-L¬??--¬¦????zkUPV__P8#+22* ,/-(! &'
ROM:000E0000 dc.b '5EOS]XOSj??zb^n???-T¦¦¦¦L¦T-T-¬¬¦+T¦??-?+¦----++¦????-??pPA4( &8A51Jag_X^\TPKB1/;A@BJRQSZbZ^k}????-+T-¦¬¬¬¦¦¦????yninttoged'
ROM:000E0000 dc.b 'diq???????-??¦¦??zm_SLC>@AHWhtz|?????¦¦+?????????uz~wfRKLRVTPWf|???????-???zqhT\e^PL@8DVdoz?????-¦¦¦++¦?????|qw?????????z}??'
ROM:000E0000 ; DATA XREF: ROM:000061C4o
ROM:000E0000 ; ROM:000483BAo ...
ROM:000E0000 dc.b '}^NFA7# #,>V[SS\kqkrzw_RV[djbSSJ?>MY\VYm???????--¦????????????????????????????-L+T+-L¬??--¬¦????zkUPV__P8#+22* ,/-(! &'
ROM:000E0000 dc.b '5EOS]XOSj??zb^n???-T¦¦¦¦L¦T-T-¬¬¦+T¦??-?+¦----++¦????-??pPA4( &8A51Jag_X^\TPKB1/;A@BJRQSZbZ^k}????-+T-¦¬¬¬¦¦¦????yninttoged'
ROM:000E0000 dc.b 'diq???????-??¦¦??zm_SLC>@AHWhtz|?????¦¦+?????????uz~wfRKLRVTPWf|???????-???zqhT\e^PL@8DVdoz?????-¦¦¦++¦?????|qw?????????z}??'
Решение:
Сделать undefine на всю область.
А также удалить названия(имя метки ascii).
Также если вы не заполняли базу, создайте новую с нуля и не делайте final analysis.
Дизасм данных как кода:
Баг когда IDA автоматически дизасмит данные как код.
Как мы уже помним любой код заканчивается на rts, jmp, bra или rte.
Решение - сделать undefine.
Трюки:
Исправление адреса от-но регистра. Это очень важный трюк. Он позволит получить абсолютный доступ к RAM в IDA, даже для от-ного метода адресации. (а значит мы сможем задать и метки и видеть точный адрес).
Этот способ я использовал для фикса адресов в Rock n' Roll Racing.
ДО:
ROM:0000DFEA move.b $395E(a4),$3984(a4)
ROM:0000DFF0 clr.w d1
ROM:0000DFF2 move.b $390F(a4),d1
ROM:0000DFF6 add.b d1,d1
ROM:0000DFF8 add.b $395F(a4),d1
ROM:0000DFFC asl.b #2,d1
ROM:0000DFFE cmpi.b #2,$4ECE(a4)
ROM:0000DFF0 clr.w d1
ROM:0000DFF2 move.b $390F(a4),d1
ROM:0000DFF6 add.b d1,d1
ROM:0000DFF8 add.b $395F(a4),d1
ROM:0000DFFC asl.b #2,d1
ROM:0000DFFE cmpi.b #2,$4ECE(a4)
ПОСЛЕ:
ROM:0000DFEA move.b current_planet-$FF8000(a4),word_0_FFB984-$FF8000(a4)
ROM:0000DFF0 clr.w d1
ROM:0000DFF2 move.b difficlt_level-$FF8000(a4),d1
ROM:0000DFF6 add.b d1,d1
ROM:0000DFF8 add.b divison_num-$FF8000(a4),d1
ROM:0000DFFC asl.b #2,d1
ROM:0000DFFE cmpi.b #2,num_players-$FF8000(a4)
ROM:0000DFF0 clr.w d1
ROM:0000DFF2 move.b difficlt_level-$FF8000(a4),d1
ROM:0000DFF6 add.b d1,d1
ROM:0000DFF8 add.b divison_num-$FF8000(a4),d1
ROM:0000DFFC asl.b #2,d1
ROM:0000DFFE cmpi.b #2,num_players-$FF8000(a4)
Получил доступ к меткам и абсолютным адресам в RAM, где подписаны найденные мною переменные.
В данном случае я знал a4=FF8000, т.к. в RRR он всегда равен FF8000.
Если я нажму на метку я перейду в IDA в абсолютный адрес: $FFB95E. (395E+FF800)., т.е. реальный адрес RAM куда пишется значение.
Во всех остальных случаях регистр быть равен чему угодно, но и там его можно 'отследить'. Для этого надо изучить код, или использовать дебаг на pc на этот ром-адрес. Регистр может быть равен всегда чему-то одному, а может принимать разные значения. (во-втором случае исправление 'неточное', т.к. даст переход только к одному адресу, но это тоже бывает полезно).
Dune:
ROM:00004E74 lea (word_0_FFBF4C).l,a2
ROM:00004E7A move.b #$FC,4(a2)
ROM:00004E74 lea (word_0_FFBF4C).l,a2
ROM:00004E7A move.b #$FC,byte_0_FFBF50-$FFBF4C(a2)
ROM:00004E7A move.b #$FC,4(a2)
ROM:00004E74 lea (word_0_FFBF4C).l,a2
ROM:00004E7A move.b #$FC,byte_0_FFBF50-$FFBF4C(a2)
Трюк выполняется следующим способом:
Выделяем нужный адрес (цифру $395E) и нажимаем CTRL+R. В поле Base adress вписываем адресс который находится в регистре.
Ставим галочку treat base adress as plain number. OK.
Некоторые могут заявить что это не трюк, однако многие известные мне ромхакеры этого не знали, поэтому назыв. так.
Трюк с созданием таблиц:
Допустим вы нашли какие-то данные, знаете за что, они отвечают и хотите их упорядочить.
Для этого выделяем область и жмем правой кнопкой->array. Тут указывается что-то вроде длины и ширины таблицы.
Таблица порядка номеров трасс в RRR данным способом:
(для первой планеты по 4, для второй по 5 и т.д.)
ROM:0000189A trak_sort_vs_m: dc.b 1, 2, 3, 4 ; DATA XREF: tracks_init+1Eo
ROM:0000189A dc.b $25, $26, $27, $28
ROM:000018A2 dc.b 5, 6, 7, 8, 9
ROM:000018A2 dc.b $29, $2A, $2B, $2C, $2D
ROM:000018AC dc.b $A, $B, $C, $D, $E, $F
ROM:000018AC dc.b $2E, $2F, $30, $31, $32, $33
ROM:000018B8 dc.b $10, $11, $12, $13, $14, $15, $16
ROM:000018B8 dc.b $34, $35, $36, $37, $38, $39, $3A
ROM:000018C6 dc.b $17, $18, $19, $1A, $1B, $1C, $1D
ROM:000018C6 dc.b $3B, $3C, $3D, $3E, $3F, $40, $41
ROM:000018D4 dc.b $1E, $1F, $20, $21, $22, $23, $24
ROM:000018D4 dc.b $42, $43, $44, $45, $46, $47, $48
ROM:0000189A dc.b $25, $26, $27, $28
ROM:000018A2 dc.b 5, 6, 7, 8, 9
ROM:000018A2 dc.b $29, $2A, $2B, $2C, $2D
ROM:000018AC dc.b $A, $B, $C, $D, $E, $F
ROM:000018AC dc.b $2E, $2F, $30, $31, $32, $33
ROM:000018B8 dc.b $10, $11, $12, $13, $14, $15, $16
ROM:000018B8 dc.b $34, $35, $36, $37, $38, $39, $3A
ROM:000018C6 dc.b $17, $18, $19, $1A, $1B, $1C, $1D
ROM:000018C6 dc.b $3B, $3C, $3D, $3E, $3F, $40, $41
ROM:000018D4 dc.b $1E, $1F, $20, $21, $22, $23, $24
ROM:000018D4 dc.b $42, $43, $44, $45, $46, $47, $48
Трюки и хоткеи в winhex.
Простой поиск данных.
Например вы ищите точное значение (конретное число), и это число достаточно длинное, т.е. например цена машины.
Число может быть представлено как в 10-чной системе, так и 16-ричной.
в RRR для цен используется десятичная система. цена 24000$.
в поиск вбиваем '00240000', если значений нашлось н-ко следует проверить по группам, или каждое по очереди.
используйте 'replace hex values' для замещения и поиска всех сразу. (для поиска например в части рома выделите область и используйте поиск только в блоке - галочка search in block only.)
Если число 16-ричное (в бол-ве игр именно такое), его надо перевести на калькуляторе и потом искать.
24000= $5DC0, т.е. следовательно надо было вбивать в поиск '5dc0' или '00005dc0'
Если игра содержит много таблиц, (как например rock-n-roll racing - таблица порядка трасс, хар-ки тачек, игроков, список цен, таблицы хар-к для AI (уровни сложности).
в WinHEx в ascii-виде (правая колонка) эти таблицы выглядит в виде точек. Либо других повторяющихся последовательностей
Пример (таблица бонусов игрока + комбо на чит) - точки в ascii. (правая колонка).
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00007320 43 EC 51 9A 12 3B 00 1D D3 31 80 00 4E 75 01 00 C?Q?.;..?1€.Nu..
00007330 01 00 00 01 01 10 10 00 00 10 00 10 00 08 08 08 ................
00007340 00 00 08 00 00 00 01 01 01 01 00 03 00 02 00 03 ................
00007350 00 04 00 00 00 04 00 03 01 00 08 00 01 00 08 00 ................
00007360 02 00 04 00 02 00 04 00 08 00 FF FF E5 40 41 EC ..........???@A?
То есть 'data'-hacking возможен в чистом хекс. Но все зависит от конретной игры. Я например нашел эти 'gamedata' таблицы используя только winhex, также в dune2 я разобрался в конфиге карты, без изучения кода. (т.е. каждое значение соотв. в карте номеру юнита, его координатам на карте и жизням) - что легче определить опытным путем., чем взламывать код.
Хоткеи WINHEX:
CTRL+C - копировать
CTRL+B - 'вставить' (записать), не следует использовать CTRL+V, иначе мы сдвинем все данные.
CTRL+SHIFT+C и ALT+SHIFT+C - копировать значения, для переноса в текстовый файл. (.txt). например на форум.
ctrl -копирует только сами значения, alt - все отображение (ненадо делать скриншот)
ctrl+s - сейв файла.
ctrl+z - отмена последних изменений (очень полезный хоткей, когда игра после изменений зависла, и надо отменить, позволяет обходится без бек-апов).
ALT+G - прыжок к нужному адресу.
Также можно включить режим мнговенного редактирования (ненадо будет делать сейв):
Нажать F6, и выбрать Default Edit Mode (editable).
Также в winhex есть опция открытия жестого диска, и можно восстановить удаленные н-кые файлы.(и ненадо применять программы для восстановления). Хотя это и выходит за рамки гайда (но считаю полезным), т.к. если что-то 'полетит' вы сможете восстанавить базу с помощью winhex (но не 100%) - так что делайте бекап баз на CD-диск.
Трюки с ромами:
Используйте total commander для сравнения двух файлов. Например оригинал и пиратский хак, или просто хак.
Таким образом вы можете узнать где, и что менять, чтобы получить такой же результат. Также это поможет взломать защиту, если другие методы не помогли.
Также сравнивайте свой хак с оригиналом, если забыли где и что меняли, а также на наличие ошибок (когда забыли отменить изменения и они остались).
Заключение:
Таким методом можно взломать любую игру на Sega, также можно использовать некоторые подходы и для других платформ.
В случае если вы ничего не поняли из сего гайда, Вам остается курить бамбук. Так как понятнее может быть лишь с
картинками, а автору это пока что не под силам, т.к. сам мануал получился немаленьким.
Если вы всё поняли, и вам этого недостаточно, то стоит искать более сложные мануалы, ориентированные на что-то одно (например тех. документация на сегу, или руководство программиста по ассемблеру mc68000), т.е. не надейтесь что всё сделают за вас. Если Вы с чем-то несогласны это остается с вами. Если Вы нашли ошибку вы можете написать ее в ПМ автору.
Также не следует задавать вопросов автору (он не обучает хакингу, а только предоставляет сей мануал). Также не следует спорить, о том как нужно писать мануал и что в нем надо переделать. А также запрещается копировать текст из мануала и куда-то его заливать.
Удачного ромхакинга!
Hack guide by Ti. (с) 2010.
*********************************************************************************************************************
****************** demo (not finished) version of guide *************************************************************