Files
l2-unlegits/l2packets/login/server/L2Login_Init.cpp
2012-02-01 05:25:08 +00:00

301 lines
9.5 KiB
C++

#include "stdafx.h"
#include "L2Login_Init.h"
L2Login_Init::L2Login_Init()
{
_initNull();
_initPublicMembers();
}
L2Login_Init::L2Login_Init( const unsigned char *bytes, unsigned int length )
{
_initNull();
_initPublicMembers();
this->setBytes( bytes, length );
}
bool L2Login_Init::decodeXOR()
{
unsigned int blen = getPacketSize();
unsigned char *packet = b.getBytesPtr();
if( blen < 1 || !packet ) return false; // TODO: throw?
if( blen < 186 ) return false; // TODO: throw?
// get xor key
// XOR key position to the left from End-of-packet
unsigned int xor_offset = 8;
xor_key = 0;
unsigned char b = 0;
b = packet[ blen - xor_offset ];
xor_key |= (unsigned int)b;
b = packet[ blen - xor_offset + 1 ];
xor_key |= ( (unsigned int)b << 8 );
b = packet[ blen - xor_offset + 2 ];
xor_key |= ( (unsigned int)b << 16 );
b = packet[ blen - xor_offset + 3 ];
xor_key |= ( (unsigned int)b << 24 );
// enc xor?
unsigned int offset = 2;
unsigned int edx = 0;
unsigned int ecx = xor_key;
offset = blen - xor_offset - 4;
while( offset > 2 ) // offset > 3 ?
{
edx = (packet[offset+0] & 0xFF);
edx |= (packet[offset+1] & 0xFF) << 8;
edx |= (packet[offset+2] & 0xFF) << 16;
edx |= (packet[offset+3] & 0xFF) << 24;
edx ^= ecx;
ecx -= edx;
packet[offset+0] = (unsigned char)((edx) & 0xFF);
packet[offset+1] = (unsigned char)((edx >> 8) & 0xFF);
packet[offset+2] = (unsigned char)((edx >> 16) & 0xFF);
packet[offset+3] = (unsigned char)((edx >> 24) & 0xFF);
offset -= 4;
}
return true;
}
// static function used to decrypt RSA public key modulus from Init packet
// data must be 128-byte long array
bool L2Login_Init::unscramble_RSA_PubKeyMod( unsigned char *data )
{
int i;
// step 4 xor last 0x40 bytes with first 0x40 bytes
for( i=0; i<0x40; i++ )
data[0x40 + i] = (unsigned char)(data[0x40 + i] ^ data[i]);
// step 3 xor bytes 0x0d-0x10 with bytes 0x34-0x38
for( i=0; i<4; i++ )
data[0x0d + i] = (unsigned char)(data[0x0d + i] ^ data[0x34 + i]);
// step 2 xor first 0x40 bytes with last 0x40 bytes
for( i=0; i<0x40; i++ )
data[i] = (unsigned char)(data[i] ^ data[0x40 + i]);
// step 1
for( i=0; i<4; i++ )
{
unsigned char temp = data[0x00 + i];
data[0x00 + i] = data[0x4d + i];
data[0x4d + i] = temp;
}
return true;
}
bool L2Login_Init::scramble_RSA_PubKeyMod( unsigned char *data )
{
int i;
for( i=0; i<4; i++ )
{
unsigned char temp = data[0x00 + i];
data[0x00 + i] = data[0x4d + i];
data[0x4d + i] = temp;
}
// step 2 xor first 0x40 bytes with last 0x40 bytes
for( i=0; i<0x40; i++ )
data[i] = (unsigned char)(data[i] ^ data[0x40 + i]);
// step 3 xor bytes 0x0d-0x10 with bytes 0x34-0x38
for( i=0; i<4; i++ )
data[0x0d + i] = (unsigned char)(data[0x0d + i] ^ data[0x34 + i]);
// step 4 xor last 0x40 bytes with first 0x40 bytes
for( i=0; i<0x40; i++ )
data[0x40 + i] = (unsigned char)(data[0x40 + i] ^ data[i]);
return true;
}
bool L2Login_Init::read_SessionID( unsigned char *sidBytes )
{
if( !sidBytes ) return false;
if( !canReadBytes( 4 ) ) return false;
this->readReset();
this->readChar(); // pass packet type
sidBytes[0] = this->readUChar();
sidBytes[1] = this->readUChar();
sidBytes[2] = this->readUChar();
sidBytes[3] = this->readUChar();
return true;
}
unsigned int L2Login_Init::read_ProtoVer()
{
unsigned int ret = 0;
ret = this->readUInt();
return ret;
}
// RSApublicKeyMod must point to buffer 128 bytes len
bool L2Login_Init::read_RSA_pubKeyMod( unsigned char *RSApublicKeyMod )
{
if( !RSApublicKeyMod ) return false;
if( !canReadBytes(128) ) return false;
int i = 0;
while( i < 128 ) RSApublicKeyMod[i++] = readUChar();
return true;
}
// ggShit - 16 bytes buffer; can be NULL
bool L2Login_Init::read_GGShit( unsigned char *ggShit )
{
if( !canReadBytes( 16 ) ) return false;
int i = 0;
char c = 0;
while( i < 16 )
{
c = this->readUChar();
if( ggShit ) ggShit[i] = c;
i++;
}
return true;
}
// newBFKey - 16 bytes buffer; can NOT be NULL
bool L2Login_Init::read_DynamicBFKey( unsigned char *newBFKey )
{
if( !newBFKey ) return false;
if( !canReadBytes(16) ) return false;
int i = 0;
while( i < 16 ) newBFKey[i++] = this->readUChar();
return true;
}
void L2Login_Init::displaySelfNice( FILE *f )
{
fprintf( f, "L2Login_Init: displaying self\n" );
if( this->getPacketSize() != 186 )
{
fprintf( f, "L2Login_Init: this is not standard Interlude Init packet! (wrong size)\n" );
this->dumpToFile( stdout );
return;
}
char ptype = this->getPacketType();
if( ptype != 0 )
{
fprintf( f, "L2Login_Init: this is not standard Interlude Init packet! (wrong packet type)\n" );
this->dumpToFile( stdout );
}
// vars
unsigned char sidBytes[4] = {0,0,0,0};
unsigned int protoRev = 0;
unsigned char RSA_pubKeyMod[128];
unsigned char GG_Shit[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
unsigned char dyn_BF_key[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
unsigned char nullTerm = 0;
// memsets
memset( RSA_pubKeyMod, 0, sizeof(RSA_pubKeyMod) );
// read ...
this->read_SessionID( sidBytes );
protoRev = this->read_ProtoVer();
this->read_RSA_pubKeyMod( RSA_pubKeyMod );
this->read_GGShit( GG_Shit );
this->read_DynamicBFKey( dyn_BF_key );
nullTerm = this->readUChar();
// print
int i = 0;
fprintf( f, "Packet type : Init (0)\n" );
fprintf( f, "Session ID : %02X %02X %02X %02X\n",
sidBytes[0], sidBytes[1], sidBytes[2], sidBytes[3] );
fprintf( f, "Protocol Rev : %04X\n", protoRev );
fprintf( f, "RSA pub key mod :\n" );
for( i=0; i<128; i++ ) fprintf( f, "%02X ", (unsigned int)RSA_pubKeyMod[i] );
fprintf( f, "\n" );
fprintf( f, "GG Shit : " );
for( i=0; i<16; i++ ) fprintf( f, "%02X ", (unsigned int)GG_Shit[i] );
fprintf( f, "\n" );
fprintf( f, "Dynamic BF Key : " );
for( i=0; i<16; i++ ) fprintf( f, "%02X ", (unsigned int)dyn_BF_key[i] );
fprintf( f, "\n" );
fprintf( f, "NULL terminator : %u (0x%02X)\n",
(unsigned int)nullTerm, (unsigned int)nullTerm );
fprintf( f, "Init packet dump end ;)\n\n" );
}
void L2Login_Init::_initPublicMembers()
{
p_sessionId[0] = p_sessionId[1] = p_sessionId[2] = p_sessionId[3] = 0x00;
p_protoVer = 0x00000000;
memset( p_RSA_pubKeyMod, 0, sizeof(p_RSA_pubKeyMod) );
memset( p_GG_shit, 0, sizeof(p_GG_shit) );
memset( p_BF_dyn_key, 0, sizeof(p_BF_dyn_key) );
}
bool L2Login_Init::create( L2_VERSION ver )
{
UNREFERENCED_PARAMETER(ver); // login server packets may ignore this
//int i;
scramble_RSA_PubKeyMod( p_RSA_pubKeyMod );
// write data
writeReset();
setPacketType( 0x00 );
writeBytes( p_sessionId, 4 );
writeUInt( p_protoVer );
writeBytes( p_RSA_pubKeyMod, 128 );
writeUInt( 0x29dd954e ); // 4e 95 dd 29 // GGshit? O_o
writeUInt( 0x77c39cfc ); // fc 9c c3 77
writeUInt( 0x97adb620 ); // 20 b6 ad 97
writeUInt( 0x07bde0f7 ); // f7 e0 bd 07
writeBytes( p_BF_dyn_key, 16 );
writeChar( 0x00 );
// Init packet has no checksum or padding, but it has XOR encryption
// fill packet up to xor key position
writeD( 0x00000000 ); // write some 6 bytes, they are ignored? trash?
writeH( 0x0000 ); // tested, works OK
// now, XOR all previous bytes except first 2 bytes with packet len
// and next 4 bytes with login session id?
unsigned int xor_key = rand(); // O_o generate random XOR "key"
unsigned char *raw_bytes = b.getBytesPtr(); // we need to modify almost all bytes...
int psize = getPacketSize();
int xor_offset = 6; //2; // should we XOR login session id also?
while( xor_offset < psize )
{
// read current dword
unsigned int xoring_dword =
(unsigned int)raw_bytes[xor_offset] |
((unsigned int)raw_bytes[xor_offset+1]) << 8 |
((unsigned int)raw_bytes[xor_offset+2]) << 16 |
((unsigned int)raw_bytes[xor_offset+3]) << 24;
xor_key += xoring_dword; // increase xor key by xoring dword before XOR
xoring_dword ^= xor_key; // XOR
// decodeXOR() first XORs, then substracts :) and it goes from end of packet to beginning
// update dword inside packet
raw_bytes[xor_offset] = (unsigned char)(xoring_dword & 0xFF);
raw_bytes[xor_offset+1] = (unsigned char)(xoring_dword >> 8 & 0xFF);
raw_bytes[xor_offset+2] = (unsigned char)(xoring_dword >> 16 & 0xFF);
raw_bytes[xor_offset+3] = (unsigned char)(xoring_dword >> 24 & 0xFF);
// move to next dword
xor_offset += 4;
}
// append resulting xor key to packet
writeUInt( xor_key );
// add some 4 (trash?) bytes up to size 186
writeUInt( 0x00001234 );
// now Init packet size is 186 bytes long, all OK
// next step before sending packet to client is to encrypt Init packet
// by STATIC blowfish key (can be done by calling L2LoginPacket::encodeBlowfish( true );)
// NO need to call padPacketTo8ByteLen(), appendChecksum(), appendMore8Bytes().
return true;
}
bool L2Login_Init::parse( L2_VERSION ver )
{
UNREFERENCED_PARAMETER(ver); // login server packets may ignore this
if( getPacketSize() != 186 ) return false;
// first remove blowfish using static BF key (hardcoded)
if( !decodeBlowfish( true ) ) return false;
if( !decodeXOR() ) return false;
// read data
_initPublicMembers();
if( getPacketType() != 0x00 ) return false;
if( !read_SessionID( p_sessionId ) ) return false;
p_protoVer = read_ProtoVer();
if( !read_RSA_pubKeyMod( p_RSA_pubKeyMod ) ) return false;
if( !read_GGShit( p_GG_shit ) ) return false;
if( !read_DynamicBFKey( p_BF_dyn_key ) ) return false;
unscramble_RSA_PubKeyMod( p_RSA_pubKeyMod );
return true;
}