Поинтеры. Часть первая.
Автор Guyver   
10.05.2008 г.

ПОИНТЕРЫ. ЧАСТЬ ПЕРВАЯ. (автор: Chief_exb, правка: Guyver)

Введение

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

Ну и также владение HEX-редактором. Я пользуюсь Goldfinger’ом , вы можете взять любой, значения это не имеет. Итак, начнём. Что же такое пойнтер? Для понимания сущности пойнтера приведём небольшой пример. Идеальным примером, на мой взгляд, является Библия. Эта Святая книга содержит много книг, глав и стихов. Богословы и изучающие библию используют в своей практике ссылки на конкретные места в ней. Например (Прит.3:5,6) является ссылкой на этот текст библии:
...
«5 Надейся на Господа всем сердцем твоим, и не полагайся на разум твой.
5 Надейся на Господа всем сердцем твоим, и не полагайся на разум твой.
6 Во всех путях твоих познавай Его, и Он направит стези твои».


Так и программисты, делая игру, ставят ссылки на текст, а переводчик этим пользуется. Есть таблица пойнтеров, в которой указаны адреса начала сообщений, причём этот адрес не совпадает с тем адресом, который нам показывает HEX-редактор. Для вывода текста в игре идёт команда вывести, к примеру, 5-е сообщение. Программа ищет адрес пятого сообщения, загоняет его регистры и выводит сообщение на экран. Сигналом об окончании является символ конца сообщения, в моей практике им в 9 из 10 случаев является FFh.

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

Практика

SET X000h: чтобы не было разночтений, все адреса даны в шестнадцатеричной системе в формате 456AFh, следите за тем, чтобы не путать адрес в файле РОМА и адрес в реальном картридже.

Итак, для практики я взял игру Adventures of Bayou Billy, The (U). Составив таблицу для текста из заставки (просто их тут множество), я открыл GoldFinger и загрузил РОМ и таблицу, потом начал искать мой текст. Текст нашёлся по адресу 1685Fh.
 
Adventures of Bayou Billy, The (U)


Для поиска выберем три адреса сообщений:

1685Fh
16881h
16913h


Это адреса в редакторе, т.е. реальный адрес в роме будет на 10h меньше (размер заголовка РОМА y NES) . Отнимем то всех адресов размер заголовка.

1685Fh-10h=1684Fh
16881h-10h=16871h
16913h-10h=16903h


Для системы SET X000h (в неё по моему мнению укладывается большая часть систем пойнтеров) следует взять младшие три шестнацатиричных разряда адреса и прибавить X000, где X=0h..Fh (от 0h до Fh). Примечание: как правило X=Ah, или лежит в более узких пределах от 8h до Fh. Но бывают случаи, когда необходим полный перебор. Далее следует учесть, что адреса лежат в таком порядке: младший адрес, старший адрес.

Применив это все, получаем кусок предполагаемой таблицы пойнтеров для наших адресов:

4F8871880389 для X=8h
..
..
4FA871A803A9
для X=Ah
..
..
4FF871F803F9
для X=Fh

И ищем поочерёдно данные последовательности кода, поиск ничего не дал во всех случаях. К сожалению РОМ с изюминкой, пробуем искать не все три сообщения, а два.

Кусок предполагаемой таблицы 48A871A8h найден по адресу 167B4h (т.е. как я и говорил X=Ah), но в таблице сообщения идут немного не в том порядке, как они записаны в РОМЕ. Видимо так было удобнее. Таблица пойнтеров позволяет в ней писать адреса в любом порядке, главное она найдена. И мы можем теперь найти все сообщения, на которые она ссылается. Это не самое начало таблицы, но для понимания пойнтеров нам это не важно.

Попробуем изменить указатель. На первое сообщение поставим вместо 4Fh->71h. Сохраняем, загружаем РОМ. Второе сообщение было выведено два раза.
 
Adventures of Bayou Billy, The (U)


Таблица пойнтеров найдена. Как теперь это использовать? Пример, изменилась длина сообщения: уменьшилась или увеличилась, как быть с указателями? Надо пересчитать адреса двух или более сообщений (столько, сколько вы затронули в своем переводе плюс 1). Берёте адрес, точнее три младшие разряда адреса, отнимаете размер заголовка рома (у NES 10h, а у SNES 200h). Добавляете X000, где в нашем случае X=Ah. Получаете адрес, адрес записываете в том же формате, младший байт, старший байт.

Пример:

Новый адрес начала сообщения:

16469h-10h=16459h

Новый адрес равен X000h+459h, где х=Ah, т.е. равен

A000h+459h=A459h

Заключение

Ну вот и всё! Хочется заметить, что работа с пойнтерами не всегда идёт по шаблону. Писав данный faq я специально взял РОМ мне незнакомый, чтобы показать, что не всегда все идёт гладко. В следующих faq я хочу раскрыть тему о словарной системе, как с ней работать. Что касается данного алгоритма, то он  работает почти всегда. Бывают исключения - в моём переводе игры Adventures in the Magic Kingdom я наткнулся тоже на систему Set X000, только младший и старшие биты были записаны в разных местах (двух массивах).
Последнее обновление ( 13.11.2014 г. )