将字节数组转换为托管结构 [英] Casting a byte array to a managed structure
问题描述
更新:这个问题的答案帮助我编写了开源项目AlicanC 在 GitHub 上的现代战争 2 工具.你可以在 MW2Packets.cs 以及我编写的用于读取 Extensions.cs.
Update: Answers to this question helped me code the open sourced project AlicanC's Modern Warfare 2 Tool on GitHub. You can see how I am reading these packets in MW2Packets.cs and the extensions I've coded to read big endian data in Extensions.cs.
我正在使用 使命召唤:现代战争 2 的 UDP 数据包捕获="http://pcapdotnet.codeplex.com/" rel="noreferrer">Pcap.Net 在我的 C# 应用程序中.我从图书馆收到一个 byte[]
.我试图像字符串一样解析它,但效果不佳.
I am capturing UDP packets of Call of Duty: Modern Warfare 2 using Pcap.Net in my C# application. I receive a byte[]
from the library. I tried to parse it like a string, but that didn't work well.
byte[]
我有一个通用的包头,然后是另一个特定于包类型的头,然后是大厅中每个玩家的信息.
The byte[]
I have has a generic packet header, then another header specific to the packet type then info about each player in the lobby.
一个乐于助人的人为我检查了一些数据包并提出了以下结构:
A helpful person inspected some packets for me and came up with these structures:
// 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.
};
我在我的 C# 应用程序中重新创建了数据包头结构,如下所示:
I recreated the packet header structure in my C# application like this:
[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;
}
然后我尝试为partystate"标头创建一个结构,但是我收到错误说fixed
关键字不安全:
Then I tried to make a structure for the "partystate" header, but I got errors saying fixed
keyword is unsafe:
[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;
}
由于 unknown14
和 unknown18
的大小不同,我无法为玩家条目做任何事情.(玩家条目是最重要的.)
I couldn't do anything for the player entries because of the varying size of unknown14
and unknown18
. (Player entries are the most important.)
现在,不知何故,我必须将 byte[]
我必须转换为这些 PacketHeader
结构.遗憾的是,这并不像 (PacketHeader)bytes
那样容易.我尝试了在互联网上找到的这种方法,但它抛出了一个 AccessViolationException
:
Now, somehow, I have to cast the byte[]
I have to these PacketHeader
structures. Sadly, it's not easy as (PacketHeader)bytes
. I tried this method I've found on the internet but it threw an AccessViolationException
:
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
PacketHeader packetHeader = (PacketHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(PacketHeader));
我怎样才能做到这一点?
How can I achieve this?
推荐答案
我会将字节数组转换为内存流.然后在该流上实例化一个二进制读取器.然后定义使用二进制读取器并解析单个类的辅助函数.
I'd turn the byte array into a memory stream. Then instantiate a binary reader on that stream. And then define helper functions that take a binary reader and parse a single class.
内置的 BinaryReader
类总是使用小端.
The built in BinaryReader
class always uses little endian.
我会在这里使用类而不是结构.
I'd use classes instead of structs here.
class PacketHeader
{
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;
string packet_type; // replaced with a real string
};
PacketHeader ReadPacketHeader(BinaryReader reader)
{
var result=new PacketHeader();
result.magic = reader.ReadInt16();
...
result.packet_type=ReadCString();//Some helper function you might need to define yourself
return result;
}
这篇关于将字节数组转换为托管结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!