Sublustrum / Outcry
by kubagert on gru.29, 2010, under Programowanie gier
Daaawno dawno temu wpadła w moje ręce gra pt. Sublustrum ( znana także jako Outcry ). Jako że jestem fanem gier point&click grę postanowiłem przejść.
Grało się całkiem ciekawie. Jako że po przejściu gry pozostał mi pewien niedosyt, postanowiłem zobaczyć jak jest zbudowana od środka.
Szybki podgląd paczek plików utwierdził mnie w przekonaniu, że struktura jest bardzo prosta. Każdy plik pak zawiera w swojej strukturze:
- ilość plików w paczce
- nazwę pliku
- offset pliku względem początku
- długość pliku
Wypakowanie wszystkich plików z paczki było pryszczem, ale okazało się, że są one zaszyfrowane, lecz za pomocą bardzo prostego klucza. Na klucz wpadłem analizując nazwy plików, założyłem, że pliki graficzne są plikami DDS, dźwiękowe WAV lub OGG. Szukając powtarzających się wzorców odkryłem klucz: każdy bajt został rozbity na dwa półbajty (starsza i młodsza część. Z takiego podziału otrzymujemy 4 bity (wartości od 0-15). Każdej wartości przyporządkowana została nowa wartość z tego samego przedziału (czyli szyfr Cezara). Raz dwa powstał programik, który wypakowywuje wszystkie pliki z paków, oraz je poprawnie dekoduje. Dwie małe próbki:
I kod źródłowy jakby ktoś chciał zobaczyć całą resztę:
#include <stdio.h> #include <stdlib.h> #include <vector> struct SFile { int filenameLen; char fileName[256]; int offset; int fileLen; }; char cryptoTab[]= { 0x0C, 0x0D, 0x0E, 0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, }; void CryptoBuff( char *buff, int bufLen ) { for(int a=0; a<bufLen; a++) { char msb=(buff[a] & 0xF0)>>4; char lsb=(buff[a] & 0x0F); buff[a]=(cryptoTab[msb]<<4) | cryptoTab[lsb]; } } void DepackFile( const char *fileName ) { FILE *f=fopen(fileName,"rb"); if(!f) return; char temp[4]; fread( temp, 1, 4, f); int filesCount=0; fread( &filesCount, sizeof(int), 1, f); std::vector<SFile> files; for(int a=0; a<filesCount; a++) { SFile file; fread( &file.filenameLen, sizeof(int), 1, f); fread( file.fileName, sizeof(char), file.filenameLen, f); file.fileName[file.filenameLen]=0; fread( &file.offset, sizeof(int), 1, f); fread( &file.fileLen, sizeof(int), 1, f); files.push_back(file); } int startOffset=ftell( f ); for(int a=0; a<files.size(); a++) { fseek( f, files[a].offset+startOffset, SEEK_SET ); for(int n=0; n<strlen(files[a].fileName); n++) if(files[a].fileName[n]=='/') files[a].fileName[n]='.'; printf("\nProcess file: %s ", files[a].fileName ); FILE *nf=fopen( files[a].fileName, "wb" ); char *tempBuff=new char[files[a].fileLen]; fread( tempBuff, 1, files[a].fileLen, f ); CryptoBuff( tempBuff, files[a].fileLen ); fwrite( tempBuff, 1, files[a].fileLen, nf); fclose(nf); } fclose(f); } int main(int argc, char *argv[]) { for(int a=1; a<argc; a++) DepackFile( argv[a] ); printf("\n"); system("PAUSE"); return 0; }

