История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами

История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами

В начале прошлой главы на первом изображении я наглядно показал, что блоков с поинтерами в исполняемом файле всего более 40 штук. А теперь представьте, что все ранее описанные этапы нужно повторить заново с каждым из них. В таких случаях даже программистам приходится искать вручную каждый блок и идентифицировать все поинтеры. Потому что автоматизировать этот процесс очень сложно, ведь расположение поинтеров в большинстве блоках хаотичное, так как в одних расстояние между поинтерами одно, а в других – другое. Кроме того, расстояние в одном блоке поинтеров между разными указателями тоже может отличаться. А вот насколько сильно – вы можете посмотреть на приведённом изображении ниже:

История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами

Наглядная визуализация разных расстояний между поинтерами. Красным отмечены области с расстоянием по 4 байта, синим по 8 байт, а зелёным по 12 байт соответственно.

В этом случае возникает вопрос: а как в таком беспорядке abcde будет справляться с распознаванием поинтеров? Автор данного приложения этот момент не продумал. Если мы зададим программе интервал, то при извлечении текста в рамках этого интервала приложение будет пытаться прочитать поинтеры принудительно. Иначе говоря, после считывания обычных указателей приложение рано или поздно попытается считать поинтер из той области, которая не является поинтером. И именно в этот момент в строке с извлечённым текстом от программы стоит ожидать различного рода мусора, который будет очень сильно мешать работе в целом. Эти мусорные данные среди полезного текста выглядят примерно вот так:

История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами

Розовым, чёрным и зелёным цветами отмечены блоки, которые программа ошибочно воспринимает за поинтеры и пытается извлечь текст по этим адресам. В результате прочитанные значения могут выходить за пределы массива данных файла, что в свою очередь создаёт различную несогласованность адресов. На данном изображении это отмечено серыми стрелками. Кроме того, если при попытке считывания по ложному смещению попадается первый байт со значением 0x00, то в таком случае эта строка будет пустой при извлечении и ничего кроме тега [END] мы не увидим в сформированном блоке поинтера.

Напомню, что файлы с извлечёнными строками текста содержат свой блок данных для каждого поинтера, и в этих файлах их можно спокойно копировать и удалять, а также склеивать между собой как угодно, не нарушая синтаксис. Примерно вот так:

История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами

И здесь, как вы уже, скорее всего, догадались, все мусорные блоки с текстом, которые были идентифицированы ошибочно, придётся удалять вручную. По-другому от них никак не избавиться, потому что с помощью abcde этот процесс не автоматизировать. Можно удалять мусорные блоки прямо в текстовом редакторе, но для визуального облегчения всё это я копировал в эксель и уже там сортировал удобным образом. Поскольку в текстовом редакторе весь синтаксис тегов сливается с полезным текстом и различать мусорные данные там довольно непросто: есть риск ошибиться и захватить полезные строки. В экселе же есть возможность графически выделить разные строки, что явно ускоряет идентификацию. Наглядно это выглядит вот таким образом:

История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами

Это ещё не всё, что хотелось бы осветить по поводу поинтеров. Дело в том, что, помимо простых указателей с поправкой, ещё существует второй тип поинтеров, которые записаны в функциях в виде инструкций прямо среди основного кода исполняемого файла. И не всегда их легко различить визуально. В нашем случае несколько таких поинтеров попадается в исполняемом файле, и работу с ними мне тоже пришлось освоить. Приложение abcde нам никак не поможет, потому что уровень сложности в этом случае резко возрастает и требует более глубоких знаний и понимания кода архитектуры процессора MIPS R5900, который используется в играх для платформы PlayStation 2. Для поиска таких поинтеров в очередной раз обращаемся к инструментам обратной разработки: IDA Pro или Ghidra. Как и в прошлый раз, опишу этот процесс, выполняемый с помощью IDA Pro.

Этап 1. Поиск функции, в которой прописан нестандартный поинтер

а) Повторяем первоначальные шаги, которые были описаны в прошлой главе. Ищем нужные нам строки с текстом в исполняемом файле с помощью хекс-редактора, поинтеры которых не получилось найти. В качестве примера я выбрал строку вот с этим текстом: Chambers. Загружаем SLPS_254.50 в IDA Pro. Ждём, как приложение просчитает взаимосвязи всех функций. Далее щёлкаем по вкладке "Hex View-1" и ищем здесь начало того же текста, который нашли в хекс-редакторе. Вам необязательно сначала искать текст в хекс-редакторе, а потом в IDA Pro. Если вы достаточно хорошо ориентируетесь в IDA, то можете сразу начинать поиски текста в этом приложении. После того, как нашли строку с текстом, щёлкаем по вкладке "IDA View-A". Вы увидите вот такое окно:

История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами

б) На представленном изображении в прошлом пункте наглядно видно, как чуть ниже строки с текстом программа прописывает адресацию к функции, в которой указан индекс к началу этого текста. Наводим курсором на эту взаимосвязь "# DATA XREF: .text:00153B3C↑o" и щёлкаем 2 раза:

История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами

в) После того как два раза нажали на взаимосвязь "# DATA XREF: .text:00153B3C↑o", вас должно перекинуть на окно, которое по своей сути является просмотрщиком дизассемблированного кода:

История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами

Таким образом мы попадаем в одну из функций, в которой прописаны определённые инструкции для работы с данной строкой. Именно здесь нам и предстоит ориентироваться в поисках нестандартного поинтера.

Этап 2. Определение верхней и нижней частей среди инструкций для формирования целого поинтера

а) В первую очередь важно понять, что придётся часто переключаться между окнами "IDA View-A" и "Hex View-1", а также постоянно держать в голове поправку FF000 для точных расчётов. Можно упростить себе задачу и держать под рукой калькулятор для подсчётов в шестнадцатеричной системе счисления. Найденная область функции содержит данные сразу для работы с тремя строками:

Оригинальный текст японской версии:
1) 謎の館
2) The Hidden Chambers
3) この中に何があるのか……<__>全てが謎につつまれた館。

Текущий вариант перевода строк в нашей локализации:
1) Таинственный особняк
2) [SPACE]
3) Особняк, окутанный тайнами.<__>Никто не знает, что в нём.

Все они относятся к названию и описанию локации "Таинственный особняк". Но для того, чтобы вычислить каждый поинтер для всех этих строк, потребуются определённые манипуляции c идентификацией инструкций, в которых и спрятаны поинтеры. Кроме того, поинтеры для каждой строки разделены на 2 части и наша задача каждую из них найти, развернуть и правильно сложить.

Перед тем, как приступить к следующему шагу, нужно немного рассказать об особенностях данного типа поинтеров. Процессоры MIPS работают с 32-битными указателями. Размер любого поинтера в памяти составляет 32 бита. Проще говоря, это 4 байта. Например: 0x0022C268. Это в свою очередь накладывает определённые ограничения, потому что любая инструкция MIPS занимает ровно 4 байта. В этот размер можно уместить: код операции, номера регистров и числовую константу (immediate). В итоге на константу в одной инструкции остаётся всего 2 байта. Это означает, что в одну инструкцию умещается только половина поинтера. Именно поэтому весь указатель собирается из двух инструкций. Первая инструкция загружает верхние 2 байта, а вторая добавляет нижние 2 байта. В этом и заключается основная задача: понять, где в инструкциях прописаны числовые константы для верхней и нижней части поинтера.

История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами
История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами
История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами
История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами

б) В окне просмотра дизассемблированного кода "IDA View-A" нужно обратить внимание на следующие строки:

lui $a0, 0x23 # '#'
lui $a1, 0x23 # '#'
lui $v1, 0x23 # '#'

li $a0, unk_22C268
li $a1, aTheHiddenChamb # "The Hidden Chambers"
li $v1, unk_22C290

Первая группа из трёх строк отвечает за верхние части поинтеров, а вторая группа из трёх строк – за нижние. В итоге получаем вот такую взаимосвязь:

Верхняя часть 1 поинтера = lui $a0, 0x23 # '#'
Верхняя часть 2 поинтера = lui $a1, 0x23 # '#'
Верхняя часть 3 поинтера = lui $v1, 0x23 # '#'

Нижняя часть 1 поинтера = li $a0, unk_22C268
Нижняя часть 2 поинтера = li $a1, aTheHiddenChamb # "The Hidden Chambers"
Нижняя часть 3 поинтера = li $v1, unk_22C290

Для того, чтобы корректно отследить каждую часть, а потом сделать определённые изменения в соответствии с нашим переводом, возьмём вторую строку из первой группы и вторую строку из второй группы:

Верхняя часть 2 поинтера = lui $a1, 0x23 # '#'
Нижняя часть 2 поинтера = li $a1, aTheHiddenChamb # "The Hidden Chambers"

Как только щёлкаем в любом месте по нужной нам инструкции в окне "IDA View-A", вся её часть подсвечивается соответствующим образом и в окне "Hex View-1". Пробуем нажать на "0x23" в окне "IDA View-A" (строка верхней части 2-го поинтера), а затем переключаемся на окно "Hex View-1" и наблюдаем, что IDA Pro выделяет все 4 байта этой инструкции:

История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами

Первые 2 байта "23 00" в этом выделенном блоке и являются числовой константой, а именно верхней частью нужного нам поинтера. Запоминаем или записываем это значение. Далее приступаем к поиску нижней части поинтера. Для этого пробуем нажать на "aTheHiddenChamb" в окне "IDA View-A", а затем переключаемся на окно "Hex View-1" и снова наблюдаем, как IDA Pro выделяет все 4 байта другой инструкции:

История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами

Здесь первые 2 байта "78 C2" тоже являются числовой константой, той самой нижней частью нужного нам поинтера. Теперь у нас на руках обе части. Перед тем как их сложить, нужно их развернуть – не забываем, что на консоли PS2 порядок построения байтов в поинтерах записывается в little-endian виде:
23 00 » 00 23
78 C2 » C2 78

Затем складываем:
00 23 + C2 78 = 00 23 C2 78

Мы практически получили готовый поинтер, но не всё так просто. Если из него вычесть поправку FF000 и в исполняемом файле SLPS_254.50 в хекс-редакторе перейти по этому адресу, то мы не попадём на нужную нам строку, потому что существует определённое правило ещё одной поправки для инструкций, но уже для верхней части. Заключается оно в том, что если 2 байта из нижней части меньше или равны значению 0x8000, то к верхней части прибавляется 1 (то есть +0x10000), а если меньше, то эта поправка не нужна.

В соответствии с этим правилом корректируем полученный поинтер, так как значение нижней части поинтера в нашем случаем больше этого числа: C278 > 8000.

Пересчитываем:
00 23 C2 78 - 00 01 00 00 = 00 22 C2 78

Вот только теперь мы получили правильный поинтер, от которого нужно отнять поправку FF000, о которой я просил вас не забывать:
00 22 C2 78 - 00 0F F0 00 = 12 D2 78

Открываем исполняемый файл в хекс-редакторе и убеждаемся, что все расчёты были проведены правильно и что по данному адресу находится нужная нам строка с текстом:

История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами

Этап 3. Ручное изменение нестандратных поинтеров в хекс-редакторе

а) Ну а теперь, когда нам известно, как найти все нестандартные поинтеры, то можно приступить к их изменению в соответствии с тем переводом текста, который я привёл в начале второго этапа. Есть попытаться вставить текст третьей строки, то он свободно умещается в изначально отведённое пространство. Но со второй строкой сделать это не получится – при попытке укладки переведённого текста в первую строку он начнёт перекрывать текст второй строки. Потому что для первой строки в исполняемом файле всего выделено 15 байт, а наш вариант "Таинственный особняк" занимает 20 байт + ещё нужно учитывать 1 байт окончания строки со значением {00}. Итого для нашего варианта перевода необходим 21 байт, что явно превышает размер 15 байт. Так как укладка текста будет идти в изначальный адрес оригинальной первой строки, то значения поинтера здесь менять не нужно, а вот значения поинтера для второй строки придётся изменить. Для новичков это может звучать немного запутанно, поэтому приведу несколько скриншотов, чтобы стало понятно получше:

История русской локализации Tales of Rebirth (PS2). Глава 7. Очистка строк от лишних данных и работа с нестандартными поинтерами

Оставайтесь с нами.
Дальше будет только интереснее ; )

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

Страница русской локализации Tales of Rebirth:
https://temple-tales.ru/translations_torps2.html

Наше основное сообщество по переводам ВКонтакте:
https://vk.com/temple_of_tales_translations

Наше сообщество по конкурсам ВКонтакте:
https://vk.com/temple_of_tales_quiz

🎵 Наше музыкальное сообщество ВКонтакте:
https://vk.com/temple_of_tales_music

Наш телеграм-канал:
https://t.me/temple_tales

Наш YouTube канал:
https://www.youtube.com/@temple-tales

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
Поддержать нас, а также получить доступ к различным материалам в нашем творчестве и другим бонусам можно через подписки:
VK Donut: https://vk.com/donut/temple_of_tales_translations
VK Donut: https://vk.com/donut/temple_of_tales_quiz
VK Donut: https://vk.com/donut/temple_of_tales_music
Boosty: https://boosty.to/temple-tales

Альтернативный способ поддержки:
Карта Сбербанка: 5469 9802 0654 4716
Карта ВТБ: 4272 2908 4659 1246

17