diff --git a/saco/archive/ArchiveCommon.h b/saco/archive/ArchiveCommon.h new file mode 100644 index 0000000..70b83ee --- /dev/null +++ b/saco/archive/ArchiveCommon.h @@ -0,0 +1,85 @@ + +#pragma once + +#include +#include "Stream.h" + +// SAA_FILE_ID := {'S', 'A', 'M', 'P'} ignoring first 3 bits of each char +// first 3 bits are 010 anyhow :) +#define SAA_FILE_ID 0x83433 +#define SAA_FILE_VERSION 2 + +#define SAA_MAX_ENTRIES 256 + +#define SAA_MAX_FAKEDATA 120 + +typedef struct _SAA_ENTRY +{ + DWORD dwFileNameHash; + int field_4; +} SAA_ENTRY; + +typedef struct _SAA_FILE_HEADER +{ + // This is a fake header + struct VER1_HEADER + { + DWORD dwSAAV; + DWORD dwFileCount; + WORD wFakeData[SAA_MAX_FAKEDATA]; + } headerV1; /* 248 bytes */ + + struct VER2_HEADER + { + union + { + struct + { + DWORD dwSAMPID : 20; + DWORD dwVersion : 3; + DWORD dwSignSize : 8; + DWORD dwPadding1 : 1; + }; + DWORD dwCompleteID; + }; + union + { + struct + { + DWORD dwPadding2 : 5; + DWORD dwInvalidIndex : 8; + DWORD dwPadding3 : 19; + }; + DWORD dwXORKey; + }; + } headerV2; /* 8 bytes */ + + DWORD dwFakeDataSize; + + _SAA_FILE_HEADER() + { + dwFakeDataSize = SAA_MAX_FAKEDATA; + } + + DWORD SizeOf() + { + return(sizeof(DWORD)*2 + sizeof(WORD)*dwFakeDataSize + sizeof(VER2_HEADER)); + } + + bool VerifyIdentifier() + { + return ((headerV2.dwSAMPID == SAA_FILE_ID) && + (headerV2.dwVersion == SAA_FILE_VERSION)); + } + + void XorV2Identifier() { + this->headerV2.dwCompleteID ^= this->headerV2.dwXORKey; + } + + void Read(CAbstractStream *pStream) + { + pStream->Read(&headerV1, sizeof(DWORD)*2 + sizeof(WORD)*dwFakeDataSize); + pStream->Read(&headerV2, sizeof(VER2_HEADER)); + } + +} SAA_FILE_HEADER; diff --git a/saco/archive/ArchiveFS.cpp b/saco/archive/ArchiveFS.cpp new file mode 100644 index 0000000..cf0a992 --- /dev/null +++ b/saco/archive/ArchiveFS.cpp @@ -0,0 +1,128 @@ + +#include "ArchiveFS.h" + +#include "CryptoContext.h" +#include "KeyPair.h" +#include "Signer.h" +#include "Hasher.h" +#include "TinyEncrypt.h" + +//------------------------------------ + +CArchiveFS::CArchiveFS(void) +{ + m_dwNumEntries = SAA_MAX_ENTRIES; + m_bLoaded = false; + m_bEntriesLoaded = false; +} + +//------------------------------------ + +CArchiveFS::CArchiveFS(DWORD dwNumEntries, DWORD dwFDSize) +{ + m_dwNumEntries = dwNumEntries; + m_bLoaded = false; + m_bEntriesLoaded = false; + + m_Header.dwFakeDataSize = dwFDSize; +} + +//------------------------------------ + +void CArchiveFS::LoadEntries() +{ + // Get the file signature, verify it... use the result to decode the entries table + + // Verify the Archive Signature, and decode the Entry block + CCryptoContext context; + CKeyPair keyPair(&context); + CHasher hasher(&context); + CSigner signer; + CTinyEncrypt tinyEnc; + DWORD i; + + // 1. Load the signature from the file + DWORD dwSignSize = 128; //m_Header.headerV2.dwSignSize; + BYTE *pbSignature; + DWORD dwSignDataEnd; + + pbSignature = new BYTE[dwSignSize]; + m_pStream->Seek(-(INT)dwSignSize, CAbstractStream::SeekEnd); + dwSignDataEnd = m_pStream->Tell(); + m_pStream->Read(pbSignature, dwSignSize); + + // 2. Hash the stuff (excluding the header and signature!) + BYTE *pbReadData; + DWORD dwReadSize; + const DWORD dwReadBlockSize = 10 * 1024; // 10kb + + m_pStream->Seek(m_Header.SizeOf()); // start from the actual data section + pbReadData = new BYTE[dwReadBlockSize]; + for(i=m_Header.SizeOf(); iRead(pbReadData, dwReadBlockSize); + if (i+dwReadSize > dwSignDataEnd) + hasher.AddData(dwSignDataEnd - i, pbReadData); + else + hasher.AddData(dwReadSize, pbReadData); + i += dwReadSize; + } + delete[] pbReadData; + + // 3. Load the key and verify the signature + BOOL bVerified; + + keyPair.LoadFromMemory(RSA_PUB_KEY_SIZE, (BYTE*)RSA_PUB_KEY, RSA_XOR_KEY); + signer.SetSignature(dwSignSize, pbSignature); + bVerified = signer.VerifySignature(&hasher, &keyPair); + + delete[] pbSignature; + + // Set the obfuscation decoding mask based on the bVerified value + m_dwObfsMask = -((INT)bVerified); // if its 1 (true), then 0xffffffff, else 0. + + // 4. Decode the TEA encrypted archive entry + + m_pStream->Seek((dwSignDataEnd - m_dwNumEntries*sizeof(SAA_ENTRY))); + DWORD dwFilePos = m_pStream->Tell(); + m_pStream->Read(m_pEntries, sizeof(SAA_ENTRY), m_dwNumEntries); + dwFilePos = m_pStream->Tell(); + + tinyEnc.SetKey((BYTE*)TEA_KEY, TEA_XOR_KEY); + tinyEnc.DecryptData(sizeof(SAA_ENTRY)*m_dwNumEntries, reinterpret_cast(m_pEntries)); + + // 5. Build a binary tree of the entries.. it makes searching for files faster (since we have a + // huge index with fake entries) + for(i=0; i + +#include "ArchiveCommon.h" +#include "Stream.h" + +#include "../mod.h" + +#include "../filesystem.h" + +typedef struct _AFS_ENTRYBT_NODE +{ + SAA_ENTRY* pEntry; + _AFS_ENTRYBT_NODE* pLNode; + _AFS_ENTRYBT_NODE* pRNode; + BYTE* pbData; + + _AFS_ENTRYBT_NODE() + { + this->pEntry = NULL; + this->pLNode = NULL; + this->pRNode = NULL; + this->pbData = NULL; + } + + _AFS_ENTRYBT_NODE(SAA_ENTRY* pSAAEntry) + { + this->pEntry = pSAAEntry; + this->pLNode = NULL; + this->pRNode = NULL; + this->pbData = NULL; + } + + void AddEntry(SAA_ENTRY* pSAAEntry) + { + if (this->pEntry == NULL) { + this->pEntry = pSAAEntry; + } else { + if (pSAAEntry->dwFileNameHash < this->pEntry->dwFileNameHash) { + if (this->pLNode == NULL) + this->pLNode = new _AFS_ENTRYBT_NODE(pSAAEntry); + else + this->pLNode->AddEntry(pSAAEntry); + } else { + if (this->pRNode == NULL) + this->pRNode = new _AFS_ENTRYBT_NODE(pSAAEntry); + else + this->pRNode->AddEntry(pSAAEntry); + } + } + } + +} AFS_ENTRYBT_NODE; + +class CArchiveFS // size: 2357 + : public CFileSystem +{ +private: + bool m_bLoaded; + CAbstractStream *m_pStream; + bool m_bEntriesLoaded; + SAA_FILE_HEADER m_Header; + SAA_ENTRY m_pEntries[SAA_MAX_ENTRIES]; + AFS_ENTRYBT_NODE m_EntryBTreeRoot; + DWORD m_dwObfsMask; + DWORD m_dwNumEntries; + + void LoadEntries(); + +public: + CArchiveFS(void); + CArchiveFS(DWORD dwNumEntries, DWORD dwFDSize); + + virtual bool Load(char* szFileName); + + // TODO: CArchiveFS vftable 100E9AA8 + void CArchiveFS__sub_10065590() {}; + void CArchiveFS__sub_100654A0() {}; + void CArchiveFS__sub_10064E10() {}; + void CArchiveFS__sub_10064EC0() {}; + void CArchiveFS__sub_10064F20() {}; + void CArchiveFS__sub_10064F60() {}; + void CArchiveFS__sub_10064D30() {}; + void CArchiveFS__sub_10064E40() {}; + void CArchiveFS__sub_10065150() {}; +}; diff --git a/saco/archive/CryptoContext.cpp b/saco/archive/CryptoContext.cpp new file mode 100644 index 0000000..a94c622 --- /dev/null +++ b/saco/archive/CryptoContext.cpp @@ -0,0 +1,61 @@ + +#include "CryptoContext.h" +#include "CryptoFns.h" + +//------------------------------------ + +DWORD CCryptoContext::ms_dwRefCount = 0; +DWORD CCryptoContext::ms_dwProviderType = PROV_RSA_FULL; +LPTSTR CCryptoContext::ms_szProviderName = NULL; +LPTSTR CCryptoContext::ms_szContainerName = (LPTSTR)"SAMP"; + +//------------------------------------ + +CCryptoContext::CCryptoContext(void) +{ + /* + if (!ms_hAdvApi32) + { + ms_hAdvApi32 = LoadLibrary("advapi32.dll"); + } + */ + + // Open existing context, if not found, create one! + if ( !CRYPT(AcquireContext)(&m_hCryptProv, ms_szContainerName, ms_szProviderName, ms_dwProviderType, 0) ) { + if( !CRYPT(AcquireContext)(&m_hCryptProv, ms_szContainerName, ms_szProviderName, ms_dwProviderType, CRYPT_NEWKEYSET) ) { + throw(1); + } + } + + ms_dwRefCount++; + +} + +//------------------------------------ + +CCryptoContext::~CCryptoContext(void) +{ + // Release the context + CRYPT(ReleaseContext)(m_hCryptProv, 0); + ms_dwRefCount--; + + if (ms_dwRefCount == 0) { + /* + // Free the library + if (ms_hAdvApi32) + FreeLibrary(ms_hAdvApi32); + */ + + // Delete the context + CRYPT(AcquireContext)(&m_hCryptProv, ms_szContainerName, ms_szProviderName, ms_dwProviderType, CRYPT_DELETEKEYSET); + } +} + +//------------------------------------ + +HCRYPTPROV CCryptoContext::GetProvider() +{ + return m_hCryptProv; +} + +//------------------------------------ diff --git a/saco/archive/CryptoContext.h b/saco/archive/CryptoContext.h new file mode 100644 index 0000000..0075632 --- /dev/null +++ b/saco/archive/CryptoContext.h @@ -0,0 +1,21 @@ + +#pragma once + +#include + +class CCryptoContext +{ +private: + static DWORD ms_dwRefCount; + static DWORD ms_dwProviderType; + static LPTSTR ms_szProviderName; + static LPTSTR ms_szContainerName; + + HCRYPTPROV m_hCryptProv; + +public: + CCryptoContext(void); + ~CCryptoContext(void); + + HCRYPTPROV GetProvider(); +}; diff --git a/saco/archive/CryptoFns.cpp b/saco/archive/CryptoFns.cpp new file mode 100644 index 0000000..7fa153f --- /dev/null +++ b/saco/archive/CryptoFns.cpp @@ -0,0 +1,3 @@ + +#define CRYPT_FN_CPP +#include "CryptoFns.h" diff --git a/saco/archive/CryptoFns.h b/saco/archive/CryptoFns.h new file mode 100644 index 0000000..1a12439 --- /dev/null +++ b/saco/archive/CryptoFns.h @@ -0,0 +1,112 @@ + +// This is intended to be a wrapper for Obfuscating calls +// to CryptoAPI. Make sure that LoadLibrary("ADVAPI32.DLL") is +// somewhere (i.e. access some random reg key), otherwise this +// will fail.. miserably. + +#pragma once + +#include + +#ifndef ARCTOOL + +/* +const CHAR* CRYPT_MODULE = "advapi32"; +const CHAR* CRYPT_FN_AcquireContext = "CryptAcquireContextA"; +const CHAR* CRYPT_FN_ReleaseContext = "CryptReleaseContext"; +const CHAR* CRYPT_FN_GenRandom = "CryptGenRandom"; +const CHAR* CRYPT_FN_CreateHash = "CryptCreateHash"; +const CHAR* CRYPT_FN_DestroyHash = "CryptDestroyHash"; +const CHAR* CRYPT_FN_HashData = "CryptHashData"; +const CHAR* CRYPT_FN_DestroyKey = "CryptDestroyKey"; +const CHAR* CRYPT_FN_ImportKey = "CryptImportKey"; +const CHAR* CRYPT_FN_VerifySignature = "CryptVerifySignatureA"; +*/ + +const CHAR CRYPT_MODULE[] = "41#4%GetProvider(); + CRYPT(CreateHash)(hCryptProv, ms_dwHashAlgorithm, NULL, NULL, &m_hCryptHash); +} + +//------------------------------------ + +CHasher::~CHasher(void) +{ + // Destory the hash container + CRYPT(DestroyHash)(m_hCryptHash); +} + +//------------------------------------ + +void CHasher::AddData(DWORD dwDataLength, BYTE *pbData) +{ + // Add the data to be hashed + CRYPT(HashData)(m_hCryptHash, pbData, dwDataLength, 0); +} + +//------------------------------------ + +HCRYPTKEY CHasher::GetContainer() +{ + return m_hCryptHash; +} + +//------------------------------------ diff --git a/saco/archive/Hasher.h b/saco/archive/Hasher.h new file mode 100644 index 0000000..d17b565 --- /dev/null +++ b/saco/archive/Hasher.h @@ -0,0 +1,22 @@ + +#pragma once + +#include +#include "CryptoContext.h" + +class CHasher +{ +private: + static DWORD ms_dwHashAlgorithm; + + HCRYPTHASH m_hCryptHash; + CCryptoContext* m_pContext; + +public: + CHasher(CCryptoContext* pContext); + ~CHasher(void); + + void AddData(DWORD dwDataLength, BYTE* pbData); + HCRYPTHASH GetContainer(); + +}; diff --git a/saco/archive/KeyPair.cpp b/saco/archive/KeyPair.cpp new file mode 100644 index 0000000..7624b92 --- /dev/null +++ b/saco/archive/KeyPair.cpp @@ -0,0 +1,62 @@ + +#include "KeyPair.h" +#include "CryptoFns.h" + +//------------------------------------ + +CKeyPair::CKeyPair(CCryptoContext* pContext) +{ + m_pContext = pContext; + m_hCryptKey = NULL; +} + +//------------------------------------ + +CKeyPair::~CKeyPair(void) +{ + if (m_hCryptKey != NULL) + ReleaseKey(); +} + +//------------------------------------ + +void CKeyPair::ReleaseKey() +{ + // Destroy the key pair + CRYPT(DestroyKey)(m_hCryptKey); + m_hCryptKey = NULL; +} + +//------------------------------------ + +void CKeyPair::LoadFromMemory(DWORD dwPubKeySize, BYTE* pbPubKeyBlob, BYTE bytXORKey) +{ + BYTE *pbKeyBlob; + + // Un-XOR keys from memory + if (bytXORKey != 0) { + pbKeyBlob = new BYTE[dwPubKeySize]; + for(DWORD i=0; iGetProvider(); + CRYPT(ImportKey)(hCryptProv, pbKeyBlob, dwPubKeySize, NULL, NULL, &m_hCryptKey); + + // Clean up + if (bytXORKey != 0) { + delete[] pbKeyBlob; + } +} + +//------------------------------------ + +HCRYPTKEY CKeyPair::GetContainer() +{ + return m_hCryptKey; +} + +//------------------------------------ diff --git a/saco/archive/KeyPair.h b/saco/archive/KeyPair.h new file mode 100644 index 0000000..e754d36 --- /dev/null +++ b/saco/archive/KeyPair.h @@ -0,0 +1,21 @@ + +#pragma once + +#include +#include "CryptoContext.h" + +class CKeyPair +{ +private: + HCRYPTKEY m_hCryptKey; + CCryptoContext* m_pContext; + +public: + CKeyPair(CCryptoContext* pContext); + ~CKeyPair(void); + + void LoadFromMemory(DWORD dwPubKeySize, BYTE* pbPubKeyBlob, BYTE bytXORKey); + void ReleaseKey(); + + HCRYPTKEY GetContainer(); +}; diff --git a/saco/archive/Obfuscator.h b/saco/archive/Obfuscator.h new file mode 100644 index 0000000..0191b8d --- /dev/null +++ b/saco/archive/Obfuscator.h @@ -0,0 +1,6 @@ + +#pragma once + +#define OBFUSCATE_KEY 0xC103D3E7 +#define OBFUSCATE_DATA(a) ((((a) << 19) | ((a) >> 13)) ^ OBFUSCATE_KEY) +#define UNOBFUSCATE_DATA(a) ((((a) ^ OBFUSCATE_KEY) >> 19) | (((a) ^ OBFUSCATE_KEY) << 13)) diff --git a/saco/archive/Signer.cpp b/saco/archive/Signer.cpp new file mode 100644 index 0000000..fb6a332 --- /dev/null +++ b/saco/archive/Signer.cpp @@ -0,0 +1,46 @@ + +#include "Signer.h" +#include "CryptoFns.h" + +//------------------------------------ + +CSigner::CSigner(void) +{ + m_dwLength = 0; + m_pbSignature = NULL; +} + +//------------------------------------ + +CSigner::~CSigner(void) +{ + if (m_pbSignature != NULL) + delete[] m_pbSignature; +} + +//------------------------------------ + +void CSigner::SetSignature(DWORD dwLength, BYTE *pbSignature) +{ + if (m_pbSignature != NULL) + delete[] m_pbSignature; + + m_dwLength = dwLength; + m_pbSignature = new BYTE[dwLength]; + memcpy(m_pbSignature, pbSignature, m_dwLength); +} + +//------------------------------------ + +BOOL CSigner::VerifySignature(CHasher *pHasher, CKeyPair *pKeyPair) +{ + HCRYPTHASH hCryptHash = pHasher->GetContainer(); + HCRYPTKEY hCryptKey = pKeyPair->GetContainer(); + BOOL bVerify; + + bVerify = CRYPT(VerifySignature)(hCryptHash, m_pbSignature, m_dwLength, hCryptKey, NULL, CRYPT_NOHASHOID); + + return bVerify; +} + +//------------------------------------ diff --git a/saco/archive/Signer.h b/saco/archive/Signer.h new file mode 100644 index 0000000..43eb238 --- /dev/null +++ b/saco/archive/Signer.h @@ -0,0 +1,21 @@ + +#pragma once + +#include +#include "Hasher.h" +#include "KeyPair.h" + +class CSigner +{ +private: + BYTE* m_pbSignature; + DWORD m_dwLength; + +public: + CSigner(void); + ~CSigner(void); + + void SetSignature(DWORD dwLength, BYTE* pbSignature); + BOOL VerifySignature(CHasher* pHasher, CKeyPair* pKeyPair); + +}; diff --git a/saco/archive/Stream.h b/saco/archive/Stream.h new file mode 100644 index 0000000..33d8954 --- /dev/null +++ b/saco/archive/Stream.h @@ -0,0 +1,248 @@ + +#pragma once + +#include + +class CAbstractStream +{ +public: + enum eSeek + { + SeekStart, + SeekCurrent, + SeekEnd, + }; + + CAbstractStream() {} + + virtual ~CAbstractStream() {} + + virtual unsigned int Read(void *pbBuffer, int nNumberOfBytes) = 0; + + virtual unsigned int Read(void *pbBuffer, int nElementSize, int nNumberOfElements) + { + return Read(pbBuffer, nNumberOfElements * nElementSize); + } + + virtual unsigned int Write(const void *pbBuffer, int nNumberOfBytes) = 0; + + virtual unsigned int Write(const void *pbBuffer, int nElementSize, int nNumberOfElements) + { + return Write(pbBuffer, nNumberOfElements * nElementSize); + } + + virtual void Seek(int nOffset, eSeek seekMode) = 0; + + virtual void Seek(int nOffset) + { + Seek(nOffset, SeekStart); + } + + virtual unsigned int Tell() = 0; +}; + +class CFileStream : + public CAbstractStream +{ +protected: + FILE *m_fiFile; + +public: + enum eMode + { + ModeRead, + ModeReadWrite, + ModeAppend, + ModeWrite, + }; + + enum eType + { + TypeText, + TypeBinary, + }; + + CFileStream(const char *szFilename, eType type, eMode mode) + { + m_fiFile = NULL; + Open(szFilename, type, mode); + } + + virtual ~CFileStream() + { + if (m_fiFile) + Close(); + } + + virtual bool Open(const char *szFilename, eType type, eMode mode) + { + if (m_fiFile) + Close(); + + char szMode[4]; + int nPos = 0; + szMode[0] = szMode[1] = szMode[2] = szMode[3] = 0; + + switch(mode) + { + case ModeRead: + szMode[nPos++] = 'r'; break; + case ModeWrite: + szMode[nPos++] = 'w'; break; + case ModeReadWrite: + szMode[nPos++] = 'r'; szMode[nPos++] = '+'; break; + case ModeAppend: + szMode[nPos++] = 'a'; break; + } + + switch(type) + { + case TypeText: + szMode[nPos++] = 't'; break; + case TypeBinary: + szMode[nPos++] = 'b'; break; + } + + m_fiFile = fopen(szFilename, szMode); + if (!m_fiFile) + return false; + + return true; + } + + virtual bool IsOpen() + { + return (m_fiFile != NULL); + } + + virtual void Close() + { + if (m_fiFile) + { + fclose(m_fiFile); + m_fiFile = NULL; + } + } + + virtual unsigned int Read(void *pbBuffer, int nNumberOfBytes) + { + return (unsigned int)fread(pbBuffer, 1, nNumberOfBytes, m_fiFile); + } + + virtual unsigned int Read(void *pbBuffer, int nElementSize, int nNumberOfElements) + { + return (unsigned int)fread(pbBuffer, nElementSize, nNumberOfElements, m_fiFile); + } + + virtual unsigned int Write(const void *pbBuffer, int nNumberOfBytes) + { + return (unsigned int)fwrite(pbBuffer, 1, nNumberOfBytes, m_fiFile); + } + + virtual unsigned int Write(const void *pbBuffer, int nElementSize, int nNumberOfElements) + { + return (unsigned int)fwrite(pbBuffer, nElementSize, nNumberOfElements, m_fiFile); + } + + virtual void Seek(int nOffset, eSeek seekMode) + { + int mode = 0; + switch (seekMode) + { + case SeekCurrent: + mode = SEEK_CUR; break; + case SeekStart: + mode = SEEK_SET; break; + case SeekEnd: + mode = SEEK_END; break; + } + + fseek(m_fiFile, nOffset, seekMode); + } + + virtual unsigned int Tell() + { + return (unsigned int)ftell(m_fiFile); + } + +}; + +class CMemoryStream : + public CAbstractStream +{ +protected: + unsigned char *m_pbBuffer; + unsigned int m_nOffset; + unsigned int m_nLength; + bool m_bCopy; + +public: + CMemoryStream(unsigned char *pbBuffer, unsigned int nLength, bool bCopy = true) + { + m_bCopy = bCopy; + m_nOffset = 0; + m_nLength = nLength; + + if (bCopy) + { + m_pbBuffer = (unsigned char *)malloc(nLength); + memcpy(m_pbBuffer, pbBuffer, nLength); + } + else + { + m_pbBuffer = pbBuffer; + } + } + + virtual ~CMemoryStream() + { + if (m_bCopy && m_pbBuffer) + { + free(m_pbBuffer); + } + } + + virtual unsigned int Read(void *pbBuffer, int nNumberOfBytes) + { + if (m_nOffset + nNumberOfBytes > m_nLength) + nNumberOfBytes = m_nLength - m_nOffset; + + memcpy(pbBuffer, m_pbBuffer + m_nOffset, nNumberOfBytes); + m_nOffset += nNumberOfBytes; + + return nNumberOfBytes; + } + + virtual unsigned int Write(const void *pbBuffer, int nNumberOfBytes) + { + if (m_nOffset + nNumberOfBytes > m_nLength) + nNumberOfBytes = m_nLength - m_nOffset; + + memcpy(m_pbBuffer + m_nOffset, pbBuffer, nNumberOfBytes); + m_nOffset += nNumberOfBytes; + + return nNumberOfBytes; + } + + virtual void Seek(int nOffset, eSeek seekMode) + { + switch(seekMode) + { + case SeekStart: + m_nOffset = nOffset; break; + case SeekCurrent: + m_nOffset += nOffset; break; + case SeekEnd: + m_nOffset = m_nLength + nOffset; break; + } + + if (m_nOffset > m_nLength) + m_nOffset = m_nLength; + } + + virtual unsigned int Tell() + { + return m_nOffset; + } + +}; diff --git a/saco/archive/TinyEncrypt.cpp b/saco/archive/TinyEncrypt.cpp new file mode 100644 index 0000000..d4a3fb8 --- /dev/null +++ b/saco/archive/TinyEncrypt.cpp @@ -0,0 +1,75 @@ + +#include "TinyEncrypt.h" +#include "Obfuscator.h" + +//------------------------------------ + +DWORD CTinyEncrypt::ms_dwRounds = 32; +DWORD CTinyEncrypt::ms_dwInitDelta = OBFUSCATE_DATA(0x9E3779B9); +DWORD CTinyEncrypt::ms_dwInitSum = 0; +BOOL CTinyEncrypt::ms_bInitDone = FALSE; + +//------------------------------------ + +CTinyEncrypt::CTinyEncrypt(void) +{ + if (!ms_bInitDone) { + ms_dwInitDelta = UNOBFUSCATE_DATA(ms_dwInitDelta); + ms_dwInitSum = ms_dwInitDelta * ms_dwRounds; + ms_bInitDone = TRUE; + } +} + +//------------------------------------ + +CTinyEncrypt::~CTinyEncrypt(void) +{ +} + +//------------------------------------ + +void CTinyEncrypt::SetKey(BYTE *pbKey, BYTE bytXORKey) +{ + memcpy(m_pdwKey, pbKey, TEA_KEY_SIZE); + + if (bytXORKey != 0) + { + BYTE *pbKeyRef = reinterpret_cast(m_pdwKey); + for(DWORD i=0; i> 5) + dwV0) ^ (dwSum + m_pdwKey[dwSum>>11 & 3]); + dwSum -= ms_dwInitDelta; + dwV0 -= ((dwV1 << 4 ^ dwV1 >> 5) + dwV1) ^ (dwSum + m_pdwKey[dwSum & 3]); + } + + m_pdwKey[0] ^= dwV0old; + m_pdwKey[1] ^= dwV1old; + m_pdwKey[2] ^= dwV0old; + m_pdwKey[3] ^= dwV1old; +} + +//------------------------------------ + +void CTinyEncrypt::DecryptData(DWORD dwLength, BYTE *pbData) +{ + DWORD dwBlocks = dwLength / 4; + DWORD *pdwData = reinterpret_cast(pbData); + for(DWORD i=0; i + +#define TEA_KEY_SIZE 16 + +class CTinyEncrypt +{ +private: + static DWORD ms_dwRounds; + static DWORD ms_dwInitDelta; + static DWORD ms_dwInitSum; + static BOOL ms_bInitDone; + + DWORD m_pdwKey[TEA_KEY_SIZE/sizeof(DWORD)]; + + void DecryptBlock(DWORD &dwV0, DWORD &dwV1); + +public: + CTinyEncrypt(void); + ~CTinyEncrypt(void); + + void SetKey(BYTE* pbKey, BYTE bytXORKey); + + void DecryptData(DWORD dwLength, BYTE* pbData); +}; diff --git a/saco/main.cpp b/saco/main.cpp index 8e1bf52..320de23 100644 --- a/saco/main.cpp +++ b/saco/main.cpp @@ -6,6 +6,8 @@ HANDLE hInstance=0; CGame *pGame=0; +CFileSystem *pFileSystem=NULL; + // forwards LONG WINAPI exc_handler(_EXCEPTION_POINTERS* exc_inf); @@ -20,34 +22,17 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) if(tSettings.bDebug || tSettings.bPlayOnline) { SetUnhandledExceptionFilter(exc_handler); + //dword_1026EB3C = (int)sub_100C4FF0; - // TODO: DllMain - /* - dword_1026EB3C = (int)sub_100C4FF0; - GetModuleFileNameA((HMODULE)hInstance, &Filename, 0x104u); - v3 = strlen(&Filename); - if ( *(&Filename + v3) != 92 ) - { - do - v4 = *((_BYTE *)&v12 + v3-- + 3); - while ( v4 != 92 ); - } - v5 = &v15[v3]; - *(_DWORD *)v5 = 1886216563; - *((_DWORD *)v5 + 1) = 1633776430; - v5[8] = 0; - v6 = operator new(0x935u); - v12 = v6; - v16 = 0; - if ( v6 ) - v7 = (int *)sub_10065350(v6); - else - v7 = 0; - dword_1026EB44 = (int)v7; - v8 = *v7; - v16 = -1; - if ( !(unsigned __int8)(*(int (__thiscall **)(int *, int *))(v8 + 4))(v7, &dword_100EDB18) ) - __debugbreak();*/ + CHAR szArchiveFile[MAX_PATH]; + GetModuleFileNameA((HMODULE)hInstance, szArchiveFile, MAX_PATH); + DWORD dwFileNameLen = strlen(szArchiveFile); + while(szArchiveFile[dwFileNameLen] != '\\') + dwFileNameLen--; + strcpy(szArchiveFile+dwFileNameLen+1, ARCHIVE_FILE); + + pFileSystem = new CArchiveFS(); + if(!pFileSystem->Load(ARCHIVE_FILE)) _asm int 3 AddFontResourceA("gtaweap3.ttf"); AddFontResourceA("sampaux3.ttf"); diff --git a/saco/main.h b/saco/main.h index fb5d315..f76595c 100644 --- a/saco/main.h +++ b/saco/main.h @@ -20,6 +20,8 @@ typedef struct _GAME_SETTINGS { #include "game/game.h" +#include "archive/ArchiveFS.h" + void SetStringFromCommandLine(char *szCmdLine, char *szString); void SetStringFromQuotedCommandLine(char *szCmdLine, char *szString); void InitSettings(); diff --git a/saco/saco.vcproj b/saco/saco.vcproj index d1aed5c..08b5f08 100644 --- a/saco/saco.vcproj +++ b/saco/saco.vcproj @@ -169,6 +169,61 @@ RelativePath=".\game\util.h"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +