Nelson's log

libenet / league of legends protocol success!

Last year I looked into the League of Legends real time protocol, the format of the UDP messages between the game server and clients. My recent lag problems motivated me to look again and I’ve gotten somewhere this time.

The protocol is said to be based on libenet 1.2 with some modifications. The body of the protocol itself is encrypted, presumably to make it harder for third party hacks to sniff data from the game. (It doesn’t make it impossible though, so once again DRM frustrates legit use without dissuading cheaters.) But I don’t care about the body, I just want the enet headers, the sequence numbers and retransmits and stuff. And that’s in the clear!

The best guide I’ve found is this Wireshark dissector, or rather an updated version Boreeas kindly gave me that isn’t checked in anywhere. The key thing is inside the UDP packet, the first 8 bytes are a not-very-interesting header. Then the 9th byte is an Enet command, the 10th byte is a channel number, and the 11th and 12th bytes are the sequence number. (To complicate things sometimes only the first 6 bytes are the header, so the command is the 7th byte, etc.) ACK packets have some bogus sequence number, but the first 2 bytes after that are the sequence number of the packet being acknowledged.

So I put all that together and wrote some Python Impacket code and now I have something printing a summary of UDP captures I made. Below is a few lines from my outputter. This shows the server sending a reliable packet on channel 3 numbered 01a9, then another numbered 01aa, then another number 01ac. My client acknowledges all three. But what happened to 01ab? The server sends that along 200ms later, either because it arrived out of order or else because the server knew to try to send it again. Note that in the meantime 01ad also went missing; that never showed up, so I’m confused. Still, it’s a start. I assume the LoL client shows lag if a reliable packet doesn’t arrive properly.


SREL   03 01a9 00167.521401   00000000: 0D 89 78 BC A7 80 96 CE  86 03 01 A9 00 38 D6 23  ..x..........8.#
  ACKK 03 01a9 00167.521538   00000000: F3 CC 6D 92 A7 03 01 03  00 00 01 A9 96 CE        ..m...........
  SUNS 01 0000 00167.542210   00000000: F3 CC 6D 92 A7 03 49 01  00 00 03 8C 00 0A 87 99  ..m...I.........
SREL   03 01aa 00167.562514   00000000: 0D 89 78 BC A7 80 96 E5  86 03 01 AA 00 07 6F 00  ..x...........o.
  ACKK 03 01aa 00167.562663   00000000: F3 CC 6D 92 A7 03 01 03  00 00 01 AA 96 E5        ..m...........
  SREL 01 0065 00167.583485   00000000: F3 CC 6D 92 A7 83 8E B4  86 01 00 65 00 1F 6B 4F  ..m........e..kO
SREL   03 01ac 00167.629336   00000000: 0D 89 78 BC A7 80 97 28  86 03 01 AC 00 18 D8 AB  ..x....(........
ACKK   01 0065 00167.629393   00000000: 0D 89 78 BC A7 00 01 01  01 AC 00 65 8E B4        ..x........e..
  ACKK 03 01ac 00167.629477   00000000: F3 CC 6D 92 A7 03 01 03  00 65 01 AC 97 28        ..m......e...(
SUNS   04 0000 00167.688278   00000000: 0D 89 78 BC A7 00 49 04  00 00 03 DD 00 3B BA D6  ..x...I......;..
SREL   03 01ae 00167.688330   00000000: 0D 89 78 BC A7 80 97 64  86 03 01 AE 00 10 F5 54  ..x....d.......T
  ACKK 03 01ae 00167.688425   00000000: F3 CC 6D 92 A7 03 01 03  00 65 01 AE 97 64        ..m......e...d
  SREL 01 0066 00167.709221   00000000: F3 CC 6D 92 A7 83 8F 31  86 01 00 66 00 1F 6B 4F  ..m....1...f..kO
SREL   03 01af 00167.736732   00000000: 0D 89 78 BC A7 80 97 A5  86 03 01 AF 00 44 2B 25  ..x..........D+%
  ACKK 03 01af 00167.736863   00000000: F3 CC 6D 92 A7 03 01 03  00 66 01 AF 97 A5        ..m......f....
ACKK   01 0066 00167.739947   00000000: 0D 89 78 BC A7 00 01 01  01 93 00 66 8F 31        ..x........f.1
  SUNS 01 0000 00167.740008   00000000: F3 CC 6D 92 A7 03 49 01  00 00 03 8F 00 0A 23 68  ..m...I.......#h
SREL   03 01ab 00167.765224   00000000: 0D 89 78 BC A7 80 97 C2  86 03 01 AB 00 1B BC 8D  ..x.............
  ACKK 03 01ab 00167.765389   00000000: F3 CC 6D 92 A7 03 01 03  00 00 01 AB 97 C2 01 03  ..m.............
SUNS   04 0000 00167.770715   00000000: 0D 89 78 BC A7 00 49 04  00 00 03 DF 00 23 31 79  ..x...I......#1y

Here’s a breakdown of packet types from an ARAM game I recorded. 23.77% of packets are from my client to the server, “send unsequenced”. Huh, what does my client have to say to the server that’s so volumnious and yet unimportant? About 41% of traffic is the server sending reliable packets and the client acknowledging them and another 11% is the client sending reliable packets and the server acknowledging them. 21% of the traffic is unsequenced packets from the server, or about the same number of packets as reliable ones. I’d expected more of a bias to unreliable packets from the server than that.


   20086 .2377   SUNS
   17498 .2070   ACKK
   17475 .2068 SREL
   15406 .1823 SUNS
    5670 .0671   SREL
    5101 .0604 ACKK
    1528 .0181 SUNR
    1311 .0155   PING
     203 .0024   SUNR
     197 .0023 PING
      40 .0005 SFRG
       1 .0000 VCON
       1 .0000   CONN