Problem z kopiami.

Wszelkie kwestie techniczne.
Regulamin forum
1. W miarę możliwości prosimy o załączanie plików przez nasze forum, nie na zewnętrznych serwerach. Pliki nie znikną wtedy po upływie pewnego czasu. 2. Jeśli chcecie uzyskać pomoc przy rozpracowaniu plików (np. z tekstem, czcionką) załączajcie je do postów - nie każdy przecież posiada tłumaczoną przez Was grę.
ffgriever
Posty: 488
Rejestracja: 17 paź 2008, o 15:29

Re: Problem z kopiami.

Postautor: ffgriever » 23 lis 2008, o 23:15

Hmmm... zaglądnąłem na szybko do Suikoden II. Sprawa wygląda tak:

Gra została wykonana w systemie podmodułów. Moduły te, to coś w rodzaju bibliotek, które pojawiają się tymczasowo w pamięci, a gdy nie sa więcej potrzebne, są zastępowane przez kolejne. Moduły te zawierają zarówno kod, który ma zostać wykonany, jak i wszelkie dane niezbędne do wykonania kodu (łącznie z tekstem i bitmapami, choć czasami są one wczytywane także z zewnętrznych plików, które modułami nie są). Moduły są linkowane statycznie do głównego programu, więc mogą korzystać z jego funkcji. Na początku każdego modułu znajduje się entry point danego modułu i inne niezbędne do działania dane. Problem polega na tym, że niektóre z tych modułów są dodatkowo kompresowane. Wygląda to tak, że główny entry point modułu zawiera prosty kod ustawiający kilka parametrów, a dalej wywoływany jest z modułu kod rozpakowujący (auto unpacker, z tym, że kod rozpakowujący znajduje się w głównym programie). Na samym początku rozpakowanych danych znajduje się wtedy zawsze entry point rzeczywistego, rozpakowanego już modułu.

Metoda kompresji to jakaś metoda słownikowa. Ramka jest chyba 1024B, z tym, że nie jest to chyba typowy lz*, bo wydaje mi się, że są trzy stany do opisu zamiast standardowych dwóch (skompresowany ciąg i nieskompresowany) - w zależności, czy ctrl jest w przedziale <0x00, 0x7f>, <0x80, 0xbf> lub <0xc0, 0xff>. Jak będę miał chwilkę, to sprawdzę dokładniej algorytm kompresji i napisze dekompresor i kompresor. W plikach skompresowanych nie można sobie zbytnio poszaleć, z oczywistych względów (chyba, że udałoby się zdekompilować a potem skompilować ponownie. Na szczęście w fontach cały kod jest przed skompresowanymi danymi, więc tutaj można wydłużyć bez problemu). Fonty zauważyłem trzy, ale może być ich więcej. Na razie mogę zmusić sam program, żeby wypakował dowolną część za mnie, ale to niezbyt poręczne... do tego i tak potrzeba kompresora ;) . Tak jak pisałem, nie wszystkie są kompresowane, ale na oko zdecydowana większość.

To tyle na dziś. Postaram się w weekend przysiąść do tego i coś wymodzić. Chyba, że komuś po tych wskazówkach uda się coś konkretnego do tego czasu spłodzić.

ffgriever
Posty: 488
Rejestracja: 17 paź 2008, o 15:29

Re: Problem z kopiami.

Postautor: ffgriever » 30 lis 2008, o 17:20

Tak jak obiecałem. Dekompresor do suikoden2. Kompresor postaram się napisać w tygodniu, jak czasu nie braknie ;) . Wybaczcie, że niektóre zmienne ponazywane nieco z kosmosu, ale tym razem nie pracowałem bezpośrednio na skompresowanych plikach, tylko łatwiej było mi znaleźć część kodu w mips-asm odpowiedzialną za dekompresję i przełożyć ją na c++. Kod działa w 100%, tylko w kilku miejscach nie od razu wpadłem na przeznaczenie danej zmiennej/rejestru i potem się okazywało, że nazwa nie pasuje do funkcji ;). Tak samo jest kilka sprawdzeń nieco bez sensu... Jeszcze tego nie poprawiałem. Ale, skoro działa (cóż, wszystkie udziwnienia są z oryginału, więc musi działać) ... to co za różnica ;] .

Ponieważ w większości wypadków nie są to typowe archiwa, tylko pliki wykonywalne, do tego same skompresowane dane zaczynają się w różnych miejscach (czasami porwadzą do nich pointery - do off w pamięci a nie w pliku - ale nie zawsze). Zdaje się jednak, że kod dekompresujący jest zawsze taki sam, więc wystarczy pewnie pominąć pierwszą tablicę a potem szukać standardowych części kodu, w których poprzez la ładowane są dane adresy. W jednym pliku jest zazwyczaj kilka do kilkunastu skompresowanych sekcji. Same bitmapy najczęściej kompresowane są w częściach po 8kB (czy po 128x128x4bit, jak zwał, tak zwał). Taki egzek może zawierać nie tylko dane jako takie, ale także dalsze egzeki (też skompresowane). Tu już do człowieka należy stwiedzenie co jest czym (chyba, że uda mi się coś znaleźć... jakąś tablicę z opisami ;) ).

Anyway, tutaj kod funkcji dekompresującej:

Kod: Zaznacz cały

//size_pac - długość skompresowanego pliku //packed - wskaźnik do bufora ze spakowanymi danymi //unpacked - wskaźnik do bufora z rozpakowanymi danymi //stub dekompresora przetłumaczony z asm z oryginalnego pliku SLUS_009.58 na c++ //funkcja dekompresująca znajduje się w pamięci pod 0x80075F58 void decompress(u32 size_pac, u8* packed, u8* unpacked) { u8 frame[1024]; u8 ctrl; u32 tempCtrl; u8* end = packed + size_pac; u32 frameOffset = 0x3de; u8* currFrame = &frame[frameOffset]; u32 remain; u32* tempFrame = (u32*)frame; while ((u32)tempFrame < (u32)currFrame) { *tempFrame = 0; tempFrame++; } while (1) { ctrl = *packed; packed++; if (packed >= end) { return; } tempCtrl = ctrl | 0xff00; do { if (tempCtrl & 1) { s8 tempCtrl2 = *packed; packed++; s32 cnt; if ((u8)tempCtrl2 < 0x80) { remain = *packed; packed++; u8 temOff = (tempCtrl2 & 3); tempCtrl2 = (tempCtrl2 >> 2) + 2; remain |= (temOff << 8); cnt = 0; if (tempCtrl2 >= 0) { do { currFrame = &frame[frameOffset]; frameOffset++; frameOffset &= 0x3ff; u8* tempFrame = &frame[(remain + cnt) & 0x3ff]; ctrl = *tempFrame; *unpacked = ctrl; unpacked++; *currFrame = ctrl; cnt++; } while (cnt <= tempCtrl2); } } else if ((u8)tempCtrl2 < 0xc0) { remain = tempCtrl2 & 0xF; tempCtrl2 = ((tempCtrl2 & 0x30) >> 4) + 1; cnt = 0; if (tempCtrl2 >= 0) { do { u32 tempFrameOffset = frameOffset - remain; currFrame = &frame[frameOffset]; frameOffset++; frameOffset &= 0x3ff; tempFrameOffset &= 0x3ff; u8* tempFrame = &frame[tempFrameOffset]; ctrl = *tempFrame; *unpacked = ctrl; unpacked++; *currFrame = ctrl; cnt++; } while (cnt <= tempCtrl2); } } else { tempCtrl2 = (tempCtrl2 & 0x3f)+7; cnt = 0; if (tempCtrl2 >= 0) { do { ctrl = *packed; packed++; currFrame = &frame[frameOffset]; *unpacked = ctrl; unpacked++; *currFrame = ctrl; frameOffset++; if (frameOffset >= 0x400) { frameOffset = 0; } cnt++; } while (cnt <= tempCtrl2); } } } else { ctrl = *packed; packed++; if (packed >= end) { if (packed == end) { *unpacked = ctrl; } return; } *unpacked = ctrl; currFrame = &frame[frameOffset]; *currFrame = ctrl; frameOffset++; unpacked++; if (frameOffset >= 0x400) { frameOffset = 0; } } tempCtrl >>= 1; } while (tempCtrl & 0x100); } }
Np. W pliku BOOTDAT.BIN w 270_BOOT pierwsza skompresowana sekcja zaczyna się na 0xF30 (jest tutaj długość skompresowanego pliku), same skompresowane dane zaczynają się na 0xf35 (jest to animacja poruszającej się postaci). W pliku KNMLOGO.BIN pierwsza sekcja zaczyna się na 0x668, dane na 0x66d i jest to skompresowany plik wykonywalny. W tym samym pliku np. na 0x61c8 (długość: 0x402) zaczyna się sekcja, jej dane są na 0x61cd i jest to trzecia część loga konami. itd, itp.

BTW. Wie ktoś jak nazywa się ten algorytm kompresji danych? Słownikowy, tak jak mówiłem tydzień temu, słownik ma 1024B i jest osobno a nie stanowi ramki przesuwającej się po zdekompresowanych danych. Są dwa możliwe stany dla danych skompresowanych i dwa dla nieskompresowanych. Dekompresor napisałem, ale mam problemy z zakwalifikowaniem tego algorytmu ;) . Nigdy takiego nie widziałem.

PS. Jak będzie chwila, to postaram się wziąć za dialogi i jakiś edytor napisać też (ale czcionkę warto by wcześniej zrobić ;) ).

ffgriever
Posty: 488
Rejestracja: 17 paź 2008, o 15:29

Re: Problem z kopiami.

Postautor: ffgriever » 30 lis 2008, o 22:25

Na prośbę KG zamieszczam skompilowaną wersję (prosty cmd).

Przykłady:

bitmapa z suikoden i "press start" (pierwsza część):

Kod: Zaznacz cały

sui2dec.exe -in=BOOT.BIN -out=blah.bin -off=0x8d68
pierwszy font (duży, same wielkie litery):

Kod: Zaznacz cały

sui2dec.exe -in=BOOT.BIN -out=blah.bin -off=0xb07c
Mniejszy napis suikoden II:

Kod: Zaznacz cały

sui2dec.exe -in=BOOT.BIN -out=blah.bin -off=0x12be4
Ale, mam coś, co was pewnie ucieszy. Spora część jest kompresowana, ale akurat główny font kompresowany nie jest. Zestaw z głównym fontem zaczyna się w BOOT.BIN na 0x32310. Jest to zestaw bitmap 4bit. Jest dużo literek z różnych języków, więc problemów z zastąpieniem nie będzie... Ale kompresor przyda się i tak na zmianę napisu "Press Start" ;) . Jestem ciekaw tego, do czego w tej grze wykorzystuje się trzy pozostałe fonty (które są z kolei skompresowane). No, ale przynajmniej dekompresor mamy ;) .
Załączniki
sui2dec.rar
(29.84 KiB) Pobrany 158 razy


Wróć do „Technikalia”



Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 0 gości