Kubagert's dev[b]log

Sublustrum / Outcry

by 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:

Screen 1Screen 2

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;
}

Leave a Reply

You must be logged in to post a comment.

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!