If you have ever looked at the way JJ2 communicates with other servers over the web then you have probably noticed that there are two protocols in use – TCP and UDP. TCP is where most of the sensitive data is sent over the network – join requests, server status updates, player name lists, game chat, downloads, etc. UDP, however, uses much more bandwidth than TCP and is primarily used to transfer less sensitive game data such as in-game player locations, animations, gunfire data, object respawns, ping, passwords for private servers, etc. TCP packets are fairly easy to reproduce and are used in a number of utilities today. However, UDP packets come with something little extra that complicates the matters a bit. A checksum of a kind which is always located on the beginning of the packet – first two bytes to be exact. Reproducing data part of a UDP packet should really be an easy task, however the checksum can be a problem if a user does not know how to calculate it – which is what we will talk about in this article.
“A checksum is a form of redundancy check, a very simple measure for protecting the integrity of data by detecting errors in data that is sent through space (telecommunications) or time (storage). It works by adding up the basic components of a message, typically the asserted bits, and storing the resulting value. Later, anyone can perform the same operation on the data, compare the result to the authentic checksum, and (assuming that the sums match) conclude that the message was probably not corrupted.“ – quoted from wikipedia.
As stated above, the checksum is primarily used to check jj2 UDP packets for corruption. Packets with corrupted/modified data will automatically be dropped and packets with proper checksum will be processed. The point of this article is to show users how to reproduce the checksum, should they by any means find themselves in need to build UDP packets for jj2. But before we go deep into detail of the algorithm, we need a little knowledge about jj2 packets first.
There are two types of jj2 packets according to the protocol they use – TCP and UDP. They both have different structures, but both of them have their common pattern that matches all the packets of a type. Here is how each of the the normal jj2 packets are structured:
TCP: [Packet length (1 byte)][Packet ID (1 byte)] + Extra data (varies)
UDP: [Checksum (2 bytes)][Packet ID (1 byte)] + Extra data (varies)
The structure of a TCP packet is really simple. The first byte resembles actual length of the whole TCP packet. Unlike UDP, TCP packets have no checksum. This can actually be good at some point. Second byte is used for packet identification. This basically tells jj2 what type of data the rest of the packet contains and therefore how to process it. The length and meaning of the extra data that follows packet header varries according to the packet function (packet ID).
The UDP packet structure is similar to that of TCP, but not quite the same. Unlike TCP, the UDP packets have no reserved bytes for packet length in the header, but they do have a checksum instead. The first two bytes are always the checksum. We shall take a look at this part in detail soon. The second part will logically be the packet ID, again used for telling jj2 what kind of data follows the header so that jj2 may process it accordingly. The extra data that follows the header again differs by packet ID. Most of the time it has some basic structure in both cases, TCP and UDP, which I am not going to discuss here.
Now let’s take an actual look at some jj2 packets.
A simple TCP packet:
0000 09 0F AC 06 32 31 20 20 01 .. .. .. .. .. .. .. ….21 .
A simple UDP packet:
0000 95 90 0A 08 70 61 73 73 77 6F 72 64 .. .. .. .. ….password
The TCP packet (shown above) is the first packet that jj2 sends to servers when attempting to join a game. From the data you can clearly see the length of the packet is 9 bytes (represented by the first byte), packet ID for join requests appears to be 0F which is 15 in decimal (second byte) and the extra data that follows it. Byte 3 and 4 represent the client-side UDP port where the client is listening for incoming UDP data from the server. The next four bytes (5, 6, 7 and 8) represent your jj2 version and the last byte (9) tells the number of local players that want to join the server.
The UDP packet (shown above) is a password packet – the one you send to a private server when attempting to join through the password screen. It sends the password you entered directly to the server for verification. The password I entered is… well… “password”. The first two bytes (95 90) are no doubt the checksum. The third byte (0A) is used for packet identification and the fourth byte tells the length of the password, which follows afterwards.
Now let’s see how to reproduce the checksum on the given UDP example.
The checksum algorithm
Finally we come to the point of reproducing a checksum. We will be doing so by using the example UDP packet provided above. Since we are calculating the checksum, it is only logical that the checksum bytes in the packet will not be included in the calculation, but the rest of the data will. Now let’s take a look at the actual algorithm. The checksum consists of 2 bytes. These bytes are not both part of a single number, but are rather calculated independantly.
First byte: The easier one. It is a sum of all bytes in the packet (excluding the first – length itself) plus one. Additionally it is kept in size of one byte by subtracting 251 (FB in HEX) from the number each time the number goes beyond the length of it.
“01” + 0A + 08 + 70 + 61 + 73 + 73 + 77 + 6F + 72 + 64 = 386
386 – 03 * FB = 95
Second byte: The tougher one. This one was a bit more complex, but I have managed to crack the nut with some math and detailed on-paper analysis. It uses the data length plus one as its starting number. Then it adds to the number the value of each byte in the packet multiplied by the reverse location of that byte. Again, the number is kept in size of one byte by subtracting 251 (FB in HEX) from it each time it exceeds the value 251.
“01” + 0A = 0B
0B + 0A * (0A – 01 + 01) = 6F
6F + 08 * (0A – 02 + 01) = B7
B7 + 70 * (0A – 03 + 01) = 437 (437 – 04 * FB = 4B)
4B + 61 * (0A – 04 + 01) = 2F2 (2F2 – 02 * FB = FC)
FC + 73 * (0A – 05 + 01) = 3AE (3AE – 03 * FB = BD)
BD + 73 * (0A – 06 + 01) = 2FC (2FC – 03 * FB = 0B)
0B + 77 * (0A – 07 + 01) = 1E7 (1E7 – 01 * FB = EC)
EC + 6F * (0A – 08 + 01) = 239 (239 – 02 * FB = 43)
43 + 72 * (0A – 09 + 01) = 127 (127 – 01 * FB = 2C)
2C + 64 * (0A – 0A + 01) = 90
And finally here is the source code for calculating the checksum that I have programmed in Visual Basic (thanks to Neobeo for code clarification and an alignment bugfix). The first utility where this algohithm has been used is Spazyman’s JazzForce 1.1c which uses the algorithm to form password packets, allowing users to join passworded servers by entering the password over JazzForce rather than jj2.
NOTE: The source code may give you some errors in VB IDE due to this website changing certain characters. Rewriting the code, or removing comments might fix the problem.
Dim I As Long ‘Used in FOR loops lower in code
Dim pcLength As Long ‘I have used longs to prevent any overflows with longer packets
pcLength = Len(Packet) ‘Get the data length
‘First byte! It is a sum of all ASCII bytes in the packet + 1
FirstByte = 1 ‘Base number
For I = 1 To pcLength Step 1
FirstByte = FirstByte + Asc(Mid(Packet, I, 1)) ‘Sum of all ASCII values
FirstByte = FirstByte Mod 251 ‘Keep the number in length of 1 byte
‘Second byte! This is a multiplication of some sort
SecondByte = 1 + pcLength ‘Base Number
For I = 1 To pcLength Step 1
SecondByte = SecondByte + Asc(Mid(Packet, I, 1)) * (pcLength – I + 1) ‘ASC value of each byte in packet – this was the trickiest part
SecondByte = SecondByte Mod 251 ‘Keep the number in length of 1 byte
pcChecksum = Chr(FirstByte) & Chr(SecondByte) ‘Return the 2 bytes
Simply copy&paste the source code into a module and you are ready to start reproducing UDP packets. Remember that the checksum always comes before any packet data you wish to send. You can try using the following code and see that the algorithm will in fact output the UDP packet data given in the example above along with a proper checksum.
A C++ version of the code (thanks, Neobeo):
We have taken a look at how jj2 calculates checksums for its UDP packets. I hope this article proves useful to somebody in the future and that you enjoyed reading it as much as I enjoyed writing it. The checksum was not all that difficult to figure out. Basically I believe that anyone could have done it with a bunch of basic math skills and some good will.
Eat your lima beans, Johnny.