Spośród tysięcy różnych plików w archiwum GRUNTZ.REZ dwa są w pewnym sensie wyjątkowe i niepowtarzalne na swój sposób. Są to mianowicie pliki GAME\ATTRIBUTEZ.TXT oraz STATEZ\CREDITZ\PALETTEZ\CHEATZ.TXT. W sumie w archiwum są cztery pliki z rozszerzeniem *.TXT. Oprócz tych dwóch wymienionych wcześniej, są jeszcze pliki GAME\VERSION\VERSION.TXT (nie wykorzystywany przez samą grę, zawierający jedynie napis “1.00“) i STATEZ\CREDITZ\CREDITZ.TXT (napisy końcowe wyświetlane po zakończeniu gry z zabawnymi gagami na końcu). Ale o ile te dwa pliki z łatwością można rozczytać za pomocą zwykłego notatnika, o tyle na plikach ATTRIBUTEZ.TXT oraz CHEATZ.TXT można sobie połamać zęby – jak otworzy się je w notatniku, pojawiają się bowiem … same krzaki. Jeżeli ktoś chce je mieć do wglądu, można je pobrać tutaj:

Chwila moment, przecież są to pliki binarne! Kiedy pierwszy raz zobaczyłem te pliki wiele lat temu, poczułem momentalne rozgoryczenie tym faktem. Byłem bowiem wówczas przekonany o tym, że nigdy nie poznam zawartości tych plików. Co jak co, ale plik CHEATZ.TXT może wywołać ślinotok u co niektórych ze względu chociażby na samą nazwę. I co on robi w folderze PALLETEZ?

W tym poście postaram się wyjaśnić, czym tak naprawdę jest plik ATTRIBUTEZ.TXT i czemu służy. W kolejnym poście natomiast zajmę się plikiem CHEATZ.TXT.


W związku z tym, że plik ATTRIBUTEZ.TXT jest z natury plikiem binarnym, to na pierwszy ogień idzie oczywiście edytor HEX, żeby doszukać się jakiejś struktury w pliku. Niestety tutaj jest o nią naprawdę ciężko – cały plik wygląda tak, jakby został wypluty z generatora liczb pseudolosowych. Widać jednak, że na początku pliku powtarza się parę razy ciąg ośmiu bajtów: 71 F2 D4 36 B7 5B D9 E3:

To, że dane wyglądają w sposób losowy, może sugerować, że plik zawiera jakieś przetworzone dane – najczęściej w wyniku jakiegoś algorytmu kompresji albo szyfrowania. Powtarzający się ciąg bajtów może jednak sugerować, że plik został zaszyfrowany w trybie ECB (Electronic Codebook). Jest to tryb szyfrowania, w którym takie same ciągi znaków są szyfrowane w identyczny sposób, co widoczne jest w zaszyfrowanej wiadomości w postaci pewnych wzorców. Pozostawia to jednak dwa zasadnicze pytania: jaki algorytm szyfrowania został użyty i jakie klucze są potrzebne to uzyskania jawnego tekstu?

Okazuje się, że jest to algorytm szyfrowania symetrycznego Blowfish, a użyty klucz to “1212“. Niestety to nie ja do tego doszedłem. Sam spóźniłem się na imprezę, a tematem zainteresowałem się dopiero po fakcie. Wszystko się zaczęło od użytkownika Friedslick6, który na forum XeNTaX stworzył temat, w którym poprosił o pomoc w deszyfrowaniu obu plików: ATTRIBUTEZ.TXT oraz CHEATZ.TXT. Po prawie roku oczekiwania na odpowiedź, zgłosił się użytkownik dniel888, który podał nazwę algorytmu, klucz oraz skrypt do programu QuickBMS, za pomocą którego można odszyfrować plik ATTRIBUTEZ.TXT. Klucz natomiast wyodrębnił poprzez analizę pliku wykonywalnego (sam z ciekawości później spróbowałem wyodrębnić ten klucz za pomocą programu IDA – i rzeczywiście, jest to do zrobienia. Ale łatwo mi mówić po fakcie, jak wiedziałem, czego szukać, nie? :P). O pliku CHEATZ.TXT niestety nic nie powiedział, ale do tego jeszcze wrócę. Ostatecznie Friedslick6 o wszystkim poinformował społeczność GooRoo’s Gruntz Forum w tym temacie.

Wiemy więc, jak plik odszyfrować. Po użyciu algorytmu Blowfish z kluczem “1212” ukazuje się nam następujący tekst:

Widzimy teraz, że powtarzający się blok ośmiu bajtów, o którym wspominałem na samym początku, to tak naprawdę osiem znaków gwiazdki (“********“), składających się na początkowy komentarz w pliku.

Jeżeli ktoś zawartość tego pliku widzi po raz pierwszy, to powiedzmy sobie szczerze – może dostać czkawki z zachwytu. Plik zawiera setki parametrów, które kontrolują praktycznie każdy aspekt gry. W istocie jest to więc nic innego, jak plik konfiguracyjny. Dzięki niemu można na przykład:

  • zmienić prędkość poruszania się poszczególnych Gruntów (co z pewnością zepsułoby ponad 75% wszystkich dotychczasowych poziomów)
  • zmienić kolor teleporterów (jeżeli wierzyć komentarzom w pliku, jest aż 7 różnych kolorów do wyboru)
  • zmienić zasięg oddziaływania wszystkich narzędzi, nie tylko tych dalekiego zasięgu – czyli można sprawić, że np. Grunt z mieczem będzie mógł zaatakować bezpośrednio innego Grunta na drugim końcu mapy, a Grunt ze zbrojnymi rękawicami będzie mógł niszczyć kamienie dowolnie daleko się od niego znajdujące
  • zmienić szczegóły odnośnie oddziaływania zaklęć (jak chociażby czas zamrożenia, czy też prędkość wytworzonych kul)
  • zmienić prawdopodobieństwo losowego wytwarzania poszczególnych narzędzi, zabawek i cegieł podczas rozgrywki wieloosobowej
  • … i wiele, wiele innych rzeczy

Ale chyba największym zaskoczeniem jest tu obecność 70 kodów do gry, których raczej spodziewalibyśmy się w pliku CHEATZ.TXT. W pliku ATTRIBUTEZ.TXT występują jednak w zakodowanej postaci. I wbrew pozorom jest to bardzo istotna informacja.

Kody do gry są z założenia czymś sekretnym. W związku z tym, że w grze Gruntz kody wpisuje się z palca, to gra musi w jakiś sposób porównywać wpisane ciągi znaków z jakimś wzorcem i wywoływać na tej podstawie odpowiednie funkcje. Jeżeli programiści jawnie w kodzie programu użyliby ciągów znaków typu “MPVASFLAM” albo “MPLAMBERT”, znalezienie kodów byłoby banalne – wystarczyłoby otworzyć plik wykonywalny w zwykłym notatniku i wyszukać kody za pomocą funkcji szukania. Dlatego też programiści zmuszeni byli w pewien sposób ukryć te kody, by nie było to aż tak łatwe. To, co widzimy w pliku ATTRIBUTEZ.TXT to właśnie tego rezultat. To nie jest jedynie widzi-mi-sie programistów podczas ładowania kodów z pliku. W ten sposób wszystkie kody są przechowywane w pamięci gry. Więcej o tym napiszę w osobnym artykule i pokażę, jak istotne ma to konsekwencje.

Samo rozkodowanie kodów do gry można uznać jedynie za programistyczną wprawkę. Jest tak dlatego, że w przeciwieństwie do samego pliku ATTRIBUTEZ.TXT, kody do gry nie są zaszyfrowane, lecz zakodowane. Szyfrowanie ma sens wówczas, gdy chcemy ukryć zawartość łatwo lokalizowalnego pliku przed niepowołanymi osobami. Tutaj jest na odwrót – chcemy, by kody były zaciemnione (ukryte) tak, by trudne było ich zlokalizowanie. Kiedy natomiast uda się je zlokalizować, uzyskanie właściwych kodów do gry jest banalne.

Jest parę metod ukrycia łatwo rozpoznawalnych danych. Najprostszą jest chyba XOR-owanie każdego bajtu z jakąś stałą. W tym wypadku jednak programiści poszli bardziej “arytmetyczną” drogą i do każdego bajtu znaku jest po prostu dodawany stały offset. Dobrym przykładem może być tutaj kod na zdobycie miecza – czyli “mparrrrrrr“. W odszyfrowanym pliku ATTRIBUTEZ.TXT temu kodowi odpowiada ciąg bajtów 8A 8D 7E 8F 8F 8F 8F 8F 8F 8F. Od razu widać, jak kod ASCII każdej litery jest po prostu zwiększony o stały offset. Skoro literze “m” odpowiada kod ASCII 0x6D, to offset może wynosić 0x1D. Jest jednak jedno “ale” – równie dobrze jako punkt odniesienia możemy obrać kod “MPARRRRRRR“, czyli pisany dużymi literami. Wówczas literze “M” odpowiada kod ASCII 0x4D, a offset będzie wynosił 0x3D. W jaki sposób to zweryfikować? Na nasze szczęście, wśród tych 70 kodów do gry jest jeden, w którym znajduje się … cyfra. Jest to kod na zaklęcie zmartwychwstania: “mpback2life“, który jest reprezentowany ciągiem bajtów 8A 8D 7F 7E 80 88 6F 89 86 83 82. Okazuje się, że jeżeli za punkt wyjściowy obralibyśmy kod pisany mały literami i od zakodowanej w ATTRIBUTEZ.TXT wersji kodu odjęlibyśmy offset wynoszący 0x1D, uzyskalibyśmy kod … “mpbackRlife“. Jest tak, gdyż po odjęciu od wartości 0x6F offsetu 0x1D otrzymaliśmy bajt 0x52, który jest kodem ASCII dla litery “R”. Jeżeli natomiast odjęlibyśmy offset 0x3D, otrzymalibyśmy bajt o wartości 0x32, czyli cyfrę “2”. I tym samym wprawka została zakończona – offset wynosi 0x3D. Gdyby jednak tego kodu nie było, sprawa by się odrobinę skomplikowała i musielibyśmy eksperymentalnie sprawdzić, jaki offset został użyty.

Jeżeli rozkodujemy wszystkie kody, ukazuje się nam następujący plik:

Plik jest już praktycznie rozczytany, ale nie możemy jeszcze spocząć na laurach. Trochę wątpliwości może bowiem wzbudzać sama końcówka pliku. Algorytm Blowfish jest szyfrem blokowym, który działa na 8-bajtowych blokach. Jeżeli jednak spojrzymy na plik ATTRIBUTEZ.TXT, okazuje się, że jego rozmiar nie jest wielokrotnością 8 bajtów. Na końcu pliku jest jeszcze obecny jeden, jedyny, nadliczbowy bajt … w tym wypadku o wartości 0x05.

Jeżeli spojrzymy na odszyfrowany ostatni 8-bajtowy blok pliku ATTRIBUTEZ.TXT, widzimy, że oryginalny plik tekstowy został dopełniony na końcu bajtami 0x0, by jego rozmiar był wielokrotnością ośmiu bajtów (jest to tzw. zero padding). Natomiast nadliczbowy bajt służy do rozdzielenia paddingu od właściwego tekstu jawnego – jest to liczba bajtów z ostatniego bloku, która jeszcze jest częścią tekstu jawnego. Ten nadliczbowy bajt jest istotny: w razie jego braku domyślnie przyjmowana jest wartość 0x0 i cały ostatni blok szyfrogramu jest ignorowany!

To są już chyba wszystkie informacje odnośnie budowy pliku ATTRIBUTEZ.TXT. Na tej podstawie można już spokojnie pisać narzędzia pozwalające na łatwą i bezbolesną modyfikację pliku i atrybutów tam się znajdujących tak, by gra połknęła wszystko jak ciepłą kluseczkę. Będzie można również modyfikować kody do gier i … dodawać nowe (ale o tym będzie można przeczytać w jeszcze kolejnym artykule 😉 ). W każdym razie taki program jest na pewno na mojej liście TODO programów do napisania.

A w następnym artykule – o pliku CHEATZ.TXT.

Tomalla