posted this on another forum a long time ago but it didnt gain any traction so maybe people here will have use
Quote:
I decided to meddle around into guild wars 2 and found that their client/server architecture is roughly the same as the first game so, made for easy reverse engineering work
The function hooked is the outgoing packet sender for the gameserver, this is before encryption so you can see the juicy details. It is an object method so ECX is the thisptr. In this object using what is provided, you can find a table holding handlers to each incoming packet handler. Along with encodings for parameters to expect in the packet. The encodings also exist for the ctos packets in a table above.
You can hook the stoc handlers using a simple vmt-like swap if desired.
GWCA::PatternScanner is a simple pattern scanner with wildcard support, nothing fancy, can use your own. (Make sure you start the scan from the module base, it changes)
GWCA::Hook is just a wrapper for a JMP hook w/ trampoline, so again, just use your own.
ConsoleEx can be found in the hacklib project .
Have fun, would love to see some documentation on the ctos packets .
Also note, there are references to the thisptr in static mem, so you can retrieve it and emulate calls to the sender for hacks/bots if one were so inclined.
GW2 has such hard packets
if packet contains string then function ctos_detour receive in CtoGS::Packet* packet something like that <prefix><some unknown bytes><pointer to string in memory>
the same situation with CS skill packets(coordinates), SC NPC shop(prices), CS\SC chat(strings)
GW2 has such hard packets
if packet contains string then function ctos_detour receive in CtoGS::Packet* packet something like that <prefix><some unknown bytes><pointer to string in memory>
the same situation with CS skill packets(coordinates), SC NPC shop(prices), CS\SC chat(strings)
You are capturing unpacked version of the message before it enters the message queue. If you want to capture the packed version hook the sender function before call to RC4Crypt. Pointer to the packet should be in the EBX register.
Agedyn, thanks
RC4 is called for composite packets, which may contain several messages. To analyze these packages difficult, because you must correctly parse each component of its package.
I found a place where you can take outgoing packets prepared for sending
Unfortunately, I do not know what to do with incoming packets, because they are compressed. You do not know what kind of compression algorithm used for incoming packets? I found the function of decompressing the data, but it is recursive, and dynamically allocates memory for uncompressed data, me too complicated to understand it
Agedyn, thanks
RC4 is called for composite packets, which may contain several messages. To analyze these packages difficult, because you must correctly parse each component of its package.
I found a place where you can take outgoing packets prepared for sending
Unfortunately, I do not know what to do with incoming packets, because they are compressed. You do not know what kind of compression algorithm used for incoming packets? I found the function of decompressing the data, but it is recursive, and dynamically allocates memory for uncompressed data, me too complicated to understand it
Received messages are encrypted using RC4. They use the same key from sending and receiving.
LZ4 or LZMA is probably used for decompression (0xF5AF70).
Edit: LZ4 is the algorithm used for decompression. I found this by checking THIRDPARTYSOFTWAREREADME.txt for used compression algorithms (I found LZ4, LZMA and zlib) and then googling their working principle. The compression algorithm seemed similar to LZ4, so I tried to decompress packet using it and it worked just fine. LZ4 header starts at 4th byte.
Edit: First short is compressed size and second is uncompressed size.
Some messages contain compressed long fields. The size of these fields can be anywhere between 1 to 4 byte. uncompressLong is located at 0xDBA710. 0xDB9E50 is the compressLong function. .
As I'm working on a 'fake' client using NodeJS I have converted these algorithms to JavaScript.
Code:
static compressLong(value, unk) {
let compressed = 0;
if (unk) {
value &= -((value & 0x40000000) != 0);
}
let i = 0;
do
{
let compressedByte = value & 0x7F;
value >>= 7;
if (value) {
compressedByte |= 0x80;
}
compressed |= compressedByte << (i * 8);
i++;
} while(value);
return compressed;
}
static uncompressLong(value) {
let uncompressed = 0;
let i = 0;
let outSize = 0;
for (; i < 4; ++i) {
let byte = (value >> i * 8) & 0xFF;
byte = ~(byte >>= 7);
++outSize;
if ((byte & 1) != 0) {
break;
}
}
for (; i >= 0; --i) {
let byte = (value >> i * 8) & 0xFF;
uncompressed = uncompressed << 7 | byte & 0x7F;
}
return {value: uncompressed, size: outSize};
}
0xDBA0C0 is used for unpacking message into a struct and then it's passed to dispatch function (0xDB87AD).
Here are ids for message fields:
Code:
# snippet from my python message dumper (may not be 100 % correct)
net_fields_send = {
'MP_END': 0,
'MP_MSGID': 1,
'MP_BYTE': 2,
'MP_SHORT': 3,
'MP_COMPRESSED_LONG': 4,
'MP_ALIGNED_LONGLONG': 5,
'MP_FLOAT': 6,
'MP_VEC2': 7,
'MP_VEC3': 8,
'MP_VEC4': 9,
'MP_16BYTES_2': 10,
'MP_16BYTES': 11,
'MP_28BYTES': 12,
'MP_STRING': 13,
'MP_CSTRING': 14,
'MP_OPTIONAL': 15,
'MP_ARRAY_FIXED': 16, # message specific size
'MP_ARRAY_SMALL': 17,
'MP_ARRAY_LARGE': 18,
'MP_BUFFER_FIXED': 19, # message specific size
'MP_BUFFER_SMALL': 20,
'MP_BUFFER_LARGE': 21,
'MP_SRV_ALIGN': 22,
'MP_SRV_END': 24
}
# gw2 unpack function decreases field id by one. Does not have MP_END field.
net_fields_recv = {
'MP_MSGID': 1,
'MP_BYTE': 2,
'MP_SHORT': 3,
'MP_COMPRESSED_LONG': 4,
'MP_ALIGNED_LONGLONG': 5,
'MP_FLOAT': 6,
'MP_VEC2': 7,
'MP_VEC3': 8,
'MP_VEC4': 9,
'MP_16BYTES_2': 10,
'MP_16BYTES': 11,
'MP_28BYTES': 12,
'MP_STRING': 13,
'MP_CSTRING': 14,
'MP_OPTIONAL': 15,
'MP_ARRAY_FIXED': 16, # message specific size
'MP_ARRAY_SMALL': 17,
'MP_ARRAY_LARGE': 18,
'MP_BUFFER_FIXED': 19, # message specific size
'MP_BUFFER_SMALL': 20,
'MP_BUFFER_LARGE': 21,
'MP_SRV_ALIGN': 22,
'MP_SRV_END': 24
}
static compressLong(value, unk) {
let compressed = [];
if (unk) {
value &= -((value & 0x40000000) != 0);
}
let i = 0;
do
{
let b = value & 0x7F; // get all bits except most significant
value >>= 7;
let bitsShifted = 7 * (i + 1);
// check if maximum size exceeded
if (bitsShifted > 35) {
break;
}
if (bitsShifted == 35) {
b &= 0x0F; // 4 most significant bits are overflow, so discard them
} else if (value != 0) { // if not the last byte, set MSB to indicate continuation
b |= 0x80;
}
compressed.push(b);
i++;
} while(value != 0);
return compressed;
}
static uncompressLong(buffer) {
let uncompressed = 0;
let outSize = 0;
for (let i = 0; i < buffer.length; ++i) {
let b = buffer[i];
uncompressed |= (b & 0x7F) << (i * 7);
outSize++;
// check if MSB indicates end
if ((b & 0x80) == 0) {
break;
}
}
return {value: uncompressed >>> 0, size: outSize};
}
[Selling] Silver Hosting | Gameserver | ★Dein High-End Gameserver zum günstigen Preis★ 02/25/2014 - elite*gold Trading - 25 Replies Sehr geehrte Mitglieder von Elitepvpers,
hiermit möchten wir Ihnen High-End Gameserver zum günstigen Preis anbieten.
Gameserver - Multi Theft Auto
http://abload.de/img/mta_1h3d0k.png
Forum.Zap-Hosting.com - kostenlose Gameserver - Das Gameserver-Communityboard 08/28/2011 - Counter-Strike - 11 Replies Forum.Zap-Hosting.com - Das Gameserver - Communityboard
http://zap-hosting.com/images/zapcommunity.png
Zum Board
Kostenlose Voice- und Gameserver! Wir sehen uns als das erste und einzige deutsche Forum in welchem die Communitymitglieder für das aktive Schreiben mit Voice- und Gameservern belohnt werden. Erarbeite dir deine ZAPs, werde reich und miete mit deinem Clan kostenlos einen Server.
Werde Admin von erfolgreichen oder geplanten Publicserverprojekten.