фан-сайт игры Mafia: the City of Lost Heaven
   radio             


Оглавление

Новости
Немного истории
Секреты и приколы
Видеогалерея
Моддинг Мафии
Расширенная версия Mafia
Пишем скрипты для Mafia
Как делать ADDin`ы
Доступ к DTA файлам
Чемпионат по игре
The Alive mod v.16
Пришелец-алхимик
Телохранители
Пушка броневика
Продавцы машин
Грязные гонки
Голем (памятник)
Супер-телохранители
Миссия в порту
Террорист-смертник
Ресторан Сальери
Сельская местность
Alive Mod Evolution 18.0
Секреты Аливе мода
Скачать Alive mod
Юморная страничка
Наш музей Мафии
Альфонсо Капоне
Бонни и Клайд
Джон Диллинджер
Машины той эпохи
Оружие той эпохи
Музыка из Мафии
Если хотите помочь
Благодарности
Кладовочка



Доступ к DTA файлам игры Мафия



1. Вступление.
Так как, я часто получаю письма от людей, которые просят дать им информацию о DTA-файлах, потому, что они хотели бы разработать новый инструмент для работы с DTA-файлами (например, часто спрашиваемый DTA-упаковщик), то я решил написать этот документ, чтобы обеспечить желающих всей информацией, которую мне удалось собрать о DTA-файлах.

Данный документ полностью описывает методы, которые MafiaDataXtractor использует для извлечения содержимого из DTA-файлов.

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

Я рассчитываю на то, что вы знаете C и немного x86-Ассемблер, иначе вы не все поймете. Пожалуйста, не докучайте мне с вопросами относительно C или Ассемблера.

А теперь давайте перейдем к потехе…

2. Ключи шифрования.
Как вы могли догадаться, просматривая DTA-файлы с помощью hex-редактора, эти файлы зашифрованы. Фактически некоторые из них к тому же сжаты, но я совершенно не имел дела с методами сжатия. Чтобы читать из них вы должны знать два 32-битных ключа, которые различны для (почти) каждого DTA-файла. К счастью, я смог найти их довольно просто во время просмотра дизассемблированного GAME.EXE, так как они там хранились без всякой (серьезной) защиты. Эти ключи, похоже, идентичны для любой интернациональной версии игры, так как все они используют одинаковый файл GAME.EXE, кроме немецкой версии, но ключи все же идентичны и для этой версии.
(Действительно, файлы из немецкой версии игры не взаимозаменяемы с файлами из других версий. Дело в том, что игра не могла выйти на немецкий рынок при том уровне жестокости, который в ней присутствует. Поэтому игра была существенно урезана для немецкого рынка, например, была полностью убрана кровь и т.п. Соответственно, многие файлы собраны иначе и не совместимы с файлами других международных версий игры. Прим. MikeMouse.)

Для вашего сведения я привожу ключи здесь: см. фото.
Обратите внимание, что A8.dta был представлен совсем недавно, вместе с патчем 1.1, и не имелся в версии игры 1.0.

3. Использование библиотеки rw_data.dll.
Простейший метод извлечения содержимого из DTA-файлов, который позволит избежать проблем, это использование собственной DLL (Dynamic-Link Library — динамически подключаемая библиотека. Прим. MikeMouse) игры Mafia. Это файл «rw_data.dll», вы найдете его в папке «Mafia».

Так как игра Mafia использует этот файл, то и мы может извлекать файлы тем же самым способом, каким Mafia делает это. И мы можем не иметь дела с методами шифрования и сжатия, которые использует Mafia. “Круто!” – можете вы завопить сейчас, но, как и всегда, жизнь не так проста. Оказалось, что взломать шифрование недостаточно, чтобы достичь безукоризненных результатов. Но я забегаю вперед.

Прежде всего, давайте взглянем на все функции, которые выполняет «rw_data.dll» и каким образом они работают:

DWORD dtaBin2Text(DWORD unknown1, DWORD unknown2)
Описание:
Я не имел дела с этой функцией, так как, похоже, что она не используется Мафией вообще.
Параметры:
Неизвестны.
Возвращает:
Неизвестно.

void dtaClose(DWORD FileHandle)
Описание:
Закрывает файл, который был открыт внутри DTA.
Параметры:
FileHandle - дескриптор файла, который был открыт с помощью dtaOpen.
Возвращает:
Ничего.

DWORD dtaCreate(char* FileName)
Описание:
Эта функция НЕ создает файла каким-либо способом, хотя ее имя наводит на такую мысль. Фактически, это способ монтирования DTA-файла таким образом, чтобы содержащиеся в нем файлы стали доступны с помощью последующих вызовов dtaOpen.
Параметры:
FileName – имя DTA-файла, который монтируется.
Возвращает:
NULL, когда вызов функции был неудачным.
Ненулевой указатель на объект (благодарю Jonathan Wilson, который указал мне на это).
Примечания:
Теперь нечто особенное о числе, которое возвращает вызов этой функции. Сначала я думал, что возвращаемая величина не имеет значения, но, как оказалось, Mafia использует эту величину, чтобы установить ключи шифрования DTA-файлов. Фактически, это указатель на экземпляр класса внутри «rw_data.dll». Так как Mafia была написана на C++, то первое двойное слово класса указывает на его таблицу виртуальных функций. Интересующая нас функция четвертая в таблице (адрес таблицы + 0x0c). Она должна вызываться с двумя корректными ключами, помещенными в стек, которые замаскированы соответствующими величинами (Мне кажется, что программистам понятен общепринятый термин “маска”. Речь идет об исключающем ИЛИ. А вся эта возня со стеком и пр. нужна для того, чтобы соответствовать соглашению Visual C++ для вызовов функций. В частности, для передачи параметров вызываемой функции. Прим. MikeMouse). Более того, ECX-регистр должен содержать возвращаемое значение для соответствия C++ конвенция вызовов объектов.

Обе маски всегда одинаковые: первый ключ шифрования имеет маску 0x0x34985762, а второй ключ шифрования имеет маску 0x39475694.

Следующий код является примером того, как смонтировать “a9.dta” и установить для него ключи шифрования: см. фото.
Возможно, что вы захотите проверить другие функции из этой таблицы функций, вполне вероятно, что они тоже делают нечто интересное.

DWORD dtaDelete(DWORD unknown1)
Описание:
Я не имел дела с этой функцией.
Параметр:
Неизвестен.
Возвращает:
Неизвестно.

DWORD dtaDumpMemoryLeaks(DWORD unknown1)
Описание:
Я не имел дела с этой функцией, так как, похоже, что она не используется Мафией вообще.
Параметры:
Неизвестны.
Возвращает:
Неизвестно.

DWORD dtaGetTime(DWORD unknown1, DWORD unknown2, DWORD unknown3)
Описание:
Я не имел дела с этой функцией.
Параметры:
Неизвестны.
Возвращает:
Неизвестно.

DWORD dtaOpen(char* FileName, DWORD unknown1)
Описание:
Эта функция открывает файл содержащийся внутри смонтированных DTA-файлов. ДЛЛка ищет по всем DTA-файлам, которые были непосредственно перед этим смонтированы с помощью функции dtaCreate().
Параметры:
FileName – имя файла, который должен быть открыт.
unknown1 – этот параметр, кажется, всегда равняется 0.
Возвращает:
0xffffffff если вызов не имел успеха, закончился неудачей.
Если вызов был успешным, то возвращает дескриптор файла, который используется для дальнейшей работы с этим файлом.

DWORD dtaOpenWrite(DWORD unknown1, DWORD unknown2)
Описание:
Я не имел дела с этой функцией.
Параметры:
Неизвестны.
Возвращает:
Неизвестно.

DWORD dtaRead(DWORD FileHandle, char* Buffer, DWORD ByteCount)
Описание:
Эта Функция читает из файла, открытого с помощью dtaOpen(). Чтение начинается с текущей позиции файла.
Параметры:
FileHandle – дескриптор файла, который нужно читать.
Buffer – указатель на буфер, который будет накапливать прочтенные данные.
Убедитесь, что буфер достаточно велик, чтобы вместить все данные, которые вы запросили.
ByteCount – количество байт, которые требуется прочитать.
Возвращает:
Количество байт, которые были реально считаны.
Это число может быть меньше, чем запрошено в ByteCount. Например, если будет достигнут конец файла или случится ошибка.

DWORD dtaSeek(DWORD FileHandle, DWORD unknown1, DWORD unknown2)
Описание:
Я не пользовался этой функцией. Но, разгадать ее должно быть просто.
Я подозреваю, что параметры похожи, или даже идентичны, параметрам функции fseek().
Параметры:
Неизвестны.
Возвращает:
Неизвестно.

void dtaSetDtaFirstForce()
Описание:
Эта очень интересная функция! Она управляет тем, из какого источника загружаются файлы.
«rw_data.dll» имеет два режима работы:
1. По умолчанию читать файлы с жесткого диска, а в случае неудачи читать из DTA.
2. По умолчанию читать из DTA, а в случае неудачи читать с жесткого диска.
До вызова этой функции используется первый режим работы. После вызова функции «rw_data.dll» переключается на второй режим работы. Эту функцию патчит MafiaDataXtractor, превращая ее фиктивную, пустую функцию. Таким образом режим работы №2 никогда не включается и по умолчанию читаются извлеченные файлы.
Параметры:
Нет.
Возвращает:
Ничего.

DWORD dtaWrite(DWORD unknown1, DWORD unknown2, DWORDN unknown3)
Описание:
Я не имел дела с этой функцией.
Параметры:
Неизвестны.
Возвращает:
Неизвестно.

Уф-ффф! Вот как-то так… Если вы выясните что-либо относительно неизвестных функций, пожалуйста, дайте мне знать, чтобы я смог обновить этот документ.

Итак, как же вы на самом деле можете читать файлы, используя эти функции?
Прежде всего, используйте НЕ патченую версию «rw_data.dll», или используйте ДЛЛку из чистой инсталляции, или используйте «rw_data.bak», если был установлен MafiaDataXtractor. Если вы используете патченую версию, то вы, в конечном счете, будете читать файлы, которые уже были извлечены (и может быть позже изменены), а это совсем не то, чего мы хотим.

1. Вызовите функцию dtaSetDtaFirstForce(), чтобы обеспечить чтение файлов из DTA.
2. Смонтируйте DTA-файлы с помощью функции dtaCreate() и установите ключи шифрования.
3. Откройте файл с помощью функции dtaOpen().
4. Прочитайте содержимое, используя функцию dtaRead().
5. Закройте файл функцией dtaClose().

Если вы пытаетесь импортировать функции из «rw_data.dll», использовать LoadLibrary() и GetProcAddress(), то имейте в виду, пожалуйста, что имена функций декорированы. Перед именем функции ставится черточка (символ подчеркивания. Прим. MikeMouse), а после имени ставится знак ‘@’ (в обиходе именуемый «собакой». Прим. MikeMouse), за которым следует число байт, переданных функции в качестве параметров. Таким образом, экспортируемое имя для функции dtaRead() будет таким _dataRead@12.

Вот и всё! Превосходно, не правда ли? Ладно, одной маленькой штучки недостает. Как выяснить какие файлы находятся внутри этих DTA-файлов? ДЛЛка очевидно не содержит функций для поиска файлов. Я буду разбираться с этой проблемой в следующей главе.

4. Расшифровка таблицы содержимого DTA.
Теперь мы добрались до плохо проработанного и трудного материала – самостоятельного открывания DTA-файлов!

Прежде я объяснял вам структуру DTA-файлов, сейчас я покажу, как расшифровать данные внутри них, так как почти все нуждается в расшифровке. Я не изучал функцию расшифровки слишком пристально, но, благодаря Roger H. J?rg, превратил свой ассемблерный хлам в миленькую C функцию: см. фото.

Как вы видите, пользоваться этой функцией довольно легко – передаете указатель на буфер с зашифрованными данными, длину буфера и оба ключа шифрования, которые вы можете найти в таблице ключей, в начале этого документа. После возврата данные будут расшифрованы, и вы можете продолжать работу. ПРОСТО!

Итак, теперь к структуре DTA-файла.

Четыре первые байта каждого DTA должны содержать “ISD0”. Это использовано для определения корректного DTA-файла. За этим магическим значением следует небольшой заголовок, который должен быть расшифрован с помощью функции Decrypt(): см. фото.

Теперь мы имеем всю информацию, которая нам нужна, чтобы прочитать таблицу содержимого. После расшифровки таблица содержимого станет массивом таблиц, которые выглядит так (т.е. каждому файлу в DTA-архиве будет соответствовать отдельная табличка, сколько файлов, столько и таких таблиц. Прим. MikeMouse): см. фото. К несчастью, здесь не содержится информации, которая нам нужна. Полное имя файла не является частью этой структуры. Все, что имеется здесь, это подсказка, которая содержит 16 последних символов от имени файла. Моя догадка, что Mafia использует подсказку, чтобы быстрее отвергать записи при поиске конкретного файла. Более того, я подозреваю, что одна из неизвестных записей должна быть хэш-значением реального имени файла. Поскольку мы еще не нашли то, что ищем, нам нужно копать глубже. Поэтому, мы читаем информационный заголовок файла, смещение до которого мы только что получили. Он должен быть еще раз расшифрован с помощью функции Decrypt().

Информационный заголовок файла выглядит так: см. фото. Теперь это в точности то, что мы хотели знать! Сейчас мы знаем точное имя файла, которое может быть передано функции dtaOpen(). Имея эту информацию мы можем извлечь ВСЕ файлы из DTA-архивов.

5. Вот теперь действительно все!
Это все, что я знаю. Теперь вы можете копать глубже, если хотите.

И, пожалуйста, дайте мне знать, если выясните что-нибудь интересное, чтобы я смог обновить этот документ.

Если у вас есть какие-то проблемы с пониманием написанного, то сделайте следующее:
1. Прочитайте документ ПОЛНОСТЬЮ!
2. Используйте свой мозг!
3. Используйте свой мозг еще больше!
4. Напишите мне: massasnygga@kamalook.de
.

 

Автор статьи MassaSnygga,
перевод MikeMouse © 2003-2012



Последние новости

2.05.2017
50 оттенков Alive Bars Mod
29.04.2017
Gangsters Mod
12.09.2015
Functional Black Metal
8.04.2015
О форсированных машинах
1.04.2015
История одного сицилийца
11.02.2015
Мод для изучения ПДД на улицах Лост Хэвэна
10.02.2015
Alive Continuing Mod - новый мод из семейства Alive



Это интересно

HotLog

Все права защищены © www.webgamer.hhos.ru 2003- © MikeMouse 2003- ©

Mail.Ru