// Try to decrypt incoming data. public void DecodeIncomingPacket(NetState from, ref byte[] buffer, ref int length) { if (m_Encryption != null) { // If we're decrypting using LoginCrypt and we've already been relayed, // only decrypt a single packet using logincrypt and then disable it if (m_AlreadyRelayed && m_Encryption is LoginEncryption) { uint newSeed = ((((LoginEncryption)(m_Encryption)).Key1 + 1) ^ ((LoginEncryption)(m_Encryption)).Key2); // Swap the seed newSeed = ((newSeed >> 24) & 0xFF) | ((newSeed >> 8) & 0xFF00) | ((newSeed << 8) & 0xFF0000) | ((newSeed << 24) & 0xFF000000); // XOR it with the old seed newSeed ^= m_Seed; IClientEncryption newEncryption = new GameEncryption(newSeed); // Game Encryption comes first newEncryption.clientDecrypt(ref buffer, length); // The login encryption is still used for this one packet m_Encryption.clientDecrypt(ref buffer, length); // Swap the encryption schemes m_Encryption = newEncryption; m_Seed = newSeed; return; } m_Encryption.clientDecrypt(ref buffer, length); return; } // If the client did not connect on the game server port, // it's not our business to handle encryption for it if (((IPEndPoint)from.Socket.LocalEndPoint).Port != Listener.Port) { m_Encryption = new NoEncryption(); return; } // For simplicities sake, enqueue what we just received as long as we're not initialized m_Buffer.Enqueue(buffer, 0, length); // Clear the array length = 0; // If we didn't receive the seed yet, queue data until we can read the seed if (!m_Seeded) { // Now check if we have at least 4 bytes to get the seed if (m_Buffer.Length >= 4) { byte[] m_Peek = new byte[m_Buffer.Length]; m_Buffer.Dequeue(m_Peek, 0, m_Buffer.Length); // Dequeue everything m_Seed = (uint)((m_Peek[0] << 24) | (m_Peek[1] << 16) | (m_Peek[2] << 8) | m_Peek[3]); m_Seeded = true; Buffer.BlockCopy(m_Peek, 0, buffer, 0, 4); length = 4; } else { return; } } // If the context isn't initialized yet, that means we haven't decided on an encryption method yet if (m_Encryption == null) { int packetLength = m_Buffer.Length; int packetOffset = length; m_Buffer.Dequeue(buffer, length, packetLength); // Dequeue everything length += packetLength; // This is special handling for the "special" UOG packet if (packetLength >= 3) { if (buffer[packetOffset] == 0xf1 && buffer[packetOffset + 1] == ((packetLength >> 8) & 0xFF) && buffer[packetOffset + 2] == (packetLength & 0xFF)) { m_Encryption = new NoEncryption(); return; } } // This is special handling for the "Emulator" packet if (packetLength >= 5) { if (buffer[packetOffset] == 0xbf && buffer[packetOffset + 1] < 0x10 && buffer[packetOffset + 3] == 0x55 && buffer[packetOffset + 4] == 0x55) { m_Encryption = new NoEncryption(); return; } } // Check if the current buffer contains a valid login packet (62 byte + 4 byte header) // Please note that the client sends these in two chunks. One 4 byte and one 62 byte. if (packetLength == 62) { // Check certain indices in the array to see if the given data is unencrypted if (buffer[packetOffset] == 0x80 && buffer[packetOffset + 30] == 0x00 && buffer[packetOffset + 60] == 0x00) { if (Configuration.AllowUnencryptedClients) { m_Encryption = new NoEncryption(); } else { RejectNoEncryption(from); from.Dispose(); return; } } else { LoginEncryption encryption = new LoginEncryption(); if (encryption.init(m_Seed, buffer, packetOffset, packetLength)) { log.InfoFormat("Client: {0}: Encrypted client detected, using keys of client {1}", from, encryption.Name); m_Encryption = encryption; byte[] packet = new byte[packetLength]; Buffer.BlockCopy(buffer, packetOffset, packet, 0, packetLength); encryption.clientDecrypt(ref packet, packet.Length); Buffer.BlockCopy(packet, 0, buffer, packetOffset, packetLength); } else { log.Warn("Detected an unknown client."); } } } else if (packetLength == 65) { // If its unencrypted, use the NoEncryption class if (buffer[packetOffset] == '\x91' && buffer[packetOffset + 1] == ((m_Seed >> 24) & 0xFF) && buffer[packetOffset + 2] == ((m_Seed >> 16) & 0xFF) && buffer[packetOffset + 3] == ((m_Seed >> 8) & 0xFF) && buffer[packetOffset + 4] == (m_Seed & 0xFF)) { if (Configuration.AllowUnencryptedClients) { m_Encryption = new NoEncryption(); } else { RejectNoEncryption(from); from.Dispose(); return; } } else { // If it's not an unencrypted packet, simply assume it's encrypted with the seed m_Encryption = new GameEncryption(m_Seed); byte[] packet = new byte[packetLength]; Buffer.BlockCopy(buffer, packetOffset, packet, 0, packetLength); m_Encryption.clientDecrypt(ref packet, packet.Length); Buffer.BlockCopy(packet, 0, buffer, packetOffset, packetLength); } } // If it's still not initialized, copy the data back to the queue and wait for more if (m_Encryption == null) { m_Buffer.Enqueue(buffer, packetOffset, packetLength); length -= packetLength; return; } } }
// Try to decrypt incoming data. public void DecodeIncomingPacket( NetState from, ref byte[] buffer, ref int length ) { if (m_Encryption != null) { // If we're decrypting using LoginCrypt and we've already been relayed, // only decrypt a single packet using logincrypt and then disable it if (m_AlreadyRelayed && m_Encryption is LoginEncryption) { uint newSeed = ((((LoginEncryption)(m_Encryption)).Key1 + 1) ^ ((LoginEncryption)(m_Encryption)).Key2); // Swap the seed newSeed = ((newSeed >> 24) & 0xFF) | ((newSeed >> 8) & 0xFF00) | ((newSeed << 8) & 0xFF0000) | ((newSeed << 24) & 0xFF000000); // XOR it with the old seed newSeed ^= m_Seed; IClientEncryption newEncryption = new GameEncryption(newSeed); // Game Encryption comes first newEncryption.clientDecrypt(ref buffer, length); // The login encryption is still used for this one packet m_Encryption.clientDecrypt(ref buffer, length); // Swap the encryption schemes m_Encryption = newEncryption; m_Seed = newSeed; return; } m_Encryption.clientDecrypt(ref buffer, length); return; } // If the client did not connect on the game server port, // it's not our business to handle encryption for it if (((IPEndPoint)from.Socket.LocalEndPoint).Port != Listener.Port) { m_Encryption = new NoEncryption(); return; } // For simplicities sake, enqueue what we just received as long as we're not initialized m_Buffer.Enqueue(buffer, 0, length); // Clear the array length = 0; // If we didn't receive the seed yet, queue data until we can read the seed if (!m_Seeded) { // Now check if we have at least 4 bytes to get the seed if (m_Buffer.Length >= 4) { byte[] m_Peek = new byte[m_Buffer.Length]; m_Buffer.Dequeue( m_Peek, 0, m_Buffer.Length ); // Dequeue everything m_Seed = (uint)((m_Peek[0] << 24) | (m_Peek[1] << 16) | (m_Peek[2] << 8) | m_Peek[3]); m_Seeded = true; Buffer.BlockCopy(m_Peek, 0, buffer, 0, 4); length = 4; } else { return; } } // If the context isn't initialized yet, that means we haven't decided on an encryption method yet if (m_Encryption == null) { int packetLength = m_Buffer.Length; int packetOffset = length; m_Buffer.Dequeue( buffer, length, packetLength); // Dequeue everything length += packetLength; // This is special handling for the "special" UOG packet if (packetLength >= 3) { if (buffer[packetOffset] == 0xf1 && buffer[packetOffset+1] == ((packetLength >> 8) & 0xFF) && buffer[packetOffset+2] == (packetLength & 0xFF)) { m_Encryption = new NoEncryption(); return; } } // Check if the current buffer contains a valid login packet (62 byte + 4 byte header) // Please note that the client sends these in two chunks. One 4 byte and one 62 byte. if (packetLength == 62) { // Check certain indices in the array to see if the given data is unencrypted if (buffer[packetOffset] == 0x80 && buffer[packetOffset+30] == 0x00 && buffer[packetOffset+60] == 0x00) { if (Configuration.AllowUnencryptedClients) { m_Encryption = new NoEncryption(); } else { RejectNoEncryption(from); from.Dispose(); return; } } else { LoginEncryption encryption = new LoginEncryption(); if (encryption.init(m_Seed, buffer, packetOffset, packetLength)) { Console.WriteLine( "Client: {0}: Encrypted client detected, using keys of client {1}", from, encryption.Name ); m_Encryption = encryption; byte[] packet = new byte[packetLength]; Buffer.BlockCopy(buffer, packetOffset, packet, 0, packetLength); encryption.clientDecrypt(ref packet, packet.Length); Buffer.BlockCopy(packet, 0, buffer, packetOffset, packetLength); } else { Console.WriteLine("Detected an unknown client."); } } } else if (packetLength == 65) { // If its unencrypted, use the NoEncryption class if ( buffer[packetOffset] == '\x91' && buffer[packetOffset+1] == ((m_Seed >> 24) & 0xFF) && buffer[packetOffset+2] == ((m_Seed >> 16) & 0xFF) && buffer[packetOffset+3] == ((m_Seed >> 8) & 0xFF) && buffer[packetOffset+4] == (m_Seed & 0xFF) ) { if (Configuration.AllowUnencryptedClients) { m_Encryption = new NoEncryption(); } else { RejectNoEncryption(from); from.Dispose(); return; } } else { // If it's not an unencrypted packet, simply assume it's encrypted with the seed m_Encryption = new GameEncryption(m_Seed); byte[] packet = new byte[packetLength]; Buffer.BlockCopy(buffer, packetOffset, packet, 0, packetLength); m_Encryption.clientDecrypt(ref packet, packet.Length); Buffer.BlockCopy(packet, 0, buffer, packetOffset, packetLength); } } // If it's still not initialized, copy the data back to the queue and wait for more if (m_Encryption == null) { m_Buffer.Enqueue(buffer, packetOffset, packetLength); length -= packetLength ; return; } } }