Celá hra se vejde do dvanácti souborů
Pokud se podíváte do instalačního adresáře Mafie, najdete tam dvanáct souborů pojmenovaných
A0.dta až ac.dta. V nich je doslova vše — každý výstřel, každá textura dlažby, každá nota z hudby Vladimíra Šimůnka i scripty všech 21 misí. Celá Lost Heaven je zabalená do těchto archivů.Fungují podobně jako ZIP soubory, ale s jedním háčkem: jsou zašifrované. Nestačí je jen rozbalit — bez správných klíčů dostanete jen změť nesmyslných dat. Samotná hra si klíče nese ukryté v
GAME.EXE a při spuštění archivy tiše „připojí" přes vlastní knihovnu rw_data.dll. Hráč nic nevidí, nic netuší — soubory prostě fungují, jako by ležely volně na disku.Co je v každém archivu?
Každý DTA soubor má na starost jiný typ dat. Takhle je to rozděleno:
| Soubor | Obsah |
|---|---|
A0.dta | Zvukové efekty — výstřely, kroky, motory, okolní hluk |
A1.dta | Mise — scripty, scény, logika všech 21 misí |
A2.dta | 3D modely — auta, postavy, rekvizity |
A3.dta | Animace postav I |
A4.dta | Animace postav II |
A5.dta | Rozdílová data — opravy a patche aplikované přes původní obsah |
A6.dta | Textury — povrchy, materiály, vizuální vzhled celého světa |
A7.dta | Záznamy a interní data |
A9.dta | Systémová data enginu |
aa.dta | Herní tabulky — statistiky, vlastnosti objektů, parametry |
ab.dta | Hudba — Citymusic, pozadí a hudba |
ac.dta | Animace postav III |
A6.dta s texturami a A1.dta s daty misí bývají zdaleka největší. Jen data misí zahrnují pohyb všech NPC, rozmístění aut, dialogy a stovky scriptových příkazů pro každou ze 21 misí.Šifrování: dva klíče a trocha magie s nulami
Každý DTA archiv má svůj vlastní pár šifrovacích klíčů — dvě 32-bitová čísla (tj. čísla velká až přes čtyři miliardy) ukrytá v
GAME.EXE. Bez nich jde obsah přečíst jen jako šum.Samotné šifrování je elegantně jednoduché. Hra prochází data po osmi bajtech najednou a na každý blok aplikuje dvě operace přímé z procesoru: NOT (překlopí každý bit — jedničky se stanou nulami a naopak) a XOR s klíčem (porovná bity a tam, kde se liší, dá jedničku). Geniální na tom je, že stejný postup data zašifruje i dešifruje — nejsou potřeba dva různé algoritmy.
Navíc jsou klíče před použitím ještě jednou XORovány s pevnými hodnotami (
0x34985762 a 0x39475694), takže i kdyby někdo klíče v EXE souboru našel, nevidí rovnou jejich „pravou" podobu.Níže je dešifrovací funkce přesně tak, jak ji MassaSnygga v roce 2002 zkopíroval z disassembleru
rw_data.dll. Funkce dostane buffer se zašifrovanými daty, jejich délku a oba klíče. Na výstupu jsou data čitelná:C / C++
void Decrypt(void* Buffer, DWORD BufferSize, DWORD Key1, DWORD Key2)
// DWORD = 32-bitové celé číslo (4 bajty), hodnota 0 až ~4,3 miliardy
{
__asm
{
mov ecx, BufferSize ; délka dat do registru ECX
push esi ; uložit registry (konvence volání)
mov eax, ecx
push edi
shr eax, 3 ; vydělit 8 → počet celých 8-bajtových bloků
lea esi, ds:0[eax*8] ; velikost zarovnaná na 8 bajtů
sub ecx, esi ; zbytek po zarovnání (0–7 bajtů)
mov edx, ecx ; uložit zbytek
mov ecx, Buffer ; ukazatel na data
test eax, eax
jz short loc_0_100046F5 ; žádné celé bloky → přejít na zbytek
mov edi, Key1 ; první klíč do EDI
push Key2 ; druhý klíč na zásobník
push ebx
push ebp
loc_0_100046B4: ; --- smyčka přes 8-bajtové bloky ---
mov ebx, [ecx+eax*8-8] ; načíst první 4 bajty bloku
mov ebp, [ecx+eax*8-4] ; načíst druhé 4 bajty bloku
dec eax
not ebx ; NOT: překlopit všechny bity
not ebp
mov [ecx+eax*8], ebx
mov ebx, [esp + 8h] ; druhý klíč ze zásobníku
mov [ecx+eax*8+4], ebp
mov ebp, [ecx+eax*8]
xor ebp, ebx ; XOR s druhým klíčem
mov ebx, [ecx+eax*8+4]
xor ebx, edi ; XOR s prvním klíčem
mov [ecx+eax*8], ebp
mov [ecx+eax*8+4], ebx
mov ebx, ebp
mov ebp, [ecx+eax*8+4]
not ebx ; druhý průchod NOT
not ebp
test eax, eax
mov [ecx+eax*8], ebx
mov [ecx+eax*8+4], ebp
jnz short loc_0_100046B4 ; opakovat dokud jsou bloky
pop ebp
pop ebx
loc_0_100046F5: ; --- zbytek (méně než 8 bajtů) ---
add ecx, esi
test edx, edx
jz short loc_0_1000471A ; žádný zbytek → konec
lea esi, Key2
lea eax, [ecx+edx]
sub esi, ecx
mov edi, edx
loc_0_10004706:
mov cl, [eax-1] ; bajt po bajtu
dec eax
not cl ; NOT na jeden bajt
mov [eax], cl
mov dl, [esi+eax]
xor dl, cl ; XOR s klíčem
dec edi
not dl ; druhý NOT
mov [eax], dl
jnz short loc_0_10004706
loc_0_1000471A:
pop edi
pop edi
pop esi
}
}Klíče ke všem dvanácti souborům MassaSnygga vyreverseoval trpělivým debugováním a analýzou
GAME.EXE. Jakmile byly klíče známé, mohly vzniknout první nástroje pro extrakci obsahu — a s nimi i základ celé moddovací komunity.Jak hra archivy čte — rw_data.dll
Mafia nevyřešila čtení DTA archivů přímo v
GAME.EXE, ale přesunula tu práci do samostatné knihovny rw_data.dll v instalačním adresáři. Tato DLL je vlastně minimalista čtecí vrstva — umí připojit archiv, otevřít soubor uvnitř, přečíst ho a zavřít:| Funkce | Co dělá |
|---|---|
dtaCreate() | „Připojí" DTA archiv a zpřístupní jeho obsah. Navzdory názvu nic nevytváří — spíš jde o „mount". |
dtaOpen() | Otevře konkrétní soubor uvnitř archivu a vrátí handle (číselný identifikátor) pro práci s ním. |
dtaRead() | Přečte požadovaný počet bajtů z otevřeného souboru — stejně jako běžné čtení ze souboru na disku. |
dtaClose() | Uzavře soubor otevřený přes dtaOpen(). Jako zavření okna po dočtení. |
dtaSetDtaFirstForce() | Přepne prioritu: DTA archiv má přednost před soubory volně na disku. Klíčová funkce pro moddování — viz níže. |
dtaSeek() | Přesune pozici čtení na jiné místo v souboru (jako přetočení u přehrávače). |
Zvláštní pozornost si zaslouží
dtaSetDtaFirstForce(). Ve výchozím stavu má čtení z disku přednost před archivem — hra se nejdřív podívá na disk, a teprve když tam soubor nenajde, sáhne do DTA. To znamená, že modder může jednoduše položit upravený soubor vedle GAME.EXE a hra ho automaticky načte místo originálu. Žádné přepisování archivů, žádné pájení — prostě zkopírovat soubor.Jenže v průběhu startu hra zavolá
dtaSetDtaFirstForce() a priorita se obrátí — od té chvíle DTA vyhrává nad diskem. Proto nástroj MafiaDataXtractor zvolil mazané řešení: v DLL přepsal tuto funkci tak, aby nedělala vůbec nic. Hra si myslí, že přepnutí provedla, ale ve skutečnosti zůstalo vše při starém — disk má pořád přednost, a moddeři mohli načítat soubory přímo.Takhle vypadá kód, který hra spouští po každém
dtaCreate() — připojí archiv a vzápětí nastaví dešifrovací klíče přes interní tabulku funkcí v DLL:C / C++
DWORD Result; // DWORD = 32-bitové číslo, zde slouží jako pointer (adresa v paměti)
if (Result = dtaCreate("a9.dta")) // připoj archiv; Result = adresa interní tabulky
{
__asm // inline assembler — přímé instrukce procesoru
{
mov eax, 06FEE6324h ; první klíč (pro A9.dta) do registru EAX
xor eax, 034985762h ; zamaskuj ho XOR operací (pevná hodnota pro všechny DTA)
push eax ; ulož připravený klíč na zásobník
mov eax, 0ACDA4783h ; druhý klíč (pro A9.dta) do EAX
xor eax, 039475694h ; zamaskuj druhým pevným XOR faktorem
push eax ; ulož druhý klíč na zásobník
mov ecx, Result ; do ECX dej pointer vrácený z dtaCreate()
mov eax, [ecx] ; přečti adresu tabulky funkcí z tohoto pointeru
call [eax + 0ch] ; zavolej čtvrtou funkci v tabulce (+0x0C = offset 12)
; → ta interně nastaví klíče pro dešifrování archivu
}
}Struktura souboru — co přesně hledáme v bajtech
Kdo chce s DTA pracovat bez
rw_data.dll — třeba napsat vlastní extraktor — musí znát fyzický formát souboru. Každý DTA začíná čtyřmi bajty s textem ISD0. Je to tzv. „magické číslo" — identifikátor formátu, který programu řekne: „toto je opravdový DTA archiv".Hned za ním leží malá hlavička (16 bajtů), zašifrovaná — nutno nejprve dešifrovat. Po dešifrování odhalí základní mapu archivu:
| Pozice | Typ | Hodnota |
|---|---|---|
| 0 | DWORD | Počet souborů uložených v archivu |
| 4 | DWORD | Kde v souboru začíná seznam obsahu (offset v bajtech) |
| 8 | DWORD | Jak dlouhý je seznam obsahu |
| 12 | DWORD | Neznámé (pravděpodobně interní příznak) |
Poznámka k typům: DWORD (Double Word) = 32-bitové celé číslo — 4 bajty, hodnota 0 až ~4,3 miliardy. UCHAR = 1 bajt bez znaménka (0–255). char[] = textový řetězec.
Z hlavičky se dostaneme k seznamu obsahu — sérii 28-bajtových záznamů, jeden za každý soubor v archivu. Každý záznam obsahuje zkrácený název (posledních 16 znaků) a odkaz na podrobnější informační blok. Zkrácený název slouží k rychlému porovnání — pokud odpovídá, teprve pak se čte celý blok.
Teprve informační blok souboru prozradí úplný název a adresu dat:
| Pozice | Typ | Hodnota |
|---|---|---|
| 0–15 | 4× DWORD | Interní identifikátor (neznámý účel, pravděpodobně hash) |
| 16 | DWORD | Velikost souboru v bajtech |
| 20 | DWORD | Neznámé |
| 24 | UCHAR | Délka názvu souboru (kolik znaků následuje) |
| 25–31 | char[7] | Neznámé (výplň nebo interní data) |
| 32+ | char[] | Název souboru — celá cesta, např. maps\freeride\city.bin |
Jakmile máme celý název, stačí ho předat do
dtaOpen() — nebo si podle offsetu v archivu soubor manuálně najít a přečíst. Takhle fungují všechny extraktory DTA archivů.Co se s extrahovanými soubory dá dělat?
Jakmile MassaSnygga v roce 2002 publikoval klíče a formát, ostatní vývojáři rychle napsali nástroje. Nejznámější byl MafiaDataXtractor — program, který z DTA archivů jedním kliknutím vytáhl veškerý obsah.
A co z toho vzešlo? Extrahované soubory otevřely dveře celé moddovací komunitě:
| Typ souboru | Co lze dělat |
|---|---|
Textury (.bmp) | Reskin aut, budov, postav — nové barvy, vzory, historické verze vozidel |
3D modely (.4ds) | Náhrada modelů aut nebo postav za vlastní tvorbu |
Scripty misí (scene2.bin, cache.bin) | Úpravy misí, nové mise, změny chování NPC |
Zvuky (.wav) | Nový dabing, hudební mody, změna zvuků zbraní |
| Herní tabulky | Vlastnosti aut, zbraní, fyziky — výkonové mody |
Právě díky těmto souborům vznikly desítky modů — od přeskinovaných historických aut přes české dabingové mody až po celé nové mise. A vše začalo tím, že jeden programátor trpělivě prozkoumával binární data a vysledoval, kde jsou ukryté klíče.
Zdroj
Technické informace vycházejí z dokumentu „Accessing Mafias DTA files" od MassaSnygga (kamalook.de), původně publikovaného v roce 2002. Dokument vznikl zpětnou analýzou (reverse engineering) — rozebrání hotového programu a postupné pochopení toho, jak funguje. Část detailů (pole označená jako „neznámé") nebyla nikdy plně objasněna, jak autor sám přiznával.
Komentáře 0
Zatím žádné komentáře. Buď první!
Přidat komentář