Lineage 2 Game Protocol

Aus Notebook
Zur Navigation springen Zur Suche springen

Protocol dumps (GoD)

Goddess of Destruction - Login

Initialisation

C->S
SYN
S->C
SYN-ACK
C->S
ACK

Some packets:

C->S Login
0x2b (UnicodeString: LoginName) (Bytes x4 from sessionKey2+4) (Bytes x4 from sessionKey2) (Bytes x8 from sessionKey1) 0x00000001
C->S ProtocolVersion
0x0e (UInt: Protocol) 0x09, 0x07, 0x54, 0x56, 0x03, 0x09, 0x0B, 0x01, 0x07, 0x02, 0x54, 0x54, 0x56, 0x07, 0x00, 0x02,
       0x55, 0x56, 0x00, 0x51,  0x00, 0x53, 0x57, 0x04, 0x07, 0x55, 0x08, 0x54, 0x01, 0x07, 0x01, 0x53, 
       0x00, 0x56, 0x55, 0x56,  0x01, 0x06, 0x05, 0x04, 0x51, 0x03, 0x08, 0x51, 0x08, 0x51, 0x56, 0x04, 
       0x54, 0x06, 0x55, 0x08,  0x02, 0x09, 0x51, 0x56, 0x01, 0x53, 0x06, 0x55, 0x04, 0x53, 0x00, 0x56, 
       0x56, 0x53, 0x01, 0x09,  0x02, 0x09, 0x01, 0x51, 0x54, 0x51, 0x09, 0x55, 0x56, 0x09, 0x03, 0x04, 
       0x07, 0x05, 0x55, 0x04,  0x06, 0x55, 0x04, 0x06, 0x09, 0x04, 0x51, 0x01, 0x08, 0x08, 0x06, 0x05, 
       0x52, 0x06, 0x04, 0x01,  0x07, 0x54, 0x03, 0x06, 0x52, 0x55, 0x06, 0x55, 0x55, 0x51, 0x01, 0x02, 
       0x04, 0x54, 0x03, 0x55,  0x54, 0x01, 0x57, 0x51, 0x55, 0x05, 0x52, 0x05, 0x54, 0x07, 0x51, 0x51, 
       0x55, 0x07, 0x02, 0x53,  0x53, 0x00, 0x52, 0x05, 0x52, 0x07, 0x01, 0x54, 0x00, 0x03, 0x05, 0x05, 
       0x08, 0x06, 0x05, 0x05,  0x06, 0x03, 0x00, 0x0D, 0x08, 0x01, 0x07, 0x09, 0x03, 0x51, 0x03, 0x07, 
       0x53, 0x09, 0x51, 0x06,  0x07, 0x54, 0x0A, 0x50, 0x56, 0x02, 0x52, 0x04, 0x05, 0x55, 0x51, 0x02, 
       0x53, 0x00, 0x08, 0x54,  0x04, 0x52, 0x56, 0x06, 0x02, 0x09, 0x00, 0x08, 0x03, 0x53, 0x56, 0x01, 
       0x05, 0x00, 0x55, 0x06,  0x08, 0x56, 0x04, 0x0D, 0x06, 0x07, 0x52, 0x06, 0x07, 0x04, 0x0A, 0x06, 
       0x01, 0x04, 0x54, 0x04,  0x00, 0x05, 0x02, 0x04, 0x54, 0x00, 0x09, 0x52, 0x53, 0x05, 0x04, 0x01, 
       0x04, 0x05, 0x05, 0x01,  0x52, 0x51, 0x52, 0x0D, 0x06, 0x51, 0x08, 0x09, 0x54, 0x53, 0x00, 0x0D, 
       0x01, 0x02, 0x03, 0x54,  0x53, 0x01, 0x05, 0x03, 0x08, 0x56, 0x54, 0x07, 0x02, 0x54, 0x0B, 0x06,
       0xFB, 0x87, 0xB9, 0x4A  }; // these last 4 bytes may differ
C->S EnterWorld
0x11
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
C9 BC F2 A7 66 5A 0B 98 36 A5 BD 89 ED 7F E4 D7
6B 49 E2 9F EF 76 EB CE A3 FA F4 BF 0C 64 A3 B4
A4 CE DC C6 08 3E 6E EA 45 CA D3 FE 88 13 87 B8
06 2C 96 F0 9B 1E 8E BC C6 9B 98 C8 63 16 CF D0
29 00 00 00 0A E1 74 17 0A 08 00 08 5C 32 BD E1

5C 32 BE 22 5E 19 03 41

C->S CharacterSelect
0x12 (UInt: Character Slot) 0x0000 0x00000000 0x00000000 0x00000000
S->C KeyPacket
(Packet type: 0x2E) (Byte: Protocol ok? 0x01: OK, 0x00: Not OK) (Byte x8: First 8 bytes of Crypto XOR key) 0x00000001 (Byte: ServerID) 0x00000000 (UInt: Opcode Obfuscator Seed)
S->C CharSelectionInfo
0x09 (UInt: Number of characters) (UInt: Max number of characters allowed on this server) 0x00 (((UnicodeString: Name) (UInt: CharID) (UnicodeString: AccountName) (UInt: SessionID) (UInt: ClanID) 0x00000000 (UInt: Sex) (UInt: Race) (UInt: BaseClassID) (UInt: IsActive) (UInt: X) (UInt: Y) (UInt: Z) (Double: HP_Current) (Double: MP_Current) (UInt: SP) (UInt64: XP) (UInt: Level) (UInt: Karma) (UInt: PKs) (0x00000000 x8) (UInt x19: Equipment worn) (0x00000000 x6) (UInt: HairStyle) (UInt: HairColor) (UInt: Face) (Double: HP_Max) (Double: MP_Max) (UInt: DeleteDays) (UInt: ClassID) (UInt: LastUsedChar) (UChar: EnchantEffect) (UShort: AugumentID) (UShort: AugumentSmth) (UInt: TransformID)) x number of Characters)
Additional data fields in Freya: (UInt: PetID) (UInt: Level) 0x00000000 (UInt: Food) (Double: MaxHP) (Double: CurHP)
Additional data fields in High Five:(UInt: Vitality)

Crypto XOR key set to:

[Bytes 3-10 of the KeyPacket packet] 0xc8 0x27 0x93 0x01 0xa1 0x6c 0x31 0x97

OpCode Obfuscation

Pseudo-Randomisation function

   unsigned int pseudo_rand()
   {
       unsigned int a;
       a = ( m_seed * 0x343fd + 0x269EC3 ) & 0xFFFFFFFF;
       m_seed = a;
       unsigned int result = ( m_seed >> 0x10 ) & 0x7FFF;
       return result;
   }

Table initialisation

   void init_tables( unsigned int seed )
   {
       unsigned int i = 0;
       unsigned char tmp = 0;
       unsigned int pos;
       unsigned int cpos;
       m_s1 = 0xD0;
       m_s2 = 0x58; // Gracia, Part 2 (amount of opcodes, depends on the protocol version)
       m_DecodeTable1 = (unsigned char *)malloc( sizeof(unsigned char) * (m_s1 + 1) );
       m_DecodeTable2 = (unsigned char *)malloc( sizeof(unsigned char) * (m_s2 + 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;
       this->pseudo_srand( seed );
       for( i = 1; i <= m_s1; i++ )
       {
               pos = this->pseudo_rand() % (i + 1);
               // swap bytes [pos] and [i] in DecodeTable1
               tmp = m_DecodeTable1[pos];
               m_DecodeTable1[pos] = m_DecodeTable1[i];
               m_DecodeTable1[i] = tmp;
       }
       for( i = 1; i <= m_s2; i++ )
       {
               pos = this->pseudo_rand() % (i + 1);
               // swap bytes [pos] and [i] in DecodeTable2
               tmp = m_DecodeTable2[pos];
               m_DecodeTable2[pos] = m_DecodeTable2[i];
               m_DecodeTable2[i] = tmp;
       }
       // 0x12 (CharacterSelect) isn't obfuscated
       cpos = 0;
       while( m_DecodeTable1[cpos] != 0x12 ) cpos++;
       tmp = m_DecodeTable1[0x12];
       m_DecodeTable1[0x12] = 0x12;
       m_DecodeTable1[cpos] = tmp;
       // 0xb1 (NetPing) isn't obfuscated either
       cpos = 0;
       while( m_DecodeTable1[cpos] != 0xB1 ) cpos++;
       tmp = m_DecodeTable1[0xB1];
       m_DecodeTable1[0xB1] = 0xB1;
       m_DecodeTable1[cpos] = tmp;
       // EncodeTables are just the reverse of DecodeTables
       m_EncodeTable1 = (unsigned char *)malloc( sizeof(unsigned char) * (m_s1 + 1) );
       m_EncodeTable2 = (unsigned char *)malloc( sizeof(unsigned char) * (m_s2 + 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;
   }

Decode IDs

   int 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 ) return -1;
               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 ) return -2;
                       else data[ofs + 1] = m_DecodeTable2[ data[ofs + 1] ];
               }
       }
       return ret_val;
   }

Encode IDs

   int 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
       int ret_val = 0;
       if( m_EncodeTable1 )
       {
               if( data[ofs] >= m_s1 ) return -1;
               else data[ofs] = m_EncodeTable1[ data[ofs] ];
               ret_val = 1;
               if( data[ofs] == 0xD0 ) // double-byte packet
               {
                       ret_val = 2;
                       if( data[ofs + 1] >= m_s2 ) return -2;
                       else data[ofs + 1] = m_EncodeTable2[ data[ofs + 1] ];
               }
       }
       return ret_val;
 }

References