将字节数组转换为托管结构
|
更新:这个问题的答案帮助我在GitHub上编写了开源项目AlicanC \'s Modern Warfare 2 Tool。您可以在MW2Packets.cs中看到我如何读取这些数据包,以及在Extensions.cs中我已编码为读取大字节序数据的扩展。
我正在C#应用程序中使用Pcap.Net捕获《使命召唤:现代战争2》的UDP数据包。我从图书馆收到a0ѭ。我试图像字符串一样解析它,但是效果不佳。
我有一个“ 0”,它有一个通用的数据包标题,然后是另一个特定于数据包类型的标题,然后是有关大厅中每个玩家的信息。
一个乐于助人的人为我检查了一些数据包,并提出了以下结构:
// 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#应用程序中重新创建了包头结构,如下所示:
[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
关键字不安全:
[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
的大小各不相同,因此我无法为玩家输入任何内容。 (玩家条目是最重要的。)
现在,以某种方式,我必须将“ 0”强制转换为这些“ 9”结构。可悲的是,要(PacketHeader)bytes
并不容易。我尝试了我在互联网上发现的这种方法,但是却花了11英镑:
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
PacketHeader packetHeader = (PacketHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(PacketHeader));
我该如何实现?
没有找到相关结果
已邀请:
7 个回复
你换
类始终使用小字节序。 我会在这里使用类而不是结构。
扫窟
桔适丛
而且在结构定义中,我没有使用任何
区域,相反,如果标准编组不起作用,我将使用
属性。这就是您可能需要的字符串。 您将使用以下功能:
编辑: 在代码示例中,我没有看到您的BigEndian \“ restriction \”。仅当字节为LittleEndian时,此解决方案才有效。 编辑2: 在示例字符串中,您可以使用以下命令装饰它:
在数组中,我将对n大小的数组进行如下处理:
徘廷
因此,前4个字节进入IntValue(1,0,0,0)-> [little endian]-> 1 接下来的3个字节直接进入数组。 如果您想要BigEndian,则应该自己做:
这样有点混乱,因此对于您来说,最好还是坚持使用自定义编写的解析器,该解析器从源byte []处一个接一个地获取字节,并在不使用StructLayout和其他本机互操作的情况下填充数据类。
豆兢
骇毖煽洁铂
类型可以是结构(没有引用类型的简单结构,那些是托管结构)或本机类型,例如
,
等。
艾食魄轻县
并将字符串转换回字节数组
现在阅读您的字符串,看看您的数据是什么。