gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-01 16:26:39 24 4
gpt4 key购买 nike

这个问题看起来很简单并且足够可行,但我一辈子都无法让它发挥作用。

我有:

  • 一个 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 消息并查看里面的内容?理想情况下不需要事先知道它是什么类型的消息?

如果您能解决这个问题,非常感谢!

最佳答案

从问题中概述的失败尝试猜测,我相信您对 pcap 文件的内容有一些误解。特别是这一行

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

让我认为您正在错误的假设下工作,即单个 pcap 数据包包含单个对象的序列化字节。不幸的是,事实并非如此。

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

现在,如果您想反序列化转储中包含的对象,您将需要编写一些代码来删除链路层和互联网协议(protocol)的所有 header ,(取消)执行传输协议(protocol)的工作并重新组装通过网络发送的字节流。*

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

一旦到达此点,您就可以解释原始数据了。剩下的就是编写一些代码来提取相关字节,将其提供给 Protocol Buffer 反序列化器,然后瞧,你的对象就回来了!

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

<小时/>

总结一下:

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

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

关于c# - 使用现有 C# 类读取 Protobuf TCP 数据包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23502473/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com