872 lines
23 KiB
C++
872 lines
23 KiB
C++
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Crytek Engine Source File.
|
|
// Copyright (C), Crytek Studios, 2001-2004.
|
|
// -------------------------------------------------------------------------
|
|
// File name: DataProbe.cpp
|
|
// Version: v1.00
|
|
// Created: 19/1/2004 by Timur.
|
|
// Compilers: Visual Studio.NET 2003
|
|
// Description: This is authentication functions, this code is not for public release!!
|
|
// -------------------------------------------------------------------------
|
|
// History:
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Timur.
|
|
// This is authentication functions, this code is not for public release!!
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#if defined(LINUX)
|
|
#include <CryLibrary.h>
|
|
#endif
|
|
|
|
#include "DataProbe.h"
|
|
#include "zlib\zlib.h"
|
|
#include "ISystem.h"
|
|
#include "CryFile.h"
|
|
|
|
#include "md5.h"
|
|
//#define FARCRY_EXE_CRC_CHECK
|
|
#if !defined(LINUX)
|
|
extern HMODULE gDLLHandle;
|
|
#endif
|
|
// embedd searchable string.
|
|
//#pragma comment( exestr, "CScriptObjectEntity:...." )
|
|
#define TEST_NAME_END 28
|
|
const char test_name[] = "Cannot find attached entity.\0....";
|
|
|
|
// Check Up to 1 Mb of data.
|
|
#define MAX_PROBE_SIZE uint64(1000000)
|
|
|
|
//#define XOR_VALUE_64 0xB1A72C931C38E5F2
|
|
|
|
#define ADLER_32_BASE 65521L /* largest prime smaller than 65536 */
|
|
#define ADLER_32_NMAX 5552
|
|
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
|
|
|
|
#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
|
|
#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
|
|
#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
|
|
#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
|
|
#define DO16(buf) DO8(buf,0); DO8(buf,8);
|
|
|
|
#define ADLER_32 SpecialFunc1
|
|
#define CRC_32 SpecialFunc2
|
|
#define CRC_64 SpecialFunc3
|
|
|
|
|
|
/* ========================================================================= */
|
|
static unsigned int ADLER_32( unsigned int adler, const char *buf, unsigned int len)
|
|
{
|
|
unsigned int s1 = adler & 0xFFFF;
|
|
unsigned int s2 = (adler >> 16) & 0xFFFF;
|
|
int k;
|
|
|
|
if (!buf)
|
|
return 1L;
|
|
|
|
while (len > 0) {
|
|
k = len < ADLER_32_NMAX ? len : ADLER_32_NMAX;
|
|
len -= k;
|
|
while (k >= 16)
|
|
{
|
|
DO16(buf);
|
|
buf += 16;
|
|
k -= 16;
|
|
}
|
|
if (k != 0) do {
|
|
s1 += *buf++;
|
|
s2 += s1;
|
|
} while (--k);
|
|
s1 %= ADLER_32_BASE;
|
|
s2 %= ADLER_32_BASE;
|
|
}
|
|
return (s2 << 16) | s1;
|
|
}
|
|
|
|
#define AUTODIN_IIREV 0xEDB88320
|
|
#define POLY64REV 0xd800000000000000ULL
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Calculate CRC32 of buffer.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
static unsigned int CRC_32( const char *buf,unsigned int len )
|
|
{
|
|
static unsigned int Table[256];
|
|
static int init = 0;
|
|
unsigned int code = 0xFFFFFFFF;
|
|
|
|
if (!init) {
|
|
int i;
|
|
init = 1;
|
|
for (i = 0; i <= 255; i++) {
|
|
int j;
|
|
unsigned int part = i;
|
|
for (j = 0; j < 8; j++) {
|
|
if (part & 1)
|
|
part = (part >> 1) ^ AUTODIN_IIREV;
|
|
else
|
|
part >>= 1;
|
|
}
|
|
Table[i] = part;
|
|
}
|
|
}
|
|
while (len--)
|
|
{
|
|
unsigned int temp1 = code >> 8;
|
|
unsigned int temp2 = Table[(code ^ (unsigned int )*buf) & 0xff];
|
|
code = temp1 ^ temp2;
|
|
buf += 1;
|
|
}
|
|
return code;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Calculate CRC64 of buffer.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
static uint64 CRC_64( const char *buf,unsigned int len )
|
|
{
|
|
static uint64 Table[256];
|
|
uint64 code = 0;
|
|
static int init = 0;
|
|
|
|
if (!init) {
|
|
int i;
|
|
init = 1;
|
|
for (i = 0; i <= 255; i++) {
|
|
int j;
|
|
uint64 part = i;
|
|
for (j = 0; j < 8; j++) {
|
|
if (part & 1)
|
|
part = (part >> 1) ^ POLY64REV;
|
|
else
|
|
part >>= 1;
|
|
}
|
|
Table[i] = part;
|
|
}
|
|
}
|
|
while (len--)
|
|
{
|
|
uint64 temp1 = code >> 8;
|
|
uint64 temp2 = Table[(code ^ (uint64)*buf) & 0xff];
|
|
code = temp1 ^ temp2;
|
|
buf += 1;
|
|
}
|
|
return code;
|
|
}
|
|
|
|
/*
|
|
void encipher(unsigned int *src,unsigned int *trg,int len,unsigned int *key )
|
|
{
|
|
unsigned int *v = (src), *w = (trg), *k = (key), nlen = (len) >> 3;
|
|
register unsigned int delta=0x9E3779B9,a=k[0],b=k[1],c=k[2],d=k[3];
|
|
while (nlen--) {
|
|
register unsigned int y=v[0],z=v[1],n=32,sum=0;
|
|
while(n-->0) { sum += delta; y += (z << 4)+a ^ z+sum ^ (z >> 5)+b; z += (y << 4)+c ^ y+sum ^ (y >> 5)+d; }
|
|
w[0]=y; w[1]=z;
|
|
v+=2,w+=2;
|
|
}
|
|
}
|
|
|
|
void decipher(unsigned int *src,unsigned int *trg,int len,unsigned int *key )
|
|
{
|
|
unsigned int *v = (src), *w = (trg), *k = (key), nlen = (len) >> 3;
|
|
register unsigned delta=0x9E3779B9,a=k[0],b=k[1],c=k[2],d=k[3];
|
|
while (nlen--) {
|
|
register unsigned int y=v[0],z=v[1],sum=0xC6EF3720,n=32;
|
|
while(n-->0) { z -= (y << 4)+c ^ y+sum ^ (y >> 5)+d; y -= (z << 4)+a ^ z+sum ^ (z >> 5)+b; sum -= delta; }
|
|
w[0]=y; w[1]=z;
|
|
v+=2,w+=2;
|
|
}
|
|
}
|
|
*/
|
|
// src and trg can be the same pointer (in place encryption)
|
|
// len must be in bytes and must be multiple of 8 byts (64bits).
|
|
// key is 128bit: int key[4] = {n1,n2,n3,n4};
|
|
// void encipher(unsigned int *const v,unsigned int *const w,const unsigned int *const k )
|
|
#define TEA_ENCODE( src,trg,len,key ) {\
|
|
register unsigned int *v = (src), *w = (trg), *k = (key), nlen = (len) >> 3; \
|
|
register unsigned int delta=0x9E3779B9,a=k[0],b=k[1],c=k[2],d=k[3]; \
|
|
while (nlen--) {\
|
|
register unsigned int y=v[0],z=v[1],n=32,sum=0; \
|
|
while(n-->0) { sum += delta; y += (z << 4)+a ^ z+sum ^ (z >> 5)+b; z += (y << 4)+c ^ y+sum ^ (y >> 5)+d; } \
|
|
w[0]=y; w[1]=z; v+=2,w+=2; }}
|
|
|
|
// src and trg can be the same pointer (in place decryption)
|
|
// len must be in bytes and must be multiple of 8 byts (64bits).
|
|
// key is 128bit: int key[4] = {n1,n2,n3,n4};
|
|
// void decipher(unsigned int *const v,unsigned int *const w,const unsigned int *const k)
|
|
#define TEA_DECODE( src,trg,len,key ) {\
|
|
register unsigned int *v = (src), *w = (trg), *k = (key), nlen = (len) >> 3; \
|
|
register unsigned int delta=0x9E3779B9,a=k[0],b=k[1],c=k[2],d=k[3]; \
|
|
while (nlen--) { \
|
|
register unsigned int y=v[0],z=v[1],sum=0xC6EF3720,n=32; \
|
|
while(n-->0) { z -= (y << 4)+c ^ y+sum ^ (y >> 5)+d; y -= (z << 4)+a ^ z+sum ^ (z >> 5)+b; sum -= delta; } \
|
|
w[0]=y; w[1]=z; v+=2,w+=2; }}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CDataProbe implementation.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CDataProbe::CDataProbe()
|
|
{
|
|
if (test_name[0]) // Make sure string is linked.
|
|
m_pRandAlloc = 0;
|
|
|
|
m_pRandAlloc = 0;
|
|
|
|
// Add current module. must be CrySystem.dll
|
|
SModuleInfo module;
|
|
module.filename = string("CrySystem")+string(".dll");
|
|
module.handle = (void*)test_name;
|
|
#if !defined(LINUX)
|
|
module.handle = gDLLHandle;
|
|
m_loadedModules.push_back(module);
|
|
#endif
|
|
#ifdef WIN32
|
|
char sPath[_MAX_PATH];
|
|
char dir[_MAX_DIR];
|
|
char drive[_MAX_DRIVE];
|
|
GetModuleFileName( GetModuleHandle(NULL),sPath,sizeof(sPath) );
|
|
_splitpath( sPath,drive,dir,NULL,NULL);
|
|
_makepath( sPath,drive,dir,NULL,NULL);
|
|
m_sBinPath = sPath;
|
|
#endif
|
|
}
|
|
|
|
CDataProbe::~CDataProbe()
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CDataProbe::GetDataCode( char *pBuf,int nSize,SDataProbeContext &ctx )
|
|
{
|
|
uint64 nCode = ((uint64)rand()) | (((uint64)rand())<<16) | (((uint64)rand())<<32) | (((uint64)rand())<<48);
|
|
nCode = 0; //@TODO: Comment out this later, 0 only for debugging.
|
|
|
|
// Hash readed data with choosen algorithm, store result into 64bit nCode.
|
|
switch ((ctx.nCodeInfo) & 7)
|
|
{
|
|
case DATAPROBE_CRC32:
|
|
{
|
|
nCode = CRC_32( pBuf,nSize );
|
|
nCode = nCode | ((~nCode) << 32);
|
|
}
|
|
break;
|
|
case DATAPROBE_CRC64:
|
|
{
|
|
nCode = CRC_64( pBuf,nSize );
|
|
}
|
|
break;
|
|
case DATAPROBE_ADLER32:
|
|
{
|
|
unsigned int code = ADLER_32(0L, 0, 0);
|
|
nCode = ADLER_32( 1,pBuf,ctx.nSize );
|
|
nCode = nCode | ((~nCode) << 32);
|
|
}
|
|
break;
|
|
case DATAPROBE_PURE_CRC32:
|
|
{
|
|
ctx.nCode = CRC_32( pBuf,nSize );
|
|
return true;
|
|
}
|
|
break;
|
|
case DATAPROBE_MD5:
|
|
{
|
|
char md5[16];
|
|
GetMD5( (char*)pBuf,nSize,md5 );
|
|
nCode = *((uint64*)md5);
|
|
return true;
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
nCode = CRC_32( pBuf,nSize );
|
|
nCode = nCode | ((~nCode) << 32);
|
|
}
|
|
}
|
|
// scramble code not to look like crc or alike.
|
|
int tkey[4] = {2985634234,378634893,387681212,436851212};
|
|
TEA_ENCODE( (unsigned int*)&nCode,(unsigned int*)&nCode,8,(unsigned int*)tkey );
|
|
ctx.nCode = nCode;
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
uint32 CDataProbe::GetHash( const char *sString )
|
|
{
|
|
return CRC_32( sString,strlen(sString) );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
uint32 CDataProbe::GetHash( const void *buffer,int len )
|
|
{
|
|
return CRC_32( (const char*)buffer,len );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CDataProbe::GetCode( SDataProbeContext &ctx )
|
|
{
|
|
if (ctx.nSize <= 0)
|
|
return false;
|
|
|
|
if (ctx.pBuffer)
|
|
{
|
|
return GetDataCode( (char*)ctx.pBuffer,ctx.nSize,ctx );
|
|
}
|
|
|
|
// Try to open file and hash it.
|
|
FILE *file = fopen( ctx.sFilename.c_str(),"rb" );
|
|
if (file)
|
|
{
|
|
fseek( file,0,SEEK_END );
|
|
unsigned int nFileSize = ftell(file);
|
|
if (ctx.nOffset >= nFileSize)
|
|
{
|
|
fclose(file);
|
|
return false;
|
|
}
|
|
ctx.nSize = min( ctx.nSize,nFileSize-ctx.nOffset );
|
|
|
|
if (fseek( file,ctx.nOffset,SEEK_SET ) != 0)
|
|
{
|
|
fclose( file );
|
|
return false;
|
|
}
|
|
char *pBuf = (char*)malloc( ctx.nSize );
|
|
if (fread( pBuf,ctx.nSize,1,file ) != 1)
|
|
{
|
|
free( pBuf );
|
|
fclose(file);
|
|
return false;
|
|
}
|
|
|
|
// Hash readed data with choosen algorithm, store result into 64bit nCode.
|
|
bool bOk = GetDataCode( pBuf,ctx.nSize,ctx );
|
|
|
|
free( pBuf );
|
|
fclose(file);
|
|
|
|
return bOk;
|
|
}
|
|
else
|
|
{
|
|
// Real file on disk not found... so check against one in the pak.
|
|
// Try to open file and hash it.
|
|
CCryFile cryfile;
|
|
if (cryfile.Open( ctx.sFilename.c_str(),"rb" ))
|
|
{
|
|
unsigned int nFileSize = cryfile.GetLength();
|
|
if (ctx.nOffset >= nFileSize)
|
|
{
|
|
return false;
|
|
}
|
|
ctx.nSize = min( ctx.nSize,nFileSize-ctx.nOffset );
|
|
|
|
if (cryfile.Seek( ctx.nOffset,SEEK_SET ) != 0)
|
|
{
|
|
return false;
|
|
}
|
|
char *pBuf = (char*)malloc( ctx.nSize );
|
|
if (cryfile.Read( pBuf,ctx.nSize ) != ctx.nSize)
|
|
{
|
|
free( pBuf );
|
|
return false;
|
|
}
|
|
|
|
// Hash readed data with choosen algorithm, store result into 64bit nCode.
|
|
bool bOk = GetDataCode( pBuf,ctx.nSize,ctx );
|
|
|
|
free( pBuf );
|
|
|
|
return bOk;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
inline int64 GetRandom( int64 nRange )
|
|
{
|
|
return (int64(nRange) * int64(rand())) / RAND_MAX;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CDataProbe::GetRandomFileProbe( SDataProbeContext &ctx,bool bAtEnd )
|
|
{
|
|
// Try to open file and hash it.
|
|
FILE *file = fopen( ctx.sFilename.c_str(),"rb" );
|
|
if (file)
|
|
{
|
|
fseek( file,0,SEEK_END );
|
|
int64 nFileSize = ftell(file);
|
|
|
|
// Choose any random size.
|
|
int64 nOffset = 0;
|
|
int64 nSize = GetRandom( MAX_PROBE_SIZE ) + 100;
|
|
if (bAtEnd)
|
|
{
|
|
// Prefare probe near the file end.
|
|
nSize = min( nSize,nFileSize-1 );
|
|
// Choose offset.
|
|
nOffset = nFileSize - nSize - GetRandom( 1000 );
|
|
}
|
|
else
|
|
{
|
|
nOffset = GetRandom( nFileSize - nSize );
|
|
|
|
if (nFileSize < MAX_PROBE_SIZE)
|
|
{
|
|
// Choose small random offset from both sides.
|
|
int nOffset1 = 0;
|
|
int nOffset2 = 0;
|
|
do {
|
|
nOffset1 = GetRandom( 1000 );
|
|
nOffset2 = GetRandom( 1000 );
|
|
} while (nOffset1+nOffset2 >= nFileSize+1);
|
|
nOffset = nOffset1;
|
|
nSize = nFileSize - nOffset2 - nOffset1;
|
|
}
|
|
}
|
|
|
|
if (nOffset < 0)
|
|
nOffset = 0;
|
|
if (nSize < 0)
|
|
nSize = nFileSize;
|
|
|
|
ctx.nSize = nSize;
|
|
ctx.nOffset = nOffset;
|
|
|
|
fclose(file);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CDataProbe::RandSeed( uint32 seed )
|
|
{
|
|
m_rand.Seed( seed );
|
|
}
|
|
|
|
uint32 CDataProbe::GetRand()
|
|
{
|
|
return m_rand.Rand();
|
|
}
|
|
|
|
float CDataProbe::GetRand( float fMin,float fMax )
|
|
{
|
|
return m_rand.Rand( fMin,fMax );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Timur.
|
|
// This is FarCry.exe authentication function, this code is not for public release!!
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CDataProbe::CheckLoader( void *pFunc )
|
|
{
|
|
const char *sKey = "Timur Davidenko";
|
|
typedef void (*AuthFunction)( void *data );
|
|
AuthFunction pCheckFunc = (AuthFunction)pFunc;
|
|
|
|
unsigned int data1[8];
|
|
unsigned int data2[8];
|
|
memcpy( data1,sKey,8 );
|
|
|
|
#ifdef FARCRY_EXE_CRC_CHECK
|
|
// Comment out after alpha master.
|
|
if (!CheckLoaderFC())
|
|
{
|
|
int *p = 0;
|
|
*p = 1;
|
|
return false;
|
|
}
|
|
#endif // FARCRY_EXE_CRC_CHECK
|
|
|
|
// data1 is filled with 32 bytes of random data.
|
|
// It is then encrypted with key1 and send to supplied check function.
|
|
// Function is supposed to uncrypt the data, and encrypt it again with key2.
|
|
// when function returns we should be able to uncrypt the data with key2 and compare with original.
|
|
// if it fails, we possibly running from the not authorized loader.
|
|
|
|
// set of keys (one for farcry.exe second for dedicated server).
|
|
int keys[6][4] = {
|
|
{1873613783,235688123,812763783,1745863682},
|
|
{1897178562,734896899,156436554,902793442},
|
|
{1178362782,223786232,371615531,90884141},
|
|
{89158165, 1389745433,971685123,785741042},
|
|
{389623487,373673863,657846392,378467832},
|
|
{1982697467,3278962783,278963782,287678311},
|
|
};
|
|
|
|
m_rand.Seed( GetTickCount() );
|
|
// Data assumed to be 32 bytes (8 ints).
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
data1[i] = m_rand.Rand();
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// First try... key0,key1
|
|
//////////////////////////////////////////////////////////////////////////
|
|
TEA_ENCODE( data1,data2,32,(unsigned int*)keys[0] );
|
|
pCheckFunc( data2 );
|
|
TEA_DECODE( data2,data2,32,(unsigned int*)keys[1] );
|
|
|
|
// Now check data1 and data2.
|
|
if (memcmp( data1,data2,32 ) == 0)
|
|
{
|
|
// Authentication passed.
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Second try... key2,key3
|
|
//////////////////////////////////////////////////////////////////////////
|
|
TEA_ENCODE( data1,data2,32,(unsigned int*)keys[2] );
|
|
pCheckFunc( data2 );
|
|
TEA_DECODE( data2,data2,32,(unsigned int*)keys[3] );
|
|
|
|
// Now check data1 and data2.
|
|
if (memcmp( data1,data2,32 ) == 0)
|
|
{
|
|
// Authentication passed.
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Third try... key4,key5
|
|
//////////////////////////////////////////////////////////////////////////
|
|
TEA_ENCODE( data1,data2,32,(unsigned int*)keys[4] );
|
|
pCheckFunc( data2 );
|
|
TEA_DECODE( data2,data2,32,(unsigned int*)keys[5] );
|
|
|
|
// Now check data1 and data2.
|
|
if (memcmp( data1,data2,32 ) == 0)
|
|
{
|
|
// Authentication passed.
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CDataProbe::CheckLoaderFC()
|
|
{
|
|
#ifdef FARCRY_EXE_CRC_CHECK
|
|
// Open exe file.
|
|
CCryFile file;
|
|
|
|
// crysystem.dll
|
|
string fsysname = string("c")+"r"+"y"+"s"+"y"+"s"+"t"+"e"+"m"+"."+"d"+"l"+"l";
|
|
// farcry.exe
|
|
string fcname = string("f")+"a"+"r"+"c"+"r"+"y"+"."+"e"+"x"+"e";
|
|
|
|
if (!file.Open( (m_sBinPath + fsysname).c_str(),"rb" ))
|
|
return false;
|
|
|
|
int nLen = file.GetLength();
|
|
char *pBuffer = new char[nLen+16];
|
|
file.Read( pBuffer,nLen );
|
|
// find embedded string.
|
|
|
|
int nStrLen = strlen(test_name)+1;
|
|
CryLogAlways( "Len=%d",nStrLen );
|
|
//nStrLen = TEST_NAME_END;
|
|
unsigned int nStoredCode = 0;
|
|
memcpy( &nStoredCode,test_name+nStrLen,sizeof(nStoredCode) );
|
|
|
|
bool bFound = false;
|
|
unsigned int nCode = 0;
|
|
|
|
for (int i = 0; i < nLen-nStrLen-32; i++)
|
|
{
|
|
if (memcmp(pBuffer+i,test_name,nStrLen) == 0)
|
|
{
|
|
// Found!
|
|
// Read code.
|
|
memcpy( &nStoredCode,pBuffer+i+nStrLen,sizeof(nCode) );
|
|
bFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bFound)
|
|
return false;
|
|
|
|
// Now compare code to the farcry.exe.
|
|
SDataProbeContext ctx;
|
|
ctx.nCodeInfo = DATAPROBE_PURE_CRC32;
|
|
ctx.sFilename = m_sBinPath + fcname;
|
|
ctx.nSize = 10000000;
|
|
if (!GetCode(ctx))
|
|
return false;
|
|
|
|
unsigned int nCurrentCode = ctx.nCode; // Invert of CRC32
|
|
|
|
nCurrentCode = ~nCurrentCode; // Invert of CRC32
|
|
|
|
// Codes must match.
|
|
if (nCurrentCode != nStoredCode)
|
|
return false;
|
|
|
|
delete []pBuffer;
|
|
|
|
#endif // FARCRY_EXE_CRC_CHECK
|
|
CryLogComment( "Init Loader" );
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int CDataProbe::Compress( void *dest,unsigned int &destLen,const void *source, unsigned int sourceLen,int level )
|
|
{
|
|
unsigned long dlen = destLen;
|
|
int res = ::compress2( (Bytef*)dest,&dlen,(const Bytef*)source,sourceLen,level );
|
|
destLen = dlen;
|
|
return res;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int CDataProbe::Uncompress( void *dest,unsigned int &destLen,const void *source, unsigned int sourceLen )
|
|
{
|
|
unsigned long dlen = destLen;
|
|
int res = ::uncompress( (Bytef*)dest,&dlen,(const Bytef*)source,sourceLen );
|
|
destLen = dlen;
|
|
return res;
|
|
}
|
|
|
|
void CDataProbe::RandomAlloc()
|
|
{
|
|
#ifndef _DEBUG
|
|
RandSeed( GetTickCount() );
|
|
m_pRandAlloc = malloc( (GetRand() & 0xFFF) ); // do a random allocation to make debugging harder.
|
|
#endif
|
|
}
|
|
|
|
#if !defined(LINUX)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Get address of executable code RAM for loaded DLL or EXE.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
static void GetModuleCodeAddress( void *base,void **pCodeStartAddress,int *nCodeSize )
|
|
{
|
|
const IMAGE_DOS_HEADER *dos_head = (IMAGE_DOS_HEADER*)base;
|
|
|
|
assert(base);
|
|
assert(pCodeStartAddress);
|
|
assert(nCodeSize);
|
|
|
|
*pCodeStartAddress = 0;
|
|
*nCodeSize = 0;
|
|
|
|
#include <pshpack1.h> // no padding.
|
|
const struct PEHeader
|
|
{
|
|
DWORD signature;
|
|
IMAGE_FILE_HEADER _head;
|
|
IMAGE_OPTIONAL_HEADER opt_head;
|
|
IMAGE_SECTION_HEADER *section_header; // actual number in NumberOfSections
|
|
}
|
|
*header;
|
|
#include <poppack.h>
|
|
|
|
if (dos_head->e_magic != IMAGE_DOS_SIGNATURE)
|
|
{
|
|
// Wrong pointer, not to PE header.
|
|
return;
|
|
}
|
|
// verify DOS-EXE-Header
|
|
// after end of DOS-EXE-Header: offset to PE-Header
|
|
header = (PEHeader*)(const void *)((char *)dos_head + dos_head->e_lfanew);
|
|
|
|
if (IsBadReadPtr(header, sizeof(*header))) // start of PE-Header
|
|
{
|
|
// (no PE header, probably DOS executable)
|
|
return;
|
|
}
|
|
|
|
/*
|
|
CryLog( "[CodeModule] base: %x",base );
|
|
CryLog( "[CodeModule] base of code: %x",header->opt_head.BaseOfCode );
|
|
CryLog( "[CodeModule] size of code: %x",header->opt_head.SizeOfCode );
|
|
*/
|
|
|
|
void *pCodeAddress = (char*)base + header->opt_head.BaseOfCode;
|
|
if (IsBadReadPtr(pCodeAddress, header->opt_head.SizeOfCode ))
|
|
{
|
|
// Something wrong..., cant read code memory, skip it.
|
|
return;
|
|
}
|
|
*pCodeStartAddress = pCodeAddress;
|
|
*nCodeSize = header->opt_head.SizeOfCode;
|
|
|
|
/*
|
|
{
|
|
int sect;
|
|
const IMAGE_SECTION_HEADER *section_header;
|
|
for (sect = 0, section_header = header->section_header; sect < header->_head.NumberOfSections; sect++, section_header++)
|
|
{
|
|
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
#endif //LINUX
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CDataProbe::GetRandomModuleProbe( SDataProbeContext &ctx )
|
|
{
|
|
#ifndef WIN32
|
|
return false; // Not WIN32
|
|
#else // WIN32
|
|
if (!ctx.pModuleBaseAddress)
|
|
{
|
|
// Try to find module handle from filename.
|
|
HMODULE hModule = GetModuleHandle( ctx.sFilename.c_str() );
|
|
if (!hModule)
|
|
return false;
|
|
ctx.pModuleBaseAddress = hModule;
|
|
}
|
|
|
|
void *pCodeAddress = 0;
|
|
int nCodeSize = 0;
|
|
// Get code sections pointers.
|
|
GetModuleCodeAddress( ctx.pModuleBaseAddress,&pCodeAddress,&nCodeSize );
|
|
if (!pCodeAddress || nCodeSize == 0)
|
|
return false;
|
|
|
|
// Choose small random offset from both sides.
|
|
int nOffset1 = 0;
|
|
int nOffset2 = 0;
|
|
do {
|
|
nOffset1 = GetRandom( 1000 );
|
|
nOffset2 = GetRandom( 1000 );
|
|
} while (nOffset1+nOffset2 >= nCodeSize+1);
|
|
|
|
ctx.pBuffer = pCodeAddress;
|
|
ctx.nOffset = nOffset1;
|
|
ctx.nSize = nCodeSize - nOffset1 - nOffset2;
|
|
if (IsBadReadPtr( (char*)pCodeAddress+nOffset1,ctx.nSize))
|
|
{
|
|
// Something wrong..., cant read code memory, skip it.
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Write this to file....
|
|
CryLog( "[CodeModule] %s, base: %x",ctx.sFilename.c_str(),ctx.pModuleBaseAddress );
|
|
char *pBuf = (char*)malloc(ctx.nSize + 128);
|
|
memset(pBuf,0,ctx.nSize+64);
|
|
memcpy(pBuf,(char*)ctx.pBuffer+ctx.nOffset,ctx.nSize);
|
|
FILE *file;
|
|
if (!GetISystem()->IsDedicated())
|
|
file = fopen( (ctx.sFilename+".client_code").c_str(),"wb" );
|
|
else
|
|
file = fopen( (ctx.sFilename+".server_code").c_str(),"wb" );
|
|
fwrite( pBuf,ctx.nSize,1,file );
|
|
fclose(file);
|
|
|
|
unsigned int nCode = CRC_32( pBuf,ctx.nSize );
|
|
CryLog( "Code CRC32=%u, offset=%d,size=%d",nCode,ctx.nOffset,ctx.nSize );
|
|
free(pBuf);
|
|
//////////////////////////////////////////////////////////////////////////
|
|
*/
|
|
|
|
return true;
|
|
#endif //WIN32
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CDataProbe::GetModuleProbe( SDataProbeContext &ctx )
|
|
{
|
|
#ifndef WIN32
|
|
return false; // Not WIN32
|
|
#else // WIN32
|
|
if (!ctx.pModuleBaseAddress)
|
|
{
|
|
// Try to find module handle from filename.
|
|
HMODULE hModule = GetModuleHandle( ctx.sFilename.c_str() );
|
|
if (!hModule)
|
|
return false;
|
|
ctx.pModuleBaseAddress = hModule;
|
|
}
|
|
|
|
void *pCodeAddress = 0;
|
|
int nCodeSize = 0;
|
|
// Get code sections pointers.
|
|
GetModuleCodeAddress( ctx.pModuleBaseAddress,&pCodeAddress,&nCodeSize );
|
|
if (!pCodeAddress || nCodeSize == 0)
|
|
return false;
|
|
|
|
ctx.pBuffer = pCodeAddress;
|
|
if (IsBadReadPtr( (char*)pCodeAddress+ctx.nOffset,ctx.nSize))
|
|
{
|
|
// Something wrong..., cant read code memory, skip it.
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Write this to file....
|
|
CryLog( "[CodeModule] %s, base: %x",ctx.sFilename.c_str(),ctx.pModuleBaseAddress );
|
|
char *pBuf = (char*)malloc(ctx.nSize + 128);
|
|
memset(pBuf,0,ctx.nSize+64);
|
|
memcpy(pBuf,(char*)ctx.pBuffer+ctx.nOffset,ctx.nSize);
|
|
FILE *file;
|
|
if (!GetISystem()->IsDedicated())
|
|
file = fopen( (ctx.sFilename+".client_code").c_str(),"wb" );
|
|
else
|
|
file = fopen( (ctx.sFilename+".server_code").c_str(),"wb" );
|
|
fwrite( pBuf,ctx.nSize,1,file );
|
|
fclose(file);
|
|
|
|
unsigned int nCode = CRC_32( pBuf,ctx.nSize );
|
|
CryLog( "Code CRC32=%u, offset=%d,size=%d",nCode,ctx.nOffset,ctx.nSize );
|
|
free(pBuf);
|
|
//////////////////////////////////////////////////////////////////////////
|
|
*/
|
|
|
|
|
|
return true;
|
|
#endif //WIN32
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int CDataProbe::GetLoadedModules( SModuleInfo **pModules )
|
|
{
|
|
*pModules = 0;
|
|
int numModules = m_loadedModules.size();
|
|
if (numModules > 0)
|
|
{
|
|
*pModules = &m_loadedModules[0];
|
|
}
|
|
return numModules;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CDataProbe::AddModule( SModuleInfo &moduleInfo )
|
|
{
|
|
m_loadedModules.push_back(moduleInfo);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CDataProbe::AESDecryptBuffer( const char *pSrcBuffer,int nSrcSize,char *pDestBuffer,int &nDestSize,const char *sKey )
|
|
{
|
|
nDestSize = nSrcSize;
|
|
memcpy( pDestBuffer,pSrcBuffer,nSrcSize );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CDataProbe::GetMD5( const char *pSrcBuffer,int nSrcSize,char signatureMD5[16] )
|
|
{
|
|
//#if !defined(LINUX)
|
|
struct MD5Context md5c;
|
|
MD5Init(&md5c);
|
|
MD5Update(&md5c, (unsigned char*)pSrcBuffer,nSrcSize );
|
|
MD5Final( (unsigned char*)signatureMD5, &md5c);
|
|
//#endif
|
|
}
|
|
|