Wenn du interne Funktionen hookst sieht die Struktur so aus
4 Bytes OpCode/MessageId
Restlichen Bytes Daten
Die Größe steht in der DataStore Struktur (komme aufm Live nicht auf die Idee direkt NetClient::Send2 zu hooken, nehme bestenfalls einen inline Hook).
Die Daten verändern sich natürlich je nach Paket. Bei Jam Nachrichten wird es so sein das sich die Struktur der Daten mit jedem größeren Patch verändert, aber nur wie die Daten ins Paket geschrieben werden, die interne Struktur der Paket-Klasse ändert sich eher selten.
Genau an diese Klasse musst du ran, wenn du selber Daten senden oder vernünftig manipulieren willst, beim Packet Log sind die Daten zwar nicht gänzlich unbrauchbar, aber schwer zu identifizieren.
GUIDs werden beispielsweise durch Bit Operationen unlesbar, die GUID in Bytes gesplittet und ins ganze Paket verteilt.
Jedes Jam Paket hat einen eigenen Constructor, seit einigen Patches verwenden viele den gleichen Destructor.
Diese beiden Funktionen rufe ich auf, nachdem ich den Constructor aufgerufen habe, setze ich die Daten so wie es WoW erwartet in die Klasseninstanz (die Daten beginnen bei 0x10). Danach wird die Klasseninstanz an ClientServices_Send übergeben (nicht Send2, die Funktion ist für die alten Pakete die noch nicht convertiert worden sind).
ClientServices_Send erledigt dann den Rest und führt die nötigen Bit Operationen aus.
Im Grunde musst du nur die interne Klassen Struktur des Paketes kennen, denn die WoW Entwickler setzen die Daten auch so.
Ich habe mir dafür z.B. eine simple Wrapper Klasse geschrieben (sorry für Delphi Code ;P). Denke dir eax, edx weg, gehört zum Delphi fastcall aufruf, da es kein thiscall gibt.
Code:
constructor CJamMessage.Create(pConstructor, pDestructor: Pointer);
var
_construct: procedure({$ifdef Win32}eax, edx: Pointer;{$endif}var pThis);
begin
inherited Create();
FDestruct := pDestructor;
@_construct := pConstructor;
_construct({$ifdef Win32}nil, nil,{$endif}FJamMessage);
end;
FJamMessage ist nen 10Kb den ich bereitstelle, ist die Klasse erstellt, setze ich die Daten entsprechend in die Struktur, die noch immer bei 0x10 beginnen sollte.
Beim Transmogrifzieren sieht die Struktur ab 0x10 z.B. so aus
Code:
TransmogData = packed record
itemGUID : UInt64;
itemID : Cardinal;
itemType : Cardinal;
end;
TJamTransmog = packed record
npc : UInt64;
numItems : Cardinal;
numItems2 : Cardinal; // möglicherweise falsch
itemArray : Array of TransmogData;
end;
TJamTansmog wird dann in FJamMessage[0x10] geschoben, ClientServices_Send mit nen Pointer zu FJamMessage aufgerufen, fertig.
In C++ würde das nochmal nen Tick schicker realisierbar sein.
Einige Constructor nehmen noch einige Parameter, wenn die Struktur des Paketes eh klein ist, z.B. die GUID.