-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
1,139 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
|
||
//------------------------------------ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() {}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
|
||
//------------------------------------ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
|
||
#define CRYPT_FN_CPP | ||
#include "CryptoFns.h" |
Oops, something went wrong.