使用现有的C#类读取Protobuf TCP数据包

时间:2014-05-06 18:40:47

标签: c# protocol-buffers

这个问题看起来很简单,但是我不能为我的生活让它发挥作用。

我有:

  • 我知道的包含少量数据包的PCAP文件是某种类型的ProtoBuf数据(可能是用protobuf-csharp-port创建的)
  • 装配的所有可能的C#类:

    [DebuggerNonUserCode, CompilerGenerated, GeneratedCode("ProtoGen", "2.4.1.473")]
    public sealed class thing : GeneratedMessageLite<thing, thing.Builder>
    

我想要做的就是使用我在汇编文件中知道的解析这些数据包。简单?可能,但无论我做什么,实际上都没有解析。

以下是许多可能类之一的示例:

    [DebuggerNonUserCode, CompilerGenerated, GeneratedCode("ProtoGen", "2.4.1.473")]
    public sealed class Thing: GeneratedMessageLite<Thing, Thing.Builder>
    {
        // Fields
        private static readonly string[] _thingFieldNames = new string[] { "list" };
        private static readonly uint[] _thingFieldTags = new uint[] { 10 };

        ...

        public static Builder CreateBuilder()
        {
            return new Builder();
        }

        ...

        public static thing ParseFrom(ByteString data)
        {
            return CreateBuilder().MergeFrom(data).BuildParsed();
        }

        ...

        public override void WriteTo(ICodedOutputStream output)
        {
            int serializedSize = this.SerializedSize;
            string[] strArray = _thingFieldNames;
            if (this.list_.Count > 0)
            {
                output.WriteMessageArray<thingData>(1, strArray[0], this.list_);
            }
        }

        ...

        [DebuggerNonUserCode, GeneratedCode("ProtoGen", "2.4.1.473"), CompilerGenerated]
        public static class Types
        {
            // Nested Types
            [CompilerGenerated, GeneratedCode("ProtoGen", "2.4.1.473")]
            public enum PacketID
            {
                ID = 19
            }
        }
    }

还有很多其他类似的东西。我尝试用每个数据包做这样的事情(使用protobuf-csharp-port):

    Console.WriteLine(Thing.ParseFrom(packet.Buffer).ToString());

我期待看到实际的文本数据。但我要么什么也得不到,关于无效数据包标签的错误,或者关于它是“0”的错误。

我也尝试过使用protobuf-net,但它只是给了我关于不兼容性,意外类型等的随机错误:

    Console.WriteLine(ProtoBuf.Serializer.Deserialize<Thing>(ms));

我在这里做错了什么?有没有更好的方法,使用程序集中的所有已知类型,只需解码Protobuf消息,看看里面有什么?理想情况下,无需事先知道它是什么类型的消息?

非常感谢你能解决这个问题!

1 个答案:

答案 0 :(得分:5)

根据问题中列出的失败尝试进行猜测,我相信您对pcap文件的内容存在一些误解。 特别是这一行

Console.WriteLine(Thing.ParseFrom(packet.Buffer).ToString());

让我觉得你正在错误地假设一个pcap数据包包含一个对象的序列化字节。不幸的是,事实并非如此。

正如您所知,TCP / IP网络使用分层协议栈,其中每个层都添加功能并将上层协议与低层协议的细节隔离(反之亦然)。这是通过将从上层发送的数据封装到网络中并在数据在接收侧向上移动时对数据进行解封装来完成的。 现在,您的pcap文件包含网络接口看到的原始数据,即序列化有效负载以及应用程序,传输,Internet和链接层添加的所有数据。

现在,如果要对转储中包含的对象进行反序列化,则需要编写一些代码来删除链接层和Internet协议的所有标头,(un-)执行传输协议的工作并重新组装通过网络发送的字节流。*

接下来,您需要分析生成的字节转储,并对应用程序级协议的设计进行一些复杂的猜测。它在开始通信时是否实现了握手?它是否与实际有效载荷一起发送校验和?数据在通过网络发送之前是否已压缩?应用程序在发送数据之前是否对数据进行加密?如果使用TCP作为传输协议,如何实现消息框架等等。当然,如果您可以访问生成数据的应用程序的源代码(或至少是应用程序二进制文件),那么您只需阅读代码(或对二进制文件进行逆向工程)以确定这一部分。

此时,您可以解释原始数据。剩下的就是编写一些提取相关字节的代码,将其提供给协议缓冲区反序列化器,然后再将对象恢复原状!

(*还有其他一些小问题,例如碎片化的IP数据包,TCP段无序到达,以及TCP重传,当然。)


总结一下:

  • 理论上可能 编写一个工具,用于对使用协议缓冲区从pcap转储序列化的对象进行反序列化,前提是转储包含完整的通信在两个对等体之间,即生成转储等的工具不会截断数据包。
  • 在实践中 ,有许多障碍需要克服,即使对于经验丰富的艺术从业者来说也是微不足道的,因为这样的工具必须:
    1. 能够处理TCP / IP低层协议的所有复杂问题,以重建对等体之间的数据流。
    2. 能够理解用于传输序列化对象的应用程序级协议。

请注意,仅上述第1点就要求至少部分地实现TCP / IP堆栈的功能。实现这一目标的最简单方法可能是重用开源TCP / IP实现的代码,例如Linux或* BSD内核中的代码。许多做类似事情的工具,比如从捕获文件重建HTTP流量,就是这样做的。 (参见例如Justsniffer。)