协议缓冲区——用现有的c#类读取TCP协议包
本文关键字:协议 读取 TCP 缓冲区 | 更新日期: 2023-09-27 18:01:54
这个问题看似简单可行,但我就是做不出来。
我:
- 一个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网络使用分层协议栈,其中每一层增加功能并将上层协议与下层协议的细节隔离(反之亦然)。这是通过封装从上层发送到网络的数据,并在数据在接收端沿堆栈向上传输时对其进行反封装来实现的。现在,您的pcap文件包含了您的网络接口所看到的原始数据,即序列化的有效负载加上应用程序、传输、internet和链路层添加的所有数据。
现在,如果您想要反序列化转储中包含的对象,则需要编写一些代码来删除链路层和internet协议的所有头,(un-)执行传输协议的工作并重新组装通过网络发送的字节流。*
接下来,您需要分析产生的字节转储,并对应用程序级协议的设计进行一些复杂的猜测。它在开始通信时实现握手吗?它是否与实际的有效负载一起发送校验和?数据在通过网络发送之前被压缩了吗?应用程序在发送数据之前对数据进行加密吗?如果使用TCP作为传输协议,消息帧是如何实现的等等。当然,如果您可以访问生成数据的应用程序的源代码(或至少是应用程序二进制文件),那么您可以直接阅读代码(或对二进制文件进行反向工程)来弄清楚这部分内容。
在这一点上,您就可以解释原始数据了。剩下的就是编写一些代码来提取相关的字节,并将其提供给协议缓冲区反序列化器,然后,您就可以获得您的对象了!
(*还有其他小问题,如IP数据包碎片,TCP段到达无序,TCP重传,当然)
总结一下:
- 理论上是可能的编写一个工具来反序列化从pcap转储使用协议缓冲区序列化的对象,前提是转储包含两个对等体之间的完整通信,即数据包没有被生成转储的工具截断等。
- 在实践中,然而,有多个障碍要克服的是微不足道的,即使是一个经验丰富的从业者的艺术,因为这样的工具必须:
- 能够处理TCP/IP底层协议的所有复杂问题,重建对等体之间的数据流。
- 能够理解用于传输序列化对象的应用层协议。
请注意,上面第1点单独导致至少部分实现TCP/IP堆栈功能的需求。实现这一目标的最简单方法可能是重用开源TCP/IP实现的代码,比如Linux或*BSD内核中的代码。许多做类似事情的工具,比如从捕获文件重构HTTP流量,就是这样做的。(参见Justsniffer)