Code:
#include "stdafx.h"
#include "Mazey Decrypt.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// The one and only application object
/* Author WurstbrotQT
* Purpose Disassemble Mazey File Format
* Date 19/09/2014
*/
CWinApp theApp;
using namespace std;
unsigned int DecryptFile(CString&);
unsigned int DecryptMazey(CString const);
BYTE Decrypt(BYTE, BYTE);
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule != NULL)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
CreateDirectory(TEXT("Decryption"), NULL);
cout << "Decrypting..." << endl;
DWORD dwTickStart = GetTickCount();
unsigned int nDecryptedFileCount = DecryptMazey(TEXT(""));
cout << "Decrypted " << nDecryptedFileCount << " files in " << (GetTickCount() - dwTickStart) << "ms";
getchar();
}
}
else
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: GetModuleHandle failed\n"));
nRetCode = 1;
}
return nRetCode;
}
unsigned int DecryptMazey(const CString argPath)
{
CString sPathToSearch = argPath + TEXT("*.*"); // we cannot simply look for .res files since subdirectories wouldn't be included
WIN32_FIND_DATA winData;
HANDLE hSearch = FindFirstFile(sPathToSearch, &winData);
if (FAILED(hSearch))
return 0;
unsigned int nRet = 0;
do {
CString sFileName = winData.cFileName;
if (winData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (!!sFileName.Compare(TEXT(".")) && !!sFileName.Compare(TEXT(".."))){
CString sNewPath;
sNewPath.Format(TEXT("%s%s\\"), argPath, sFileName);
nRet += DecryptMazey(sNewPath);
}
}
else // file
{
int nNameLength = sFileName.GetLength();
if (nNameLength >= 4){
CString sExt = sFileName.Mid(nNameLength - 4);
if (!sExt.Compare(TEXT(".res"))) {
nRet += DecryptFile(argPath + sFileName);
}
}
}
} while (FindNextFile(hSearch, &winData));
FindClose(hSearch);
return nRet;
}
BYTE Decrypt(BYTE argValue, BYTE argKey)
{
argValue = ~argValue ^ argKey;
return (argValue << 4) | (argValue >> 4);
}
unsigned int DecryptFile(CString & argName)
{
CFile fRead;
if (FALSE == fRead.Open(argName, CFile::modeRead | CFile::shareExclusive))
return 0;
bool bEncryption;
BYTE byEncryptionKey;
int nHeaderSize;
BYTE *pData;
// we never assume negative file counts
unsigned short nFileCount;
unsigned int nRet = 0;
int nRemainder = 7; // skip version
CString sFileNameToLower = argName.MakeLower();
bool bSkipTime = !sFileNameToLower.Compare(TEXT("maze.res")) ||
!sFileNameToLower.Compare(TEXT("maze1.res")) ||
!sFileNameToLower.Compare(TEXT("world\\wdquiz\\wdquiz.res")) ||
!sFileNameToLower.Compare(TEXT("world\\wdquiz\\wdquiz1.res")) ||
!sFileNameToLower.Compare(TEXT("world\\wdmarket\\wdmarket.res")) ||
!sFileNameToLower.Compare(TEXT("model\\indigo.res")) ||
!sFileNameToLower.Compare(TEXT("model\\texture\\indigo.res"));
fRead.Read(&byEncryptionKey, sizeof(BYTE));
fRead.Read(&bEncryption, sizeof(bool));
fRead.Read(&nHeaderSize, sizeof(int));
pData = new BYTE[nHeaderSize];
fRead.Read(&pData[0], nHeaderSize);
// decrypt the header as every flyff client
for (int i = 0; i < nHeaderSize; ++i)
pData[i] = Decrypt(pData[i], byEncryptionKey);
memcpy_s(&nFileCount, sizeof(short), &pData[nRemainder], sizeof(short));
nRemainder += 2;
// we have to go thru the lot
for (short nCurFile = 0; nCurFile < nFileCount; ++nCurFile)
{
unsigned short nFileNameLength;
char szFileName[_MAX_FNAME];
int nOffset;
int nFileSize;
memcpy_s(&nFileNameLength, sizeof(short), &pData[nRemainder], sizeof(short));
nRemainder += sizeof(short);
ASSERT(nFileNameLength < _MAX_FNAME);
memcpy_s(szFileName, nFileNameLength, &pData[nRemainder], nFileNameLength);
szFileName[nFileNameLength] = 0;
nRemainder += nFileNameLength;
memcpy_s(&nFileSize, sizeof(int), &pData[nRemainder], sizeof(int));
nRemainder += sizeof(int);
// some files skip the last edit time, which is rubbish, but here we go
if ( !bSkipTime )
nRemainder += sizeof(int); // we don't need that parameter anyway, so skip as well.
// the last interesting parameter, the file offset itself
memcpy_s(&nOffset, sizeof(int), &pData[nRemainder], sizeof(int));
nRemainder += sizeof(int);
// directly write content to file
CFile fWrite;
CString sNewFileName = TEXT("Decryption\\");
sNewFileName += szFileName;
if (TRUE == fWrite.Open(sNewFileName, CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive))
{
BYTE *pContent = new BYTE[nFileSize];
fRead.Seek(nOffset, CFile::begin);
fRead.Read(pContent, nFileSize);
if ( bEncryption )
for (int i = 0; i < nFileSize; ++i)
pContent[i] = Decrypt(pContent[i], byEncryptionKey);
fWrite.Write(pContent, nFileSize);
fWrite.Close();
delete[] pContent;
nRet++;
}
}
// free unused memory
delete[] pData;
return nRet;
}






