У статті, як приклад, описується процес розпакування архіву формату DAT з гри Imperium Galactica II
Припустимо, що вам захотілося добути графіком з якоїсь іграшки. Припустимо також, що ваш вибір припав на Imperium Galactica II. Ті ж правила підійдуть практично до будь-якій грі.
Різні виробники по різному і ресурси ховають. В одному випадку можна знайти текстури, розміщені по окремих файлів, в іншому їх запаковують в архіви, точніше - в псевдоархіви, тому що в них досить рідко застосовуються алгорітни стиснення і в повному сенсі цього слова архівами вони не є. Значить, шукаємо файли, які виділяються своїм розміром на тлі інших. Втім, архіви можуть бути і порівняно невеликими, як в нашому випадку з IG2. Тут в кожному архіві міститься іноді по одному, а іноді і по сотні файлів. Ось цей випадок ми і розглянемо.
При розшифровці будь-якого формату ймовірність успішного результату різко зростає, якщо розбирати одночасно кілька зразків цього формату. У нашому випадку використовується два архіву: sounds_colony_speech_self-destruct.dat і textures_colony_lens.dat.
Тепер звернемося до другого експерементальний архіву і до Малюнку 3. Як ми вже зрозуміли, імовірно зміщення FAT можна прочитати в останніх чотирьох байтах архіву. Щоб остаточно підтвердити це припущення, подивимося на останні чотири байти другого архіву (Малюнок 3). Там, за зміщення $ 5BB2 читаємо значення $ 106. Віднімаємо це значення із загального розміру архіву і отримуємо $ 5AB0. Йдемо цим зміщення і куди потрапляємо? Так, на початок FAT другого архіву. Значить, гіпотеза підтвердилася.
Залишилося тільки розглянути структуру записи про одне з файлів. Ось що містяться в запису поля (в дужках вказана довжина поля):
- Файл (довжина довільна).
- Зсув в архіві до нього (4 байта).
- Мотлох (4 байта).
- Розмір даних (4 байта).
- Реальний розмір файлу (якщо використаний алгоритм стиснення GZip) (4 байта).
- Мотлох (4 байта).
Довжина поля імені може бути в усіх записах фіксованого або довільної. У другому випадку або перед полем вказується довжина імені, або (як у нашому випадку) ім'я читається до першого нульового символу. Решта поля відгадуються експерементально. Розмір першого файлу = Зсув другого-зміщення першого. Саме зміщення можна відгадати. Це особливо легко, в разі якщо всі файли мають один і той-же тип, тобто мають загальний ідентифікатор в заголовку. Наприклад, у другому архіві розглянемо запис першого запису (зміщення $ 5AB0), і про другий (зміщення $ 5ACE). Після імені першого файлу, пропустивши один нульовий символ, читаємо $ 00 00 00 00. Будемо вважати, що це і є зміщення до першого файлу. Йдемо цим зміщення, тобто в початок архіву і запам'ятовуємо хоча б два перших байта - $ 78 9C. Тепер читаємо ті ж чотири символи - $ FF 48 00 00. Йдемо з цього зміщення ($ 48FF) і бачимо ті ж два байта. Т.ч. збігаються ідентифікатори обох файлів, отже поле, що містить зсув файлу визначено вірно. Таким же методом наукового тику визначаються і інші поля.
Наостанок хотілося б приділити увагу ще дещо чого. Іноді файли в псевдоархівах стиснуті абсолютно справжнім архіватором GZip. Цей метод використаний і в IG2, і в HOMM III. Ідентифікатором формату GZip є послідовність $ 1F 8B 08 00 00 00 00 00 00 00. Однак в іграх цей ідентифікатор з невідомої мені причини замінюють на $ 78 9C. Що б при розпакуванні псевдоархіва сформувати повноцінний архів GZip з того файлу, що там зберігається, наприклад, правильно витягти з другого архіву файл flare.bmp (Малюнок 3), потрібно:
- Створити файл з ім'ям Flare.bmp.
- Записати туди справжній ідентифікатор GZip, тобто $ 1F 8B 08 00 00 00 00 00 00 00.
- Копіювати в створений файл дані Flare.bmp з псевдоархіва. починаючи з третього байта (щоб відсікти помилковий ідентифікатор GZip).
- В кінці Flare.bmp вписати Реальний розмір файлу. Він включений в запис FAT.
Маневр з «хибним заголовком» GZip справедливий в тому, і тільки в тому випадку, коли ви використовуєте бібліотеку GZipLib або інші бібліотеки того ж класу. При використанні ZLib заголовок редагувати не треба.