将字节数组转换为托管结构 [英] Casting a byte array to a managed structure

查看:26
本文介绍了将字节数组转换为托管结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:这个问题的答案帮助我编写了开源项目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;
}

由于 unknown14unknown18 的大小不同,我无法为玩家条目做任何事情.(玩家条目是最重要的.)

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆