jo3bingham
Excellent OT User
I've been contacted by multiple people asking me to look into the packet structure changes that came with the recent Tibia 14 update. As @Marcosvf132 was the first person to ask, and also came to the same conclusion that I did, I want to make sure they get credited as well.
The first thing to point out is the changes to the client Login packet. The 2 bytes to indicate the DatRevision has been changed to a string that is the SHA256 hash of the assets.json file:
Replace:
With:
This means that the position of the RSA-encrypted block has changed, and it's best to change the following code:
github.com
From:
To:
The previous packet structure was as such:
2 bytes to indicate how many more bytes are in the packet, 4 bytes to indicate the sequence number and if the packet is compressed, then X bytes that are (potentially) compressed and XTEA encrypted. Once XTEA decrypted, the first 2 bytes of the decrypted data indicate how many bytes are remaining. If compressed, these remaining bytes then need to be decompressed via zlib inflate. What's remaining is the raw packet data to be parsed.
The new structure is as such:
2 bytes to indicate how many 8-byte chunks make up the packet data, 4 bytes to indicate the sequence number and if the packet is compressed, then X (value of the first 2 bytes of the packet multiplied by 8) bytes that are (potentially) compressed and XTEA encrypted. Once XTEA decrypted, the first byte of the decrypted data indicates how many padding bytes are at the end (can be between 0-7 bytes). If compressed, the remaining bytes (minus how many padding bytes there are) then need to be decompressed viz zlib inflate. What's remaining is the raw packet data to be parsed.
Here's a couple of examples.
1) First packet (LoginChallenge) from the server after the client sends the server name:
01 00 - Numer of 8-byte chunks to make up the packet data. In this case, it is 1.
00 00 00 00 - 4 bytes to indicate the sequence number and if the packet is compressed. In this case, the sequence number is 0 and the packet is not compressed.
01 1F FC 1D 00 00 A1 71 - 8-byte chunks as indicated by the first 2 bytes. In this case, it is just 1 8-byte chunk.
01 - Number of padding bytes at the end of the data. In this case, there is just 1 padding byte at the end.
1F FC 1D 00 00 A1 - Packet data without the padding bytes.
1F - Packet type. In this case, the LoginChallenge packet.
FC 1D 00 00 - First 4 bytes of the LoginChallenge packet is a timestamp value.
A1 - 5th byte of the LoginChallenge packet is a random value.
71 - The padding bytes that are essentially junk bytes.
2) A MoveCreature packet from the server:
02 00 - Number of 8-byte chunks to make up the packet data. In this case, it is 16 (2 * 8).
08 00 00 C0 - 4 bytes to indicate the sequence number and if the packet is compressed. In this case, the sequence number is 8 and the presence of C0 in the first byte (since Tibia packets use little-endian byte sequences) indicates it is compressed.
82 F7 34 53 91 EA 24 A1 CB 78 C7 96 AA D9 33 8A - The data to be XTEA decrypted.
The packet data after being XTEA decrypted:
07 - Number of padding bytes at the end of the data.
CA 05 93 8C 60 11 00 00 - The data to be decompressed.
8E 39 E0 10 34 72 AA - The padding/junk bytes.
The compressed data after being decompressed:
6D - Packet type. In this case, the MoveCreature packet.
71 7E ED 7D 07 - Position (xyz) of the creature to move.
01 - Stackposition of the creature to move.
72 7E ED 7D 07 - Position (xyz) to move the creature to.
The first thing to point out is the changes to the client Login packet. The 2 bytes to indicate the DatRevision has been changed to a string that is the SHA256 hash of the assets.json file:
Replace:
C#:
DatRevision = message.ReadUInt16();
C#:
var assetsHash = message.ReadString();
TibiaAPI/TibiaAPI/Network/Connection.cs at 75d31e3121d7186524d228df331dfff9e39d46e1 · jo3bingham/TibiaAPI
An open-source, cross-platform proxy library written in C# for use with Open-Tibia. - jo3bingham/TibiaAPI
C#:
var rsaStartIndex = _client.VersionNumber >= 124010030 ? 31 : 18;
C#:
_clientInMessage.Seek(16, SeekOrigin.Begin); // Skip to the string values
_clientInMessage.ReadString(); // Client version
_clientInMessage.ReadString(); // Assets.json SHA256 hash
_clientInMessage.Seek(1, SeekOrigin.Current); // Skip ClientPreviewState value
var rsaStartIndex = (int)_clientInMessage.Position;
The previous packet structure was as such:
2 bytes to indicate how many more bytes are in the packet, 4 bytes to indicate the sequence number and if the packet is compressed, then X bytes that are (potentially) compressed and XTEA encrypted. Once XTEA decrypted, the first 2 bytes of the decrypted data indicate how many bytes are remaining. If compressed, these remaining bytes then need to be decompressed via zlib inflate. What's remaining is the raw packet data to be parsed.
The new structure is as such:
2 bytes to indicate how many 8-byte chunks make up the packet data, 4 bytes to indicate the sequence number and if the packet is compressed, then X (value of the first 2 bytes of the packet multiplied by 8) bytes that are (potentially) compressed and XTEA encrypted. Once XTEA decrypted, the first byte of the decrypted data indicates how many padding bytes are at the end (can be between 0-7 bytes). If compressed, the remaining bytes (minus how many padding bytes there are) then need to be decompressed viz zlib inflate. What's remaining is the raw packet data to be parsed.
Here's a couple of examples.
1) First packet (LoginChallenge) from the server after the client sends the server name:
Code:
01 00 00 00 00 00 01 1F FC 1D 00 00 A1 71
00 00 00 00 - 4 bytes to indicate the sequence number and if the packet is compressed. In this case, the sequence number is 0 and the packet is not compressed.
01 1F FC 1D 00 00 A1 71 - 8-byte chunks as indicated by the first 2 bytes. In this case, it is just 1 8-byte chunk.
01 - Number of padding bytes at the end of the data. In this case, there is just 1 padding byte at the end.
1F FC 1D 00 00 A1 - Packet data without the padding bytes.
1F - Packet type. In this case, the LoginChallenge packet.
FC 1D 00 00 - First 4 bytes of the LoginChallenge packet is a timestamp value.
A1 - 5th byte of the LoginChallenge packet is a random value.
71 - The padding bytes that are essentially junk bytes.
2) A MoveCreature packet from the server:
Code:
02 00 08 00 00 C0 82 F7 34 53 91 EA 24 A1 CB 78 C7 96 AA D9 33 8A
08 00 00 C0 - 4 bytes to indicate the sequence number and if the packet is compressed. In this case, the sequence number is 8 and the presence of C0 in the first byte (since Tibia packets use little-endian byte sequences) indicates it is compressed.
82 F7 34 53 91 EA 24 A1 CB 78 C7 96 AA D9 33 8A - The data to be XTEA decrypted.
The packet data after being XTEA decrypted:
Code:
07 CA 05 93 8C 60 11 00 00 8E 39 E0 10 34 72 AA
CA 05 93 8C 60 11 00 00 - The data to be decompressed.
8E 39 E0 10 34 72 AA - The padding/junk bytes.
The compressed data after being decompressed:
Code:
6D 71 7E ED 7D 07 01 72 7E ED 7D 07
71 7E ED 7D 07 - Position (xyz) of the creature to move.
01 - Stackposition of the creature to move.
72 7E ED 7D 07 - Position (xyz) to move the creature to.
Last edited: