public Encryption() { m_AlreadyRelayed = false; m_Encryption = null; m_Buffer = new ByteQueue(); m_Seeded = false; m_Seed = 0; }
// 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) { #region m_Encryption != null 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; } #endregion #region Port Scan //11JUN2008 GOW SVN fix ** START *** // 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; //} bool handle = false; for (int i = 0; i < Listener.EndPoints.Length; i++) { IPEndPoint ipep = (IPEndPoint)Listener.EndPoints[i]; if (((IPEndPoint)from.Socket.LocalEndPoint).Port == ipep.Port) handle = true; } if (!handle) { m_Encryption = new NoEncryption(); return; } #endregion #region !m_Seeded // 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; // } //} //http://uodev.de/viewtopic.php?t=5097&postdays=0&postorder=asc&start=15&sid=dfb8e6c73b9e3eb95c1634ca3586e8a7 //if (!m_Seeded) //{ // int seed_length = m_Buffer.GetSeedLength(); // if (m_Buffer.Length >= seed_length) // { // byte[] m_Peek = new byte[m_Buffer.Length]; // m_Buffer.Dequeue(m_Peek, 0, seed_length); // if (seed_length == 4) // m_Seed = (uint)((m_Peek[0] << 24) | (m_Peek[1] << 16) | (m_Peek[2] << 8) | m_Peek[3]); // else if (seed_length == 21) // m_Seed = (uint)((m_Peek[1] << 24) | (m_Peek[2] << 16) | (m_Peek[3] << 8) | m_Peek[4]); // m_Seeded = true; // Buffer.BlockCopy(m_Peek, 0, buffer, 0, seed_length); // length = seed_length; // } // else // { // return; // } //} //11JUN2008 My Version if (!m_Seeded) { if (m_Buffer.Length <= 3) //Short Length, try again. { Console.WriteLine("Encryption: Failed - Short Lenght"); return; } //else if ((m_Buffer.Length == 83) && (m_Buffer.GetPacketID() == 239)) //New Client //{ // byte[] m_Peek = new byte[21]; // m_Buffer.Dequeue(m_Peek, 0, 21); // m_Seed = (uint)((m_Peek[1] << 24) | (m_Peek[2] << 16) | (m_Peek[3] << 8) | m_Peek[4]); // m_Seeded = true; // Buffer.BlockCopy(m_Peek, 0, buffer, 0, 21); // length = 21; // Console.WriteLine("Encryption: Passed - New Client"); //} //05MAR2009 Smjert's fix for double log in. *** START *** else if ((m_Buffer.Length == 83 || m_Buffer.Length == 21) && (m_Buffer.GetPacketID() == 239)) //New Client { length = m_Buffer.Length; byte[] m_Peek = new byte[21]; m_Buffer.Dequeue(m_Peek, 0, 21); m_Seed = (uint)((m_Peek[1] << 24) | (m_Peek[2] << 16) | (m_Peek[3] << 8) | m_Peek[4]); m_Seeded = true; Buffer.BlockCopy(m_Peek, 0, buffer, 0, 21); Console.WriteLine("Encryption: Passed - New Client"); // We need to wait the next packet if (length == 21) return; length = 21; } else if (m_Buffer.Length >= 4) //Old Client //05MAR2009 Smjert's fix for double log in. *** END *** { byte[] m_Peek = new byte[4]; m_Buffer.Dequeue(m_Peek, 0, 4); 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; Console.WriteLine("Encryption: Passed - Old Client"); } else //It should never reach here. { Console.WriteLine("Encryption: Failed - It should never reach here"); return; } } #endregion // If the context isn't initialized yet, that means we haven't decided on an encryption method yet #region m_Encryption == null 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) { Console.WriteLine("Checking packetLength 62 == " + packetLength); // 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; Console.WriteLine("Encryption: Check 1"); byte[] packet = new byte[packetLength]; Console.WriteLine("Encryption: Check 2"); Buffer.BlockCopy(buffer, packetOffset, packet, 0, packetLength); Console.WriteLine("Encryption: Check 3"); encryption.clientDecrypt(ref packet, packet.Length); Console.WriteLine("Encryption: Check 4"); Buffer.BlockCopy(packet, 0, buffer, packetOffset, packetLength); Console.WriteLine("Encryption: Check 5"); //return; //Just throwing this in. } else { Console.WriteLine("Detected an unknown client."); } } } else if (packetLength == 65) { Console.WriteLine("Checking packetLength 65 == " + packetLength); // 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(); } } 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) { Console.WriteLine("Encryption: Check - Waiting"); m_Buffer.Enqueue(buffer, packetOffset, packetLength); length -= packetLength; return; } } #endregion }
// Try to decrypt incoming data. public void DecodeIncomingPacket(NetState from, ref byte[] buffer, ref int length) { #region m_Encryption != null 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; } #endregion #region Port Scan //11JUN2008 RunUO SVN fix ** START *** // 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; //} bool handle = false; for (int i = 0; i < Listener.EndPoints.Length; i++) { IPEndPoint ipep = (IPEndPoint)Listener.EndPoints[i]; if (((IPEndPoint)from.Socket.LocalEndPoint).Port == ipep.Port) { handle = true; } } if (!handle) { m_Encryption = new NoEncryption(); return; } //11JUN2008 RunUO SVN fix ** END *** #endregion #region !m_Seeded // 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; // } //} //http://uodev.de/viewtopic.php?t=5097&postdays=0&postorder=asc&start=15&sid=dfb8e6c73b9e3eb95c1634ca3586e8a7 //if (!m_Seeded) //{ // int seed_length = m_Buffer.GetSeedLength(); // if (m_Buffer.Length >= seed_length) // { // byte[] m_Peek = new byte[m_Buffer.Length]; // m_Buffer.Dequeue(m_Peek, 0, seed_length); // if (seed_length == 4) // m_Seed = (uint)((m_Peek[0] << 24) | (m_Peek[1] << 16) | (m_Peek[2] << 8) | m_Peek[3]); // else if (seed_length == 21) // m_Seed = (uint)((m_Peek[1] << 24) | (m_Peek[2] << 16) | (m_Peek[3] << 8) | m_Peek[4]); // m_Seeded = true; // Buffer.BlockCopy(m_Peek, 0, buffer, 0, seed_length); // length = seed_length; // } // else // { // return; // } //} //11JUN2008 My Version if (!m_Seeded) { if (m_Buffer.Length <= 3) //Short Length, try again. { Console.WriteLine("Encryption: Failed - Short Lenght"); return; } //else if ((m_Buffer.Length == 83) && (m_Buffer.GetPacketID() == 239)) //New Client //{ // byte[] m_Peek = new byte[21]; // m_Buffer.Dequeue(m_Peek, 0, 21); // m_Seed = (uint)((m_Peek[1] << 24) | (m_Peek[2] << 16) | (m_Peek[3] << 8) | m_Peek[4]); // m_Seeded = true; // Buffer.BlockCopy(m_Peek, 0, buffer, 0, 21); // length = 21; // Console.WriteLine("Encryption: Passed - New Client"); //} //05MAR2009 Smjert's fix for double log in. *** START *** else if ((m_Buffer.Length == 83 || m_Buffer.Length == 21) && (m_Buffer.GetPacketID() == 239)) //New Client { length = m_Buffer.Length; byte[] m_Peek = new byte[21]; m_Buffer.Dequeue(m_Peek, 0, 21); m_Seed = (uint)((m_Peek[1] << 24) | (m_Peek[2] << 16) | (m_Peek[3] << 8) | m_Peek[4]); m_Seeded = true; Buffer.BlockCopy(m_Peek, 0, buffer, 0, 21); Console.WriteLine("Encryption: Passed - New Client"); // We need to wait the next packet if (length == 21) { return; } length = 21; } else if (m_Buffer.Length >= 4) //Old Client //05MAR2009 Smjert's fix for double log in. *** END *** { byte[] m_Peek = new byte[4]; m_Buffer.Dequeue(m_Peek, 0, 4); 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; Console.WriteLine("Encryption: Passed - Old Client"); } else //It should never reach here. { Console.WriteLine("Encryption: Failed - It should never reach here"); return; } } #endregion // If the context isn't initialized yet, that means we haven't decided on an encryption method yet #region m_Encryption == null 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) { Console.WriteLine("Checking packetLength 62 == " + packetLength); // 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; Console.WriteLine("Encryption: Check 1"); byte[] packet = new byte[packetLength]; Console.WriteLine("Encryption: Check 2"); Buffer.BlockCopy(buffer, packetOffset, packet, 0, packetLength); Console.WriteLine("Encryption: Check 3"); encryption.clientDecrypt(ref packet, packet.Length); Console.WriteLine("Encryption: Check 4"); Buffer.BlockCopy(packet, 0, buffer, packetOffset, packetLength); Console.WriteLine("Encryption: Check 5"); //return; //Just throwing this in. } else { Console.WriteLine("Detected an unknown client."); } } } else if (packetLength == 65) { Console.WriteLine("Checking packetLength 65 == " + packetLength); // 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(); } } 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) { Console.WriteLine("Encryption: Check - Waiting"); m_Buffer.Enqueue(buffer, packetOffset, packetLength); length -= packetLength; return; } } #endregion }
// 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; } } }
// Try to decrypt incoming data. public void DecodeIncomingPacket(NetState from, ref byte[] buffer, ref int length) { #region m_Encryption != null 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; } #endregion #region Port Scan bool handle = false; for (int i = 0; i < Listener.EndPoints.Length; i++) { IPEndPoint ipep = Listener.EndPoints[i]; if (((IPEndPoint)from.Socket.LocalEndPoint).Port == ipep.Port) { handle = true; } } if (!handle) { m_Encryption = new NoEncryption(); return; } #endregion #region !m_Seeded // 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 (!m_Seeded) { if ((m_Buffer.Length == 83 || m_Buffer.Length == 21) && (m_Buffer.GetPacketID() == 239)) //New Client { length = m_Buffer.Length; byte[] m_Peek = new byte[21]; m_Buffer.Dequeue(m_Peek, 0, 21); m_Seed = (uint)((m_Peek[1] << 24) | (m_Peek[2] << 16) | (m_Peek[3] << 8) | m_Peek[4]); m_Seeded = true; Buffer.BlockCopy(m_Peek, 0, buffer, 0, 21); // We need to wait the next packet if (length == 21) { return; } length = 21; } else if (m_Buffer.Length >= 4) // Old Client { byte[] m_Peek = new byte[4]; m_Buffer.Dequeue(m_Peek, 0, 4); 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 { //Console.WriteLine("Encryption: Failed - Invalid Client."); return; } } #endregion // If the context isn't initialized yet, that means we haven't decided on an encryption method yet #region m_Encryption == null 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.Initialize(m_Seed, buffer, packetOffset, packetLength, from)) { Console.WriteLine("Client: {0}: Encrypted client detected, using keys for client v{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("Client: Unknown client detected, disconnecting."); from.Dispose(); } } } 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); } } 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; } } #endregion }
public void DecodeIncomingPacket(NetState from, ref byte[] buffer, ref int length) { if (m_Encryption != null) { if (m_AlreadyRelayed && m_Encryption is LoginEncryption) { uint newSeed = ((((LoginEncryption)(m_Encryption)).Key1 + 1) ^ ((LoginEncryption)(m_Encryption)).Key2); newSeed = ((newSeed >> 24) & 0xFF) | ((newSeed >> 8) & 0xFF00) | ((newSeed << 8) & 0xFF0000) | ((newSeed << 24) & 0xFF000000); newSeed ^= m_Seed; IClientEncryption newEncryption = new GameEncryption(newSeed); newEncryption.clientDecrypt(ref buffer, length); m_Encryption.clientDecrypt(ref buffer, length); m_Encryption = newEncryption; m_Seed = newSeed; return; } m_Encryption.clientDecrypt(ref buffer, length); return; } bool handle = false; for (int i = 0; i < Listener.EndPoints.Length; i++) { IPEndPoint ipep = (IPEndPoint)Listener.EndPoints[i]; if (((IPEndPoint)from.Socket.LocalEndPoint).Port == ipep.Port) { handle = true; } } if (!handle) { m_Encryption = new NoEncryption(); return; } m_Buffer.Enqueue(buffer, 0, length); length = 0; if (!m_Seeded) { if (m_Buffer.Length <= 3) { Console.WriteLine("Encryption: Failed - Short Lenght"); return; } else if ((m_Buffer.Length == 83 || m_Buffer.Length == 21) && (m_Buffer.GetPacketID() == 239)) //New Client { length = m_Buffer.Length; byte[] m_Peek = new byte[21]; m_Buffer.Dequeue(m_Peek, 0, 21); m_Seed = (uint)((m_Peek[1] << 24) | (m_Peek[2] << 16) | (m_Peek[3] << 8) | m_Peek[4]); m_Seeded = true; Buffer.BlockCopy(m_Peek, 0, buffer, 0, 21); Console.WriteLine("Encryption: Passed - New Client"); if (length == 21) { return; } length = 21; } else if (m_Buffer.Length >= 4) { byte[] m_Peek = new byte[4]; m_Buffer.Dequeue(m_Peek, 0, 4); 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; Console.WriteLine("Encryption: Passed - Old Client"); } else { Console.WriteLine("Encryption: Failed - It should never reach here"); return; } } if (m_Encryption == null) { int packetLength = m_Buffer.Length; int packetOffset = length; m_Buffer.Dequeue(buffer, length, packetLength); length += packetLength; if (packetLength >= 3) { if (buffer[packetOffset] == 0xf1 && buffer[packetOffset + 1] == ((packetLength >> 8) & 0xFF) && buffer[packetOffset + 2] == (packetLength & 0xFF)) { m_Encryption = new NoEncryption(); return; } } if (packetLength == 62) { 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("Client: {0}: Detected an unknown client.", from); } } } else if (packetLength == 65) { 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(); } } else { 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 (m_Encryption == null) { Console.WriteLine("Encryption: Check - Waiting"); m_Buffer.Enqueue(buffer, packetOffset, packetLength); length -= packetLength; return; } } }