c# - 将字节数组转换为托管结构

标签 c# bytearray structure pcap.net

更新:这个问题的答案帮助我编写了开源项目 AlicanC's Modern Warfare 2 Tool on GitHub .您可以在 MW2Packets.cs 中看到我如何读取这些数据包以及我编码的扩展以读取 Extensions.cs 中的大端数据.

我正在捕获 Call of Duty: Modern Warfare 2 的 UDP 数据包使用 Pcap.Net在我的 C# 应用程序中。我从图书馆收到了一个 byte[]。我尝试将其像字符串一样进行解析,但效果不佳。

我的 byte[] 有一个通用数据包 header ,然后是另一个特定于数据包类型的 header ,然后是大厅中每个玩家的信息。

一位乐于助人的人为我检查了一些数据包并提出了这些结构:

// 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” header 制作一个结构,但我收到错误提示 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 的大小不同,我无法为播放器条目做任何事情。 (玩家条目是最重要的。)

现在,不知何故,我必须将我必须的 byte[] 转换为这些 PacketHeader 结构。遗憾的是,这并不像 (PacketHeader)bytes 那样简单。我尝试了我在互联网上找到的这种方法,但它引发了 AccessViolationException:

GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
PacketHeader packetHeader = (PacketHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(PacketHeader));

我怎样才能做到这一点?

最佳答案

//我在以下位置找到了这个:http://code.cheesydesign.com/?p=572 (我还没有测试过,但是 //乍一看它会工作得很好。)

    /// <summary>
    /// Reads in a block from a file and converts it to the struct
    /// type specified by the template parameter
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="reader"></param>
    /// <returns></returns>
    private static T FromBinaryReader<T>(BinaryReader reader)
    {

        // Read in a byte array
        byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));

        // Pin the managed memory while, copy it out the data, then unpin it
        GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
        handle.Free();

        return theStructure;
    }

关于c# - 将字节数组转换为托管结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6335153/

相关文章:

android - 无需压缩即可将位图编码和解码为字节数组

c - 如何从c中的头文件外部动态设置头文件中数组的大小?

c - 具有位域的结构大小的输出

javascript:从结构中函数的范围访问结构中的父对象

c# - 在分层列表中查找项目

c# - .NET 远程处理异常 : Permission denied: cannot call non-public or static methods remotely

c# - MVC Entity Framework 连接字符串不起作用

c# - 为什么即使值相同,哈希表中的值比较也会返回 false?

c# - 在c#和java套接字之间读写数据

java - 使用字节掩码防止符号扩展