wot-replays.org: Replay file secrets #1: The beginning, an analysis, and some random
After some consideration I decided on the following:
Given WG's abysmal track record with regards to listening to their customers, and their equally abysmal track record at actually delivering patches that do not crash the game or require you to reinstall the game, I have lost confidence that the security issue I reported will be properly fixed, if it is even looked at. This is not a slight towards the moderators and community managers who have been (let's be fair here people) very responsive and have done their best, as far as I am concerned. I've got a feeling WG doesn't listen to them much either.
It has now been about two weeks since first reporting the issue, and I have now verified that your private messages also end up in replay files if you are in battle whilst receiving any. Having now also decided that playing WoT has become very much un-fun if your game crashes after every battle, I've decided to go all out, and let the chips (read: banstick) fall where they may. Since being nice to WG and asking them things does not seem to work, perhaps a swift kick or two in the clackers might do the trick.
You can read more after the jump since this will be a loooooooong post...
So, replay files and chat messages. After having done my magic voodoo dance on the .pyc files (for the un-initiated, .pyc files are byte-code python files, they're stored like that after the interpreter translates the script to bytecode, so that step can be skipped on the next run. Also a great way to "hide" your code, sort of). and having turned them into something that is somewhat human-readable, I started poking at things.
What I found is that even though the un-pyc tool will convert the files to merely a list of opcodes (instructions to the interpreter) and doesn't include comments or any other things, you can definitely tell there's about 6 to 7 different people working on the codebase. They are of varying levels in skill as well, and it seems they don't really communicate much, because I've now seen at least 3 different implementations of the same bit of code that does the same thing, in a slightly different fashion. Indicative of the left hand not knowing what the right hand is doing.
Anyway, a bit of digging later and I discovered that the replay file manager is built in to the game executable itself, but that nearly every last subsystem in the game (chat, etc.) ties back into it.This means that as soon as you hit "Battle" and have replays enabled, your entire network stream gets dumped to disk. The problem here is obvious, since chat messages are part of this stream. Given of course that during a battle, only the 'team' and 'common' channels are displayed, it seems this is perfectly okay. It's not.
Of course, you must wonder, because:
- 0.7.1 replays are merely compressed with Zlib. Judging from old parsers, they contain the exact same information as "current day" replays.
- 0.7.2 (and up) replays were switched to have a few plaintext blocks at the start of the file, and then followed by the same data as the 0.7.1 replay file, except now besides being compressed, it is also encrypted.
To me, the only reason to encrypt anything is to make sure something stays "secret". I have a hunch that WG is already aware of the fact your chat messages go into a replay file, and are blissfully ignoring it since hey, the file is encrypted, right?
Generally speaking, if you want to find information, you dig for it. There are multiple ways of digging, and one that takes a lot of skill and patience (patience that I don't have) is running WoT under a live debugger. It'll allow you to inspect the stack, and see the call chains. A while ago I was informed that one of our Russian brethren had already done this, and had discovered the encryption algorithm (Blowfish) and the encryption key. Now I'm still such a nice guy that I'm not going to outright give that key to you, but it's available if you know where to look.
So, how is it done? Well, it's done in a way that to me screams "what the hell are you people thinking". From the game's perspective, what happens is this:
- The replay data is first compressed with Zlib
- Then, the first 8 bytes of compressed replay data are encrypted and written to disk
- From here to the end of the file, the next compressed 8 bytes are taken, and a XOR is done with the previous 8 unencrypted bytes. Then the 8 byte result is encrypted and written to disk.
The XOR is there as a way to obfuscate the data before encryption to make it harder to do a cryptanalysis - but it's the "easiest" way of mixing available. That aside...
The process to decrypt a replay is literally done in reverse; in pseudo-code you would get something like this:
Which is quite simple depending on your language of choice. My poison is Perl, and in Perl it looks like this:
Anyway, so after having done that, you run the entire wad of data through Zlib to uncompress it, and what you end up with is now an uncompressed, unencrypted replay file. This is where the fun begins, and as an introduction I'll start off with some data you can obtain from here.Please put on your bytes, offset and lengths hat.
The "proper" World of Tanks version can be obtained as follows:
- Seek to offset 12 in the uncompressed replay file
- Read 4 bytes. This is an unsigned long containing the length of the following string, we'll just call it length from now on
- Read length bytes.
The result from step #3 is the WoT version string, it will look like "World of Tanks v.0.7.4 #220" and is similar to the one you see on the splash screen. This not only gets you the major version, but also the patch level. If the string happens to contain "Public Test" or "Common Test", it's a replay from the test server.
In the next installment, I'll move on to vehicle information.