Hi folks, attached is a outdated (e.g, works w/ 3.0.x and hasn't been updated for 3.1.x as I don't play the game at the moment). Might give people some ideas for those interested in doing things at the packet level (the WorldPacketConsumer class might be the most useful).
It is written in python. Implements a proxying Realm Server and a proxying World Server and decrypts a few types of packets (and logs the rest). It reads the session key directly from the wow process using ReadProcessMemory.
When I re-up my account I might update it for 3.1, but till then hope it is useful for someone. I'd probably use libpcap/winpcap in the future.
A session key (which is the 20 bytes you're referring to) is sent somewhere during the logon process. Once that packet is sent, all subsequent packets are encrypted, and compressed using the 20 byte session key. The headers are never encrypted. (Or was it only the headers are encrypted? Bah...)
A session key (which is the 20 bytes you're referring to) is sent somewhere during the logon process. Once that packet is sent, all subsequent packets are encrypted, and compressed using the 20 byte session key. The headers are never encrypted. (Or was it only the headers are encrypted? Bah...)
Send/Recv have their own individual 'index' of the key to track their progress, so it only applies to the direction of the packet. but you're correct, that CMSG's are 2 bytes longer (with the extra junk in the trunk thats useless)
However, the session key is _never_ sent over the wire (not in any usable form, anyways). The session key is an HMAC sha1 of K in SRP6 implementation used for authentication (see: SRP: Design Specifications - though wow does reverse a few values, it's the same concept). Once you're connected to the world server, the server requests authentication, sending a seed, requesting a digest of your seed + the server seed and you're calculated K (for proofing purposes, of course). The client then sends the auth response with that digest, and any traffic after that (headers only), is encrypted.
Last edited by BoogieManTM; 06-06-2009 at 02:50 AM.
So, what's the best way to store the packet? I thought about a class, but how would you store the header? unsigned char[]? That would be annoying to manually assign like that whenever I wanted a new packet though. More help is appreciated.
EDIT: ehhhh,
Code:
struct Packet
{
public:
uint16 opcode;
uint16 size;
uint16 junk;
unsigned int movementFlags;
short unk1;
unsigned int timestamp;
float x;
float y;
float z;
float orientation;
unsigned int unk2;
};
So, what's the best way to store the packet? I thought about a class, but how would you store the header? unsigned char[]? That would be annoying to manually assign like that whenever I wanted a new packet though. More help is appreciated.
EDIT: ehhhh,
Code:
struct Packet
{
public:
uint16 opcode;
uint16 size;
uint16 junk;
unsigned int movementFlags;
short unk1;
unsigned int timestamp;
float x;
float y;
float z;
float orientation;
unsigned int unk2;
};
I use a variant of BinaryWriter in C# to build my packets. For C++ I use a ByteBuffer class, similar to wow's CDataStore. It's basically the same concept, an abstract class to manage a raw array of bytes. The ByteBuffer class (you can find it in Ascent's code, possibly mangos too) is just a utility class wrapped around a std::vector of bytes, appending appropriate based on size.
That way you have a generic container to build any packets you want. When i go to encrypt the header, you know any packet going out, you just encrypt the first 6 bytes of the data in that packet prior to it being sent out. I also calculate size just prior to encryption.
Final question, does GetTickCount() return a valid number for the timestamp? or is it one of the other timing functions?
I believe I have seen calls to GetTickCount() in my thus-far brief examination of the relevant code.
Originally Posted by BoogieManTM
That way you have a generic container to build any packets you want. When i go to encrypt the header, you know any packet going out, you just encrypt the first 6 bytes of the data in that packet prior to it being sent out. I also calculate size just prior to encryption.
Do you have your own encryption routine(s) or do you use WoW's? If the later, can you offer some guidance on locating it?
Throw your packet into the base send function. It encrypts and everything. FOR YOU. Or you could make a packet using 0x8361B0. And then call send at 0x5F92F0. Look at any of the lua functions and their sub-calls. They call the first address a few times, and then call send. Neat stuff.
I believe I have seen calls to GetTickCount() in my thus-far brief examination of the relevant code.
My examinations of packet data have shown a few different time formats. One of the more common is a "milliseconds since sync" value. You'll see various [S/C]MSG_TIME_SYNC_REQUEST packets where the client and server basically agree upon a sync time that is a millisecond value. I've looked at the actual number and it doesn't make sense in any known format (epoch time, etc.), so it's most likely something that's only locally relevant, like milliseconds since some server was rebooted, or something. But that's not important, since you know the time when the sync response was sent, and you know the "magic number," and you know it's in milliseconds. You can do the math from there, for future packets, if you capture the sync response.
Originally Posted by bierstud
Do you have your own encryption routine(s) or do you use WoW's? If the later, can you offer some guidance on locating it?
You can encrypt/decrypt completely out of process. All you need are the client and server seeds, and the session key. Everything else is using standard cryptology methods available in just about every language. The seeds you can hardcode (do they ever change? doesn't matter since they're easy to find in the binary), and the session key you can just rip from memory. I've got it working in C# (with massive props to the sniffitzt guys, who produced the initial code, albeit in -- *shudder* -- java). I would release it, but I believe that that would technically be a DMCA "anti-circumvention" breach, and I really don't want to be sued.
My examinations of packet data have shown a few different time formats. One of the more common is a "milliseconds since sync" value. You'll see various [S/C]MSG_TIME_SYNC_REQUEST packets where the client and server basically agree upon a sync time that is a millisecond value. I've looked at the actual number and it doesn't make sense in any known format (epoch time, etc.), so it's most likely something that's only locally relevant, like milliseconds since some server was rebooted, or something. But that's not important, since you know the time when the sync response was sent, and you know the "magic number," and you know it's in milliseconds. You can do the math from there, for future packets, if you capture the sync response.
My understanding of the time_sync packets are just the server's way of verifying the client's system tick. Probably for use with checking to see if someone is altering their timestamps in movement packets, but not altering the time sync.
In my clientless, all I'm sending for my CMSG_TIME_SYNC is the sequence id, and Environment.TickCount. server seems to be fine with that