[saco] Implement archive functions

This commit is contained in:
RD42 2023-11-08 20:29:53 +08:00
parent 916d4d02f2
commit 8defa849b9
20 changed files with 1139 additions and 27 deletions

View File

@ -0,0 +1,85 @@
#pragma once
#include <windows.h>
#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;

128
saco/archive/ArchiveFS.cpp Normal file
View File

@ -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(); i<dwSignDataEnd; ) {
dwReadSize = m_pStream->Read(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<BYTE*>(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<m_dwNumEntries; i++) {
m_EntryBTreeRoot.AddEntry(&m_pEntries[i]);
}
// Done.
m_bEntriesLoaded = true;
}
//------------------------------------
bool CArchiveFS::Load(char* szFileName)
{
if (m_bLoaded)
Unload();
m_pStream = new CFileStream(szFileName, CFileStream::TypeBinary, CFileStream::ModeRead);
m_Header.Read(m_pStream);
m_Header.XorV2Identifier();
m_bLoaded = true;
if (!m_Header.VerifyIdentifier()) {
Unload();
return false;
}
return true;
}
//------------------------------------

88
saco/archive/ArchiveFS.h Normal file
View File

@ -0,0 +1,88 @@
#pragma once
#include <windows.h>
#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() {};
};

View File

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

View File

@ -0,0 +1,21 @@
#pragma once
#include <windows.h>
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();
};

View File

@ -0,0 +1,3 @@
#define CRYPT_FN_CPP
#include "CryptoFns.h"

112
saco/archive/CryptoFns.h Normal file
View File

@ -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 <windows.h>
#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%<fgU";
const CHAR CRYPT_FN_AcquireContext[] = {0x16,0x27,0x2C,0x25,0x21,0x14,0x36,0x24,
0x20,0x3C,0x27,0x30,0x16,0x3A,0x3B,0x21,
0x30,0x2D,0x21,0x14,0x55,0x00,0x00,0x00};
const CHAR CRYPT_FN_ReleaseContext[] = {0x16,0x27,0x2C,0x25,0x21,0x07,0x30,0x39,
0x30,0x34,0x26,0x30,0x16,0x3A,0x3B,0x21,
0x30,0x2D,0x21,0x55,0x00,0x00,0x00,0x00,};
const CHAR CRYPT_FN_CreateHash[] = {0x16,0x27,0x2C,0x25,0x21,0x16,0x27,0x30,
0x34,0x21,0x30,0x1D,0x34,0x26,0x3D,0x55};
const CHAR CRYPT_FN_DestroyHash[] = {0x16,0x27,0x2C,0x25,0x21,0x11,0x30,0x26,
0x21,0x27,0x3A,0x2C,0x1D,0x34,0x26,0x3D,
0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
const CHAR CRYPT_FN_HashData[] = {0x16,0x27,0x2C,0x25,0x21,0x1D,0x34,0x26,
0x3D,0x11,0x34,0x21,0x34,0x55,0x00,0x00};
const CHAR CRYPT_FN_DestroyKey[] = {0x16,0x27,0x2C,0x25,0x21,0x11,0x30,0x26,
0x21,0x27,0x3A,0x2C,0x1E,0x30,0x2C,0x55};
const CHAR CRYPT_FN_ImportKey[] = {0x16,0x27,0x2C,0x25,0x21,0x1C,0x38,0x25,
0x3A,0x27,0x21,0x1E,0x30,0x2C,0x55,0x00};
const CHAR CRYPT_FN_VerifySignature[] = {0x16,0x27,0x2C,0x25,0x21,0x03,0x30,0x27,
0x3C,0x33,0x2C,0x06,0x3C,0x32,0x3B,0x34,
0x21,0x20,0x27,0x30,0x14,0x55,0x00,0x00};
#define CRYPT_GET_NAME(a,b) \
CHAR* a = NULL; \
{ \
DWORD dwFnLen = strlen(b); \
a = new CHAR[dwFnLen]; \
for(DWORD i=0; i<dwFnLen; i++) \
##a[i] = (CHAR)(##b[i] ^ 0x55); \
}
#ifndef CRYPT_FN_CPP
#define CRYPT_IMPL_FN(n,r,p) \
r WINAPI xCryptCall##n##p;
#else
// This is for the actual function when in the .CPP
#define CRYPT_IMPL_FN(n,r,p) \
DWORD xCryptOffs##n = NULL; \
__declspec(naked) r WINAPI xCryptCall##n##p \
{ \
if (xCryptOffs##n == NULL) { \
_asm { lea eax, CRYPT_FN_##n }; \
_asm { push eax }; \
_asm { call xCryptGetFunction }; \
_asm { add esp, 4 }; \
_asm { mov dword ptr xCryptOffs##n, eax }; \
} \
_asm { mov eax, dword ptr xCryptOffs##n }; \
_asm { jmp eax }; \
}
#endif
#ifdef CRYPT_FN_CPP
FARPROC xCryptGetFunction(CHAR* name, DWORD len)
{
CRYPT_GET_NAME(szModName, CRYPT_MODULE);
CRYPT_GET_NAME(szProcName, name);
HMODULE hMod = GetModuleHandle(szModName);
FARPROC fpProc = GetProcAddress(hMod, szProcName);
return fpProc;
}
#endif
#define CRYPT(n) \
xCryptCall##n
CRYPT_IMPL_FN(AcquireContext, BOOL, (HCRYPTPROV* phProv, LPCTSTR pszContainer, LPCTSTR pszProvider, DWORD dwProvType, DWORD dwFlags))
CRYPT_IMPL_FN(ReleaseContext, BOOL, (HCRYPTPROV hProv, DWORD dwFlags))
CRYPT_IMPL_FN(CreateHash, BOOL, (HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH* phHash))
CRYPT_IMPL_FN(DestroyHash, BOOL, (HCRYPTHASH hHash))
CRYPT_IMPL_FN(HashData, BOOL, (HCRYPTHASH hHash, BYTE* pbData, DWORD dwDataLen, DWORD dwFlags))
CRYPT_IMPL_FN(DestroyKey, BOOL, (HCRYPTKEY hKey))
CRYPT_IMPL_FN(ImportKey, BOOL, (HCRYPTPROV hProv, BYTE* pbData, DWORD dwDataLen, HCRYPTKEY hPubKey, DWORD dwFlags, HCRYPTKEY* phKey))
CRYPT_IMPL_FN(VerifySignature, BOOL, (HCRYPTHASH hHash, BYTE* pbSignature, DWORD dwSigLen, HCRYPTKEY hPubKey, LPCTSTR sDescription, DWORD dwFlags))
#else
#define CRYPT(n) \
Crypt##n
#endif

44
saco/archive/Hasher.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "Hasher.h"
#include "CryptoFns.h"
//------------------------------------
DWORD CHasher::ms_dwHashAlgorithm = CALG_SHA1;
//------------------------------------
CHasher::CHasher(CCryptoContext* pContext)
{
// Save context for later
m_pContext = pContext;
// Generate a hash container
HCRYPTPROV hCryptProv = pContext->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;
}
//------------------------------------

22
saco/archive/Hasher.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include <windows.h>
#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();
};

62
saco/archive/KeyPair.cpp Normal file
View File

@ -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; i<dwPubKeySize; i++)
pbKeyBlob[i] = pbPubKeyBlob[i] ^ bytXORKey;
} else {
pbKeyBlob = pbPubKeyBlob;
}
// Import the key
HCRYPTPROV hCryptProv = m_pContext->GetProvider();
CRYPT(ImportKey)(hCryptProv, pbKeyBlob, dwPubKeySize, NULL, NULL, &m_hCryptKey);
// Clean up
if (bytXORKey != 0) {
delete[] pbKeyBlob;
}
}
//------------------------------------
HCRYPTKEY CKeyPair::GetContainer()
{
return m_hCryptKey;
}
//------------------------------------

21
saco/archive/KeyPair.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <windows.h>
#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();
};

View File

@ -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))

46
saco/archive/Signer.cpp Normal file
View File

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

21
saco/archive/Signer.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <windows.h>
#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);
};

248
saco/archive/Stream.h Normal file
View File

@ -0,0 +1,248 @@
#pragma once
#include <stdio.h>
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;
}
};

View File

@ -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<BYTE*>(m_pdwKey);
for(DWORD i=0; i<TEA_KEY_SIZE; i++)
pbKeyRef[i] ^= bytXORKey;
}
}
//------------------------------------
void CTinyEncrypt::DecryptBlock(DWORD &dwV0, DWORD &dwV1)
{
DWORD dwSum = ms_dwInitSum;
DWORD dwV0old = dwV0;
DWORD dwV1old = dwV1;
for(DWORD i=0; i<ms_dwRounds; i++) {
dwV1 -= ((dwV0 << 4 ^ dwV0 >> 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<DWORD*>(pbData);
for(DWORD i=0; i<dwBlocks; i+=2) {
DecryptBlock(pdwData[i+0], pdwData[i+1]);
}
}
//------------------------------------

View File

@ -0,0 +1,27 @@
#pragma once
#include <windows.h>
#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);
};

View File

@ -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");

View File

@ -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();

View File

@ -169,6 +169,61 @@
RelativePath=".\game\util.h">
</File>
</Filter>
<Filter
Name="archive"
Filter="">
<File
RelativePath=".\archive\ArchiveCommon.h">
</File>
<File
RelativePath=".\archive\ArchiveFS.cpp">
</File>
<File
RelativePath=".\archive\ArchiveFS.h">
</File>
<File
RelativePath=".\archive\CryptoContext.cpp">
</File>
<File
RelativePath=".\archive\CryptoContext.h">
</File>
<File
RelativePath=".\archive\CryptoFns.cpp">
</File>
<File
RelativePath=".\archive\CryptoFns.h">
</File>
<File
RelativePath=".\archive\Hasher.cpp">
</File>
<File
RelativePath=".\archive\Hasher.h">
</File>
<File
RelativePath=".\archive\KeyPair.cpp">
</File>
<File
RelativePath=".\archive\KeyPair.h">
</File>
<File
RelativePath=".\archive\Obfuscator.h">
</File>
<File
RelativePath=".\archive\Signer.cpp">
</File>
<File
RelativePath=".\archive\Signer.h">
</File>
<File
RelativePath=".\archive\Stream.h">
</File>
<File
RelativePath=".\archive\TinyEncrypt.cpp">
</File>
<File
RelativePath=".\archive\TinyEncrypt.h">
</File>
</Filter>
<File
RelativePath=".\audiostream.cpp">
</File>