Información actualizada sobre WoW 4.0 – Cataclismo [obsoleto]

En un post del 3 de Diciembre, uno de los desarrolladores de trinity ha intentado ampliar información sobre la dificultad de implementar el nuevo sistema de funcionamiento de WoW Cataclismo en Trinity. Basicamente dice que sería factible, pero supondría tal cantidad de trabajo, y prácticamente rehacer de nuevo el servidor, que puede que se haga un proyecto de servidor aparte, pero que en el Trinity como lo conocemos hoy, no será implementado.

dicho esto, habrá que esperar a que el nuevo proyecto de emulación de Cataclismo se haga público y sea suficientemente estable como para poder ofrecerlo a los jugadores con una mínima garantía de funcionamiento.

A continuación, os dejamos el post completo para vuestra información.

Well, I'm almost done discussing this topic. After this post, I think I will be done.

I have spent the last few weeks trying, very hard, to do as much as I can reverse-engineering the 4.x client and thus gleaning some new knowledge from it. In that pursuit I believe I have overcome the problem that we once thought was our primary roadblock - "random" opcodes.

Let's have a talk about those first.

Random opcodes, if they were truly random, would be a bitch to figure out. If Blizzard were to, say, just pipe /dev/random into a text file and remove duplicates, they could have a set of true random numbers to use in order to create a set of opcodes in the client. Afterwards, simply randomizing order of initialization in functions - and doing direct assignment, as they're doing, rather than indirect assignment - would make a huge difference in terms of the complexity of finding new opcodes based on the old.

As it is, Blizzard hasn't done so well. They have left many opcodes hardcoded into the client - such as, for example, many movement opcodes, miscellaneous ones that contribute very little data, and SMSG_COMPRESSED_UPDATE_OBJECT - and those that are not hardcoded are on average still registered in the same order as they were in the 3.3.5a client.

The problem that we have there, however, is that the exact opcodes for those packets are nowhere in the client. The handlers are assigned to a giant array inside of the clientside CNetClient class. That giant array consists, really, of a ton of function pointers - where the index of the pointer is a function of the opcode that leads to that particular packet. Suffice to say, Blizzard did a good job there. The function(s) (as there is a new one with each "major" client update) have thus far all been non-inverseable. What that means is - given an index, it is not possible to hunt down a single opcode for that packet.

However, while this may be true, it is also true that the function, being non-inverseable, is a lossy function. By preventing us from going backwards, that means that they have to lose information - and in this case, simply having any individual opcode that resolves to the same handler in all cases is just as good for the purposes of an "emulator" server as having the exact opcode that Blizzard uses on their servers.

Very simply, we can just brute-force each opcode based on its index.

The relevant formula in 4.0.3.13329 is as follows:

index = opcode & 3 | ((opcode & 8 | ((opcode & 0x20 | ((opcode & 0x300 | (opcode >> 1) & 0x7C00) >> 2)) >> 1)) >> 1);

In order to get a list of opcodes that should, in theory, resolve to that handler, I just run the following Java function with the index as input:

private static void printOpcodesForOffset(long offset) {
for (long opcode = 0; opcode < 0x10000; opcode++) { if (((opcode & 0x5BFF) == 0x1000) || ((opcode & 0xCF07) == 0x800)) continue; if ((opcode & 3 | ((opcode & 8 | ((opcode & 0x20 | ((opcode & 0x300 | (opcode >> 1) & 0x7C00) >> 2)) >> 1)) >> 1)) == offset) {
System.out.println("t0x" + Long.toHexString(opcode).toUpperCase());
}
}
}

And we'll get a list of all possible opcodes for that index. To track it down to a single opcode, we can just compare against a sniff from blizzard - or, in some cases, the functions themselves contain hardcoded numbers that we can then use as the confirmed opcodes.

That in and of itself solves the problem for most Server -> Client opcodes. For Client -> Server opcodes, the struggle is slightly more difficult. From there, we can just track when integers get added into a packet object, and figure out when those functions get called. Once we know that, we can figure out which packet is being sent, and so we have the new Client -> Server opcodes. This process, as you can imagine, is a pain in the ass. Modern reverse-engineering tools such as binary differs and pattern creators make this easier, but it is still substantially more annoying than I am really willing to deal with for hours on end.

So that's the random opcodes business.

Next up, is authentication. For a long time, Blizzard used a system called Grunt for all authentication purposes when it came to WoW. Grunt was mostly cracked relatively early, and in fact all modern WoW "emulators" use Grunt as their authentication protocol. As a sloppy implementation of SRP6 with a handful of extra things added on on top, Grunt is relatively easy to implement and track down in any new client.

However, midway through Wrath of the Lich King, Blizzard switched to their Battle.net 2 authentication scheme. This is something that is not currently well-understood; and due to extremely heavy obfuscation in the Battle.net DLL and the even heavier obfuscation in all client methods related to Battle.net authentication, it is difficult to make meaningful progress. In addition, since Battle.net relies on different communication protocols and a new form of password hashing (as well as a seemingly correct implementation of SRP6a), it is substantially harder to fake a Battle.net authentication server.

The danger of Blizzard simply removing Grunt from the client is very real. While there may be ways around the problem, we have not found any as of yet.

So that's the authentication trouble.

Next up is the issue of SMSG_REDIRECT_CLIENT.

Let's start with a quick runthrough of RSA encryption.

Wouldn't it be nice to have an encryption scheme where you could publish an encryption key in a public forum - such as a newspaper - thus allowing anyone to write you messages, but yet not be able to read them? In other words, wouldn't it be nice to have an asymmetric encryption scheme, whereby there are two different keys - one encryptor, usually, and one decryptor - and where you cannot go from the encryptor key to the decryptor key (or vice-versa)?

In addition, wouldn't it be nice to be able to append a block of encrypted data to a plaintext message, ensuring that the message has not been tampered with (this is known as signing)?

These kinds of encryption do exist. RSA is one of them.

The security of RSA relies on its method of key generation: the fact that the entire key is based on a product of two extremely large prime numbers, in addition to several modular exponentiation functions (which are thought to not be reversable). The problem is simple: given a large number, is it possible to quickly and efficiently factor it into two (or more, for that matter) large (or small, for that matter) primes? So far, it appears as though the answer to that question is "No." Or at least, not in polynomial time (it is possible to bruteforce a key, however - doing so for a key of reasonable length requires more time than the current age of the universe).

Now, you might ask, alright. So, how does this matter?

It's very simple. The client, upon connecting to the server, asks for a very simple thing. "Where do I send my packets now?"

SMSG_REDIRECT_CLIENT is the server's response, signed through Blizzard's private key. The client contains the public key - but Blizzard's private exponent isn't known, and thus it is impossible to create an encrypted message for this particular public key, so far as we know.

If the client does not receive this packet, it by default just doesn't send a ton of the packets that we need to be sent to us - things like movement data, spell messages, and a ton of other information. Sure, it'll work as a "sandbox" - the player will be able to move around - but it won't work serverside, or for more than one client.

There are two ways around this problem that do not involve bruteforcing Blizzard's private key - an impossible task.

1. Edit the client. Trinity will not condone this.
2. Make a launcher that "patches" the client's memory at runtime. Trinity is not likely to condone this.

Now, streamed data.

There is an absurd amount of new data in the Cataclysm world. Each new zone map, each new creature, each new quest - all of these have data attached to them. Cataclysm offers the client a new way to download this data - a way that we, no matter how hard we try, are unlikely to be able to replicate. Thus, in order to effectively play on a private server, one would need to have a client that already has all of this data - all of the gigabytes upon gigabytes of data that means.

In addition, the existence of streamed data means that Blizzard could potentially change anything at any time, throwing back our efforts substantially while players are ingame. This by itself is a large roadblock - if they can distribute patches more easily, they have no reason not to do it more often. And each of those patches could change communication protocols, leaving us to re-reverse-engineer their information.

However, there is doubtless a way around it - even if that way around it is just more reverse-engineering time and an end to the drive to being at the latest version of the game.

Now the last problem: the new content and the new mechanics.

This is the most important problem code-wise. The other three are primarily reverse-engineering problems; once solved, these problems are easy to code away at. However, the new mechanics, and the new content, is quite simply not possible to patch onto the current version of Trinity without a significant rewrite of the majority of the core. Talents alone would need a full rewrite, as would nearly all spells and auras (as they scale now, recall!); even things as recent as the Dungeon Finder or the calendar system changed drastically with the arrival of Cataclysm. Recoding that much of the core would be a massive chore - equivalent, even, to just starting from scratch.

So.

Cataclysm: it's possible. There are ways around just about everything. However, Trinity will not support it as it is. Why, you ask? Because we refuse to take that step of modifying the client. Because many of the devs do not have the energy, the time or the desire to rewrite the vast majority of the core in order to add support for a new client version. Because it is not in the style of a learning project to just update to a new version of WoW every time Blizzard pushes it out.

So let's stop discussing. The reasons have been stated. The logic is there. There may be an emulator project for Cataclysm; suffice to say, it will not be Trinity. Brian has made that clear, and I hope this post has put all of the complaining about lack of reasoning to rest.

~ Silinoron

Note: All reverse-engineering-specific information here is directly from my work, Zor's, ralek's, or TOM_RUS's.