l2-unlegits/l2packets/pcode_obfuscator/L2PCodeObfuscator.cpp
2012-02-01 05:25:08 +00:00

304 lines
8.5 KiB
C++

#include "stdafx.h"
#include "L2PCodeObfuscator.h"
#ifdef L2P_THROW
#include "../xcpt/L2Packets_xcpt.h"
#endif
L2PCodeObfuscator::L2PCodeObfuscator()
{
m_version = L2_VERSION_T1;
m_DecodeTable1 = m_DecodeTable2 = m_DecodeTable3 = NULL;
m_EncodeTable1 = m_EncodeTable2 = m_EncodeTable3 = NULL;
m_s1 = m_s2 = m_s3 = 0;
m_seed = 0;
m_enabled = 0;
}
L2PCodeObfuscator::~L2PCodeObfuscator()
{
clear();
}
void L2PCodeObfuscator::clear()
{
if( m_DecodeTable1 ) free( m_DecodeTable1 );
if( m_DecodeTable2 ) free( m_DecodeTable2 );
if( m_DecodeTable3 ) free( m_DecodeTable3 );
if( m_EncodeTable1 ) free( m_EncodeTable1 );
if( m_EncodeTable2 ) free( m_EncodeTable2 );
if( m_EncodeTable3 ) free( m_EncodeTable3 );
m_version = L2_VERSION_T1;
m_DecodeTable1 = m_DecodeTable2 = m_DecodeTable3 = NULL;
m_EncodeTable1 = m_EncodeTable2 = m_EncodeTable3 = NULL;
m_s1 = m_s2 = m_s3 = 0;
m_seed = 0;
m_enabled = 0;
}
void L2PCodeObfuscator::pseudo_srand( unsigned int seed )
{
m_seed = seed;
}
unsigned int L2PCodeObfuscator::pseudo_rand()
{
unsigned int a;
a = ( m_seed * 0x343fd + 0x269EC3 ) & 0xFFFFFFFF;
m_seed = a;
unsigned int result = ( m_seed >> 0x10 ) & 0x7FFF;
return result;
}
void L2PCodeObfuscator::init_tables( unsigned int seed )
{
unsigned int i = 0;
unsigned char tmp = 0;
unsigned int pos;
unsigned int cpos;
m_s1 = 0xD0;
m_s2 = 0x4E; // T1.5 Hellbound
m_s3 = 0x64; // O_o
/* if gSys.Protocol = 871 then _init_tables(GInt(_dBuff, $16, 4), $58); // CT2.2
if gSys.Protocol = 851 then _init_tables(GInt(_dBuff, $16, 4), $55); // CT2
if gSys.Protocol = 831 then _init_tables(GInt(_dBuff, $16, 4), $4E); // CT1.5+ */
if( m_version == L2_VERSION_T2 ) m_s2 = 0x55; // T2 Gracia Part 1
if( m_version == L2_VERSION_T22 ) m_s2 = 0x58; // T2.2 Gracia Part 2
if( m_version == L2_VERSION_T23 ) m_s2 = 0x63; // T2.3 Gracia Final // TODO: length
if( m_DecodeTable1 ) free( m_DecodeTable1 );
if( m_DecodeTable2 ) free( m_DecodeTable2 );
if( m_DecodeTable3 ) free( m_DecodeTable3 );
m_DecodeTable1 = (unsigned char *)malloc( sizeof(unsigned char) * (m_s1 + 1) );
m_DecodeTable2 = (unsigned char *)malloc( sizeof(unsigned char) * (m_s2 + 1) );
m_DecodeTable3 = (unsigned char *)malloc( sizeof(unsigned char) * (m_s3 + 1) );
for( i = 0; i <= m_s1; i++ ) m_DecodeTable1[i] = (unsigned char)i;
for( i = 0; i <= m_s2; i++ ) m_DecodeTable2[i] = (unsigned char)i;
for( i = 0; i <= m_s3; i++ ) m_DecodeTable3[i] = (unsigned char)i;
this->pseudo_srand( seed );
// mix 1-byte opcode table
for( i = 1; i <= m_s1; i++ )
{
pos = this->pseudo_rand() % (i + 1);
// swap bytes at indexes [pos] and [i] in DecodeTable1
tmp = m_DecodeTable1[pos];
m_DecodeTable1[pos] = m_DecodeTable1[i];
m_DecodeTable1[i] = tmp;
}
// mix 2-byte opcode table
for( i = 1; i <= m_s2; i++ )
{
pos = this->pseudo_rand() % (i + 1);
// swap bytes at indexes [pos] and [i] in DecodeTable2
tmp = m_DecodeTable2[pos];
m_DecodeTable2[pos] = m_DecodeTable2[i];
m_DecodeTable2[i] = tmp;
}
cpos = 0;
while( m_DecodeTable1[cpos] != 0x12 ) cpos++;
tmp = m_DecodeTable1[0x12];
m_DecodeTable1[0x12] = 0x12;
m_DecodeTable1[cpos] = tmp;
cpos = 0;
while( m_DecodeTable1[cpos] != 0xB1 ) cpos++;
tmp = m_DecodeTable1[0xB1];
m_DecodeTable1[0xB1] = 0xB1;
m_DecodeTable1[cpos] = tmp;
m_EncodeTable1 = (unsigned char *)malloc( sizeof(unsigned char) * (m_s1 + 1) );
m_EncodeTable2 = (unsigned char *)malloc( sizeof(unsigned char) * (m_s2 + 1) );
m_EncodeTable3 = (unsigned char *)malloc( sizeof(unsigned char) * (m_s3 + 1) );
for( i = 0; i <= m_s1; i++ ) m_EncodeTable1[ m_DecodeTable1[i] ] = (unsigned char)i;
for( i = 0; i <= m_s2; i++ ) m_EncodeTable2[ m_DecodeTable2[i] ] = (unsigned char)i;
for( i = 0; i <= m_s3; i++ ) m_EncodeTable3[ m_DecodeTable3[i] ] = (unsigned char)i;
m_enabled = 1;
}
int L2PCodeObfuscator::decodeIDs( unsigned char *packet_data_raw )
{
if( !packet_data_raw ) return 0;
unsigned char *data = packet_data_raw;
int ofs = 2; // offset of packet ID in raw data
int ret_val = 0;
if( m_DecodeTable1 )
{
if( data[ofs] > m_s1 )
{
#ifdef L2P_THROW
throw L2P_DeObfuscateException( m_s1, data[ofs], -1 );
#else
return -1;
#endif
}
else data[ofs] = m_DecodeTable1[ data[ofs] ];
ret_val = 1;
if( data[ofs] == 0xD0 ) // double-byte packet
{
ret_val = 2;
if( data[ofs + 1] > m_s2 )
{
#ifdef L2P_THROW
throw L2P_DeObfuscateException( m_s2, data[ofs + 1], -2 );
#else
return -2;
#endif
}
else data[ofs + 1] = m_DecodeTable2[ data[ofs + 1] ];
}
}
return ret_val;
}
int L2PCodeObfuscator::encodeIDs( unsigned char *packet_data_raw )
{
if( !packet_data_raw ) return 0;
unsigned char *data = packet_data_raw;
int ofs = 2; // offset of packet ID in raw data (ofs+1 is position of extended opcode)
int ret_val = 0;
if( m_EncodeTable1 )
{
unsigned char prev_opcode = data[ofs]; // opcode BEFORE obfuscation
if( data[ofs] > m_s1 ) // m_s1 is a valid index in table (allocated as m_s1+1)
{
#ifdef L2P_THROW
throw L2P_ObfuscateException( m_s1, data[ofs], -1 );
#else
return -1;
#endif
}
else data[ofs] = m_EncodeTable1[ data[ofs] ];
ret_val = 1;
if( prev_opcode == 0xD0 ) // this is a double-byte packet - obfuscate second (ext) opcode
{
ret_val = 2;
if( data[ofs + 1] > m_s2 )
{
#ifdef L2P_THROW
throw L2P_ObfuscateException( m_s2, data[ofs + 1], -2 );
#else
return -2;
#endif
}
else data[ofs + 1] = m_EncodeTable2[ data[ofs + 1] ];
}
}
return ret_val;
}
bool L2PCodeObfuscator::decodeOpcode( unsigned char &singleOpcode, unsigned short &doubleOpcode )
{
unsigned short tripleOpcode = 0;
return decodeOpcode( singleOpcode, doubleOpcode, tripleOpcode );
}
bool L2PCodeObfuscator::encodeOpcode( unsigned char &singleOpcode, unsigned short &doubleOpcode )
{
unsigned short tripleOpcode = 0;
return encodeOpcode( singleOpcode, doubleOpcode, tripleOpcode );
}
bool L2PCodeObfuscator::decodeOpcode( unsigned char &singleOpcode, unsigned short &doubleOpcode, unsigned short &tripleOpcode )
{
unsigned char prev_singleOpcode = singleOpcode;
unsigned short prev_doubleOpcode = doubleOpcode;
if( singleOpcode > m_s1 )
{
#ifdef L2P_THROW
throw L2P_DeObfuscateException( m_s1, singleOpcode, -1 );
#else
return false;
#endif
}
singleOpcode = m_DecodeTable1[ singleOpcode ];
if( singleOpcode == 0xD0 ) // D0:xx
{
if( doubleOpcode > m_s2 )
{
singleOpcode = prev_singleOpcode; // restore prev. opcodes
#ifdef L2P_THROW
throw L2P_DeObfuscateException( m_s2, doubleOpcode, -2 );
#else
return false;
#endif
}
doubleOpcode = (unsigned short)m_DecodeTable2[ doubleOpcode ];
// TODO: Gracia Final triple opcodes
if( m_version == L2_VERSION_T23 )
{
if( doubleOpcode == 0x51 ) // D0:51:xx
{
if( tripleOpcode > m_s3 )
{
singleOpcode = prev_singleOpcode; // restore prev. opcodes
doubleOpcode = prev_doubleOpcode; // restore prev. opcodes
#ifdef L2P_THROW
throw L2P_DeObfuscateException( m_s3, tripleOpcode, -3 );
#else
return false;
#endif
}
tripleOpcode = (unsigned short)m_DecodeTable3[ tripleOpcode ];
}
}
}
return true;
}
bool L2PCodeObfuscator::encodeOpcode( unsigned char &singleOpcode, unsigned short &doubleOpcode, unsigned short &tripleOpcode )
{
unsigned char prev_singleOpcode = singleOpcode;
unsigned short prev_doubleOpcode = doubleOpcode;
if( singleOpcode > m_s1 )
{
#ifdef L2P_THROW
throw L2P_ObfuscateException( m_s1, singleOpcode, -1 );
#else
return false;
#endif
}
singleOpcode = m_EncodeTable1[ singleOpcode ];
if( prev_singleOpcode == 0xD0 ) // D0:xx
{
if( doubleOpcode > m_s2 )
{
singleOpcode = prev_singleOpcode; // restore prev. opcode
#ifdef L2P_THROW
throw L2P_ObfuscateException( m_s2, doubleOpcode, -2 );
#else
return false;
#endif
}
doubleOpcode = (unsigned short)m_EncodeTable2[ doubleOpcode ];
// TODO: Gracia Final triple opcodes
if( m_version == L2_VERSION_T23 )
{
if( prev_doubleOpcode == 0x51 ) // D0:51:xx
{
if( tripleOpcode > m_s3 )
{
singleOpcode = prev_singleOpcode; // restore prev. opcode
doubleOpcode = prev_doubleOpcode; // restore prev. opcode
#ifndef L2P_THROW
throw L2P_ObfuscateException( m_s3, tripleOpcode, -3 );
#else
return false;
#endif
}
tripleOpcode = (unsigned short)m_EncodeTable3[ tripleOpcode ];
}
}
}
return true;
}