Casting ein byte-array in eine verwaltete Struktur
Update: die Antworten auf diese Frage half mir code der open-Source-Projekt AlicanC Modern Warfare 2-Tool auf GitHub. Sie können sehen, wie lese ich diese Pakete in MW2Packets.cs und die Erweiterungen habe ich codiert zu Lesen, big-endian-Daten in Extensions.cs.
Ich bin capturing UDP-Pakete von Call of Duty: Modern Warfare 2 mit Pcap.Net in meiner C# - Anwendung. Ich erhalte eine byte[]
aus der Bibliothek. Ich habe versucht zu analysieren wie ein string, aber das hat nicht gut funktioniert.
Den byte[]
ich habe mit einem generischen Paket-header, dann ein anderes spezifischen header, um das Paket geben Sie dann Informationen über jeden Spieler in der lobby.
Eine hilfreiche person inspiziert, einige Pakete für mich an und kam mit diesen Strukturen:
//Fields are big endian unless specified otherwise.
struct packet_header
{
uint16_t magic;
uint16_t packet_size;
uint32_t unknown1;
uint32_t unknown2;
uint32_t unknown3;
uint32_t unknown4;
uint16_t unknown5;
uint16_t unknown6;
uint32_t unknown7;
uint32_t unknown8;
cstring_t packet_type; //\0 terminated string
};
//Fields are little endian unless specified otherwise.
struct header_partystate //Header for the "partystate" packet type
{
uint32_t unknown1;
uint8_t unknown2;
uint8_t player_entry_count;
uint32_t unknown4;
uint32_t unknown5;
uint32_t unknown6;
uint32_t unknown7;
uint8_t unknown8;
uint32_t unknown9;
uint16_t unknown10;
uint8_t unknown11;
uint8_t unknown12[9];
uint32_t unknown13;
uint32_t unknown14;
uint16_t unknown15;
uint16_t unknown16;
uint32_t unknown17[10];
uint32_t unknown18;
uint32_t unknown19;
uint8_t unknown20;
uint32_t unknown21;
uint32_t unknown22;
uint32_t unknown23;
};
//Fields are little endian unless specified otherwise.
struct player_entry
{
uint8_t player_id;
//The following fields may not actually exist in the data if it's an empty entry.
uint8_t unknown1[3];
cstring_t player_name;
uint32_t unknown2;
uint64_t steam_id;
uint32_t internal_ip;
uint32_t external_ip;
uint16_t unknown3;
uint16_t unknown4;
uint32_t unknown5;
uint32_t unknown6;
uint32_t unknown7;
uint32_t unknown8;
uint32_t unknown9;
uint32_t unknown10;
uint32_t unknown11;
uint32_t unknown12;
uint16_t unknown13;
uint8_t unknown14[???]; //Appears to be a bit mask, sometimes the length is zero, sometimes it's one. (First entry is always zero?)
uint8_t unknown15;
uint32_t unknown16;
uint16_t unknown17;
uint8_t unknown18[???]; //Most of the time this is 4 bytes, other times it is 3 bytes.
};
Ich neu die Paket-header-Struktur in meiner C# - Anwendung wie diese:
[StructLayout(LayoutKind.Sequential, Pack=1)]
struct PacketHeader
{
public UInt16 magic;
public UInt16 packetSize;
public UInt32 unknown1;
public UInt32 unknown2;
public UInt32 unknown3;
public UInt32 unknown4;
public UInt16 unknown5;
public UInt16 unknown6;
public UInt32 unknown7;
public UInt32 unknown8;
public String packetType;
}
Dann habe ich versucht, eine Struktur für die "partystate" - header, aber ich habe Fehler sagen fixed
Schlüsselwort ist unsicher:
[StructLayout(LayoutKind.Sequential, Pack=1)]
struct PartyStateHeader
{
UInt32 unknown1;
Byte unknown2;
Byte playerEntryCount;
UInt32 unknown4;
UInt32 unknown5;
UInt32 unknown6;
UInt32 unknown7;
Byte unknown8;
UInt32 unknown9;
UInt16 unknown10;
Byte unknown11;
fixed Byte unknown12[9];
UInt32 unknown13;
UInt32 unknown14;
UInt16 unknown15;
UInt16 unknown16;
fixed UInt32 unknown17[10];
UInt32 unknown18;
UInt32 unknown19;
Byte unknown20;
UInt32 unknown21;
UInt32 unknown22;
UInt32 unknown23;
}
Ich konnte nicht alles tun für die Spieler, die Einträge wegen der unterschiedlichen Größe der unknown14
und unknown18
. (Spieler-Einträge sind die wichtigsten.)
Nun, irgendwie habe ich das wirken des byte[]
ich diese PacketHeader
Strukturen. Leider, es ist nicht einfach, da (PacketHeader)bytes
. Ich habe versucht, diese Methode, die ich gefunden habe im internet, aber es warf ein AccessViolationException
:
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
PacketHeader packetHeader = (PacketHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(PacketHeader));
Wie kann ich das erreichen?
+1 für das teilen des Ergebnisses
InformationsquelleAutor AlicanC | 2011-06-13
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich würde schalten Sie den byte-array in einen memory-stream. Anschließend instanziieren Sie ein binary-reader auf dem stream. Und dann definieren Sie die helper-Funktionen, die eine binäre Leser und analysieren einer einzelnen Klasse.
Den eingebauten
BinaryReader
Klasse verwendet immer little-endian.Ich würde verwenden Sie Klassen anstelle von Strukturen hier.
InformationsquelleAutor CodesInChaos
//Habe ich gefunden unter: http://code.cheesydesign.com/?p=572 (ich habe noch nicht getestet, aber
//auf den ersten Blick funktioniert es gut.)
InformationsquelleAutor Roberto Santos
Dies ist, wie ich getan habe:
Und in der struct-definition, die ich nicht alle
fixed
region, die ich stattdessen verwendet dieMarshalAs
Attribut, wenn die standard-marshalling nicht gearbeitet. Dies ist, was Sie probally müssen für die Zeichenfolge.Verwenden Sie diese Funktion wie folgt:
Bearbeiten:
Ich nicht sehen, Ihre BigEndian "Einschränkung" im code-Beispiel. Diese Lösung funktioniert nur, wenn die bytes sind LittleEndian.
Edit 2:
Im string des Beispiels würden Sie schmücken Sie mit:
In den arrays würde ich mit so etwas für eine n-sortierte array:
InformationsquelleAutor Vladimir
Gut, Sie haben zwei Aufgaben hier wirklich. Zunächst ist zu interpretieren, byte [], struct im wesentlichen und die zweite ist die Auseinandersetzung mit unterschiedlicher endianness.
So, Sie sind etwas abweichen. AFAIK wollen Sie das Marshalling - es werden nur bytes interpretieren, als ob es verwaltete Struktur. Also das konvertieren von einem endian zu anderen ist Euch überlassen. Es ist nicht schwer zu tun, aber es wird nicht automatisch sein.
So zu interpretieren, byte [], struct Sie etwas haben wie:
Also die ersten 4 bytes gehen zu IntValue (1,0,0,0) -> [little endian] -> 1
Nächste 3 bytes gehen Sie direkt zu Feld.
Wenn Sie möchten, BigEndian, sollten Sie es selbst tun:
Es ist etwas chaotisch, also wahrscheinlich auch für Sie besser sein wird, um stick mit benutzerdefinierten parser geschrieben, der nimmt die bytes einzeln aus der Quelle byte[] und füllen Sie Ihre Daten-Klasse ohne StructLayout und andere native interop.
InformationsquelleAutor Ivan Danilov
Mein Ansatz ist anders. Ich wollte nicht kopieren, byte.
Ich wollte nur, Sie zu benutzen, ändern Sie einige von Ihnen und nutzen verändert byte [] - array an anderer Stelle als byte[].
Nach dem Graben google und stackoverflow habe ich beschlossen zu gehen in unsicheren/behoben werden.
Es spielen mit code, den ich gefunden habe, schnellen code ohne kopieren.
Dies ist die DEBUG - /TEST-code. Überprüfen Sie dies im debug-Modus.
Denken Sie daran, dass diese Weise, die Sie nicht machen Sie eine Kopie und Sie arbeiten auf raw byte[] data.
Jede änderung in der Struktur widerspiegeln, in byte [] - array ändern und Umgekehrt.
++GETESTET++ ARBEITET
InformationsquelleAutor MrHIDEn
Für diejenigen, die Zugriff auf C# 7.3 Funktionen, ich benutze dieses Stück unsicheren code zu "serialisieren" zu bytes:
Einen
unmanaged
Typ kann ein struct (einfache Struktur, die ohne Referenz-Typen, die als verwaltete Strukturen) oder einem einheitlichen Typ wieint
,short
usw.InformationsquelleAutor Philippe Paré
Umwandeln byte-array in einen string Sie dies tun;
Und konvertieren den string in ein ByteArray zurück,
Nun Lesen Sie den Text und sehen, was mit Ihren Daten ist.
InformationsquelleAutor KenL