WoW Memory EditingWoW Memory Editing for learning purposes only.
This section is more advanced than others on MMOwnedRead the section specific rules, infractions will be given out if u break them!That is including the expectations! - If you don't meet them then don't post
I've been looking at WoW's packets that it sends when I move. I've been comparing the data to the opcodes in the MangOS source code. I haven't seen any of the opcodes pointed to by the parameter. Any help here?
Donate to remove ads, get your "DONATOR title, and get access to the MMOwned community's elite Shoutbawx.
Not really much right now, I was just putting a bp in my detoured SendPacket function.
EDIT: Ok, in the SendPacket() function, what is the data stored as? I know that kynox uses a certain class for his packet, CDataStore or something like that... I'm gonna start logging the packets and see if I can see anything different.
The address I'm detouring is 0x005843A0. I'm not sure if this is encrypted or not. In the case that it's not, where is the opcode located? I'd imagine it being right at the top...
I have the whole thing downloaded on my PC :P I'm about to give this another go with logging and hoping I find it eventually. For all I know right now, I could be looking at pretty little ENCRYPTED packets...
EDIT: What logging lib do you guys use for VC++? I've googled but all I came up with is log4cxx, which appears to be for gcc.
The packet headers are indeed scrambled. They're xor'd with a key obtained by the SRP authentication. The key is 20 bytes long (Not sure where you'd find it in the client). Sent packets headers (Client->Server, AKA CMSG in emulators) are 6 bytes long, with a uint16 size, and uint32 opcode. Received messages (Server->Client, aka SMSG) are only 2 bytes, with just the opcode.
Here's a C# sniplet of my class to handle this encryption.
Code:
/// <summary>
/// This class handles the encryption that is done on the headers of world server packets.
/// The Key is 20 bytes long
/// </summary>
public class WoWCrypt
{
public class PacketKeyGenerator
{
static readonly byte[] SeedKey = { 0x38, 0xA7, 0x83, 0x15, 0xF8, 0x92, 0x25, 0x30, 0x71, 0x98, 0x67, 0xB1, 0x8C, 0x4, 0xE2, 0xAA };
public static byte[] GenerateKey(byte[] sessionKey)
{
byte[] firstBuffer = new byte[64];
byte[] secondBuffer = new byte[64];
memset(firstBuffer, 0x36);
memset(secondBuffer, 0x5C);
for (int i = 0; i < SeedKey.Length; i++)
{
firstBuffer[i] = (byte)(SeedKey[i] ^ firstBuffer[i]);
secondBuffer[i] = (byte)(SeedKey[i] ^ secondBuffer[i]);
}
Sha1Hash sha = new Sha1Hash();
sha.Update(firstBuffer);
sha.Update(sessionKey);
byte[] tempDigest = sha.Final();
sha = new Sha1Hash();
sha.Update(secondBuffer);
sha.Update(tempDigest);
byte[] finalKey = sha.Final();
return finalKey;
}
private static void memset(byte[] buffer, byte value)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = value;
}
}
}
private bool mInitialised = false;
// Encryption state
private byte mEncPrev;
public int mEncIndex;
// Decryption state
public byte mDecPrev;
public int mDecIndex;
public byte[] mKey;
public void Init(byte[] Key)
{
mKey = PacketKeyGenerator.GenerateKey(Key);
mInitialised = true;
}
public byte GetDecPrev()
{
return mDecPrev;
}
public void SetDecPrev(byte SetTo)
{
mDecPrev = SetTo;
}
public int GetDecIndex()
{
return mDecIndex;
}
public void SetDecIndex(int SetTo)
{
mDecIndex = SetTo;
}
public void Decrypt(byte[] Data, int Length)
{
if (mInitialised == false) return;
for(int i = 0; i < Length; ++i)
{
byte x = (byte)((Data[i] - mDecPrev) ^ mKey[mDecIndex]);
++mDecIndex;
mDecIndex %= mKey.Length;
mDecPrev = Data[i];
Data[i] = x;
}
}
public void Encrypt(byte[] Data, int Length)
{
if (mInitialised == false) return;
for(int i = 0; i < Length; ++i)
{
byte x = (byte)((Data[i] ^ mKey[mEncIndex]) + mEncPrev);
++mEncIndex;
mEncIndex %= mKey.Length;
mEncPrev = x;
Data[i] = x;
}
}
}
I've been thinking of doing a brute-forcer to brute force the key (fairly simple to do) on pcap's of wow's tcp stream. but that is another method of obtaining the encryption key without touching the client memory (but for you guys, whats the fun in that?). For example, capturing 20 or so ping packets (because they're sequential and easy to identify) would be sufficient data to brute the key. much like how WEP bruter's work.
Last edited by BoogieManTM; 12-15-2008 at 03:02 PM.
Ok, so I'm awfully confused. I'm detouring at 0x005843A0, is that even the correct address? I have it logging the value of the parameter and address everytime that it gets called, but it only logs once each time I log into WoW and inject... Here's my code.
The packet headers are indeed scrambled. They're xor'd with a key obtained by the SRP authentication. The key is 20 bytes long (Not sure where you'd find it in the client). Sent packets headers (Client->Server, AKA CMSG in emulators) are 6 bytes long, with a uint16 size, and uint32 opcode. Received messages (Server->Client, aka SMSG) are only 2 bytes, with just the opcode.
Here's a C# sniplet of my class to handle this encryption.
Code:
/// <summary>
/// This class handles the encryption that is done on the headers of world server packets.
/// The Key is 20 bytes long
/// </summary>
public class WoWCrypt
{
public class PacketKeyGenerator
{
static readonly byte[] SeedKey = { 0x38, 0xA7, 0x83, 0x15, 0xF8, 0x92, 0x25, 0x30, 0x71, 0x98, 0x67, 0xB1, 0x8C, 0x4, 0xE2, 0xAA };
public static byte[] GenerateKey(byte[] sessionKey)
{
byte[] firstBuffer = new byte[64];
byte[] secondBuffer = new byte[64];
memset(firstBuffer, 0x36);
memset(secondBuffer, 0x5C);
for (int i = 0; i < SeedKey.Length; i++)
{
firstBuffer[i] = (byte)(SeedKey[i] ^ firstBuffer[i]);
secondBuffer[i] = (byte)(SeedKey[i] ^ secondBuffer[i]);
}
Sha1Hash sha = new Sha1Hash();
sha.Update(firstBuffer);
sha.Update(sessionKey);
byte[] tempDigest = sha.Final();
sha = new Sha1Hash();
sha.Update(secondBuffer);
sha.Update(tempDigest);
byte[] finalKey = sha.Final();
return finalKey;
}
private static void memset(byte[] buffer, byte value)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = value;
}
}
}
private bool mInitialised = false;
// Encryption state
private byte mEncPrev;
public int mEncIndex;
// Decryption state
public byte mDecPrev;
public int mDecIndex;
public byte[] mKey;
public void Init(byte[] Key)
{
mKey = PacketKeyGenerator.GenerateKey(Key);
mInitialised = true;
}
public byte GetDecPrev()
{
return mDecPrev;
}
public void SetDecPrev(byte SetTo)
{
mDecPrev = SetTo;
}
public int GetDecIndex()
{
return mDecIndex;
}
public void SetDecIndex(int SetTo)
{
mDecIndex = SetTo;
}
public void Decrypt(byte[] Data, int Length)
{
if (mInitialised == false) return;
for(int i = 0; i < Length; ++i)
{
byte x = (byte)((Data[i] - mDecPrev) ^ mKey[mDecIndex]);
++mDecIndex;
mDecIndex %= mKey.Length;
mDecPrev = Data[i];
Data[i] = x;
}
}
public void Encrypt(byte[] Data, int Length)
{
if (mInitialised == false) return;
for(int i = 0; i < Length; ++i)
{
byte x = (byte)((Data[i] ^ mKey[mEncIndex]) + mEncPrev);
++mEncIndex;
mEncIndex %= mKey.Length;
mEncPrev = x;
Data[i] = x;
}
}
}
I've been thinking of doing a brute-forcer to brute force the key (fairly simple to do) on pcap's of wow's tcp stream. but that is another method of obtaining the encryption key without touching the client memory (but for you guys, whats the fun in that?). For example, capturing 20 or so ping packets (because they're sequential and easy to identify) would be sufficient data to brute the key. much like how WEP bruter's work.
Omgawd its boogie!!1111oneoneone
Sup?
PS. Isn't the key stored in the CNetClient class or something? I can't recall.
__________________
[Only registered and activated users can see links. ]Back online!
"Science is interesting, and if you don't agree you can **** off." [Only registered and activated users can see links. ]
"I can write very coherent things when I try that sound very good" -- Styles
PS. Isn't the key stored in the CNetClient class or something? I can't recall.
yo yo, same shit diff day. I see you're having fun with the newbs 'round here, lol! some pretty entertaining reads.
I wouldn't be surprised if it was in CNetClient, it would be a fitting place for it.. but as I do all the key generation myself, I never had to fiddle around with how the client deals with it much. Either way, grabbing it from memory, or just brute forcing the damn thing (a few proxies have implemented this method before), its fairly straight forward get around the header encryption.
I wouldn't be surprised if it was in CNetClient, it would be a fitting place for it.. but as I do all the key generation myself, I never had to fiddle around with how the client deals with it much. Either way, grabbing it from memory, or just brute forcing the damn thing (a few proxies have implemented this method before), its fairly straight forward get around the header encryption.
Tis stored in CNetClient indeed. But if this guy can't even detour a function, i hardly see this helping him.
PS: HAI BOOGIE
__________________
[Only registered and activated users can see links. ]
BoogieMan, you can replace the C# PacketGenerator class with 1 line:
byte[] mKey = new System.Security.Cryptography.HMACSHA1(EncryptionSeed).ComputeHash(SessionKey);
The key generation is just HMAC sha1 seeded with those 16 static bytes.
Also, packets can have either 2 or 3 bytes in the header for the size field, depending on how big the packet is. If the packet is over 32767 bytes, 3 bytes are used, and the first byte is OR'd with 0x80 as a marker
This goes for both server-sent and client-sent packets
Now for some offsets
At (ClientConnection + 0x27E4) is a pointer to the class that handles the actual communication with the server. I just called this WoWConnection, but it could be the CNetClient
struct WoWConnection
{
int field_0;
SOCKET Socket;
int field_8;
int field_C;
int field_10;
ClientConnection* ClientConnectionPtr;
int field_18;
char *InputBuffer;
int InputBufferPosition;
int InputBufferSize;
int field_28[27];
struct _RTL_CRITICAL_SECTION CS_field_94;
int field_AC;
int ProcessingThreadId;
ClientConnection* SavedClientConnectionContext;
int field_B8[9];
WDSNode PacketQueue;// 0xDC - 0xE8
struct _RTL_CRITICAL_SECTION CS_field_E8;
int field_100[6];
char IsEncryptionInitialized;// 0x118
char EncKeyIndex;
char EncKeyPrevious;
char ClientOpcodeLen; // always 4
char DecKeyIndex;
char DecKeyPrevious;
char ServerOpcodeLen; // always 2
char EncryptionKey[20]; // 0x11F - 0x133 this is whats used to encrypt packets
}
Now if you need the full 40byte sessionkey for some reason, its at ClientConnection+0x288.
The client still keeps this because its used to seed warden modules and hashed in one of the bot packets, but thats another matter
And if you want to see the CDataStore class for the packets, go to [Only registered and activated users can see links. ] and check out datastore.cpp/h. Its looks to be the exact same as what the client uses, based on some of the function names in the asserts of the ptr clients
-Ralek
Still waiting on my new account to activate, been a few days now. Had to grab this old one from way back