Virtual PacketField:如何处理多态protocole?

问题描述 投票:4回答:1

我是一个新的scapy用户,今天我要求你的帮助。

我正在尝试在scapy中添加一个新的protocole。这个protocole有点特别,因为他是多态的。通过变形,我的意思是他的结构和他的长度取决于某些领域。通常,有一个'function'ByteField,更改此值会改变所有下一个字段。

所以,让我们看一下这段代码,说明我想做什么。有一个简单的多态数据包,带有一个主常量结构// header // parameter // data //。变化在参数和数据结构内。

### VIRTUAL PARAMETER PACKET
class myPacketParam(Packet):
    name = "Virtual Param Packet"

### REAL PARAMETER PACKET ONE
class myPacketParamOne(myPacketParam):
    name = "Parameter Type One"
    fields_desc = [
        ByteField("paramOne", 0x0),
        ByteField("paramTwo", 0x0)
    ]

### REAL PARAMETER PACKET TWO
class myPacketParamTwo(myPacketParam):
    name = "Parameter Type Two"
    fields_desc = [
        FieldLenField("length", None, length_of="stringOpt"),
        StrLenField("stringOpt", "BAGUETTE", # Random default value
                    length_from=lambda pkt: pkt.length)
    ]

### VIRTUAL DATA PACKET
class myPacketData(Packet):
    name = "Virtual Data Packet"

### REAL DATA PACKET ONE
class myPacketDataOne(myPacketData):
    name = "Data Type One"
    fields_desc = [
        ByteField("length", 2),
        ByteField("dataOne", 0x0),
        ByteField("dataTwo", 0x0)
    ]

### REAL DATA PACKET TWO
class myPacketDataTwo(myPacketData):
    name = "Data Type Two"
    fields_desc = [
        FieldLenField("length", None, length_of="data"),
        StrLenField("data", "SAUCISSON", length_from=lambda pkt: pkt.length) # Random default value
    ]

### MAIN PACKET
class myPacket(Packet):
    name = "myPacket"

    def changeFunction(self, value, data):
        if value == 0x1:
            self.param = myPacketParamOne()
            self.data = myPacketDataOne()
        else:
            self.param = myPacketParamTwo()
            self.data = myPacketDataTwo()

    fields_desc = [
        ByteField("version", 0x15),
        ActionField(ByteField("function", 0x1), "changeFunction"),
        FieldLenField("lengthParam", None, length_of="param"),
        FieldLenField("lengthData", None, length_of="data"),
        PacketField("param", myPacketParamOne(), myPacketParam),
        PacketField("data", myPacketDataOne(), myPacketData)
    ]

好吧,关键是主数据包“myPacket”中的“param”和“data”字段。例如,“param”packetfield正在询问myPacketParam数据包。但我希望这个数据包是虚拟的:后面的真正数据包可以是myPacketParamOne或myPacketParamTwo。数据同样如此。

构建此数据包看起来没问题。

p = myPacket()
p.show()

# great result

p.function = 2
p.show()

###[ myPacket ]###
  version   = 21
  function  = 2
  lengthParam= None
  lengthData= None
  \param     \
   |###[ Parameter Type Two ]###
   |  length    = None
   |  stringOpt = 'BAGUETTE'
  \data      \
   |###[ Data Type Two ]###
   |  length    = None
   |  data      = 'SAUCISSON'

但我猜解剖是行不通的。

p.show2()

###[ myPacket ]###
  version   = 21
  function  = 2
  lengthParam= 10
  lengthData= 11
  \param     \
   |###[ Virtual Param Packet ]###
   |###[ Raw ]###
   |     load      = 'BAGUETTE\x00\tSAUCISSON'
  \data      \
   |###[ Data Type One ]###
   |  length    = 2
   |  dataOne   = 0
   |  dataTwo   = 0

这是完全错误的。

我找到了一些解决方案通过示例使用conditionalField。但在我真正的protocole中,同一个数据包中有很多形态。并且因为字段不能具有相同的名称,所以主数据包中没有简单的param字段,而是每个案例的新名称。因此,真正利用我的scapy实现是非常无聊而且不简单。

第二种解决方案是取消链接标题,参数和数据。所以你可以像这样使用protocole:p = myPacket()/ myPacketParamOne()/ myPacketDataOne()。但对我来说这不是一个好的解决方案,因为我的真正的protocole在每个部分之间都存在依赖关系,而且对于我的scapy实现的用户来说仍然很复杂。

所以,如果可能的话,我正在寻找一个解决方案: - 尊重主要结构(标题/参数/数据) - 简单地使用这个protocole(myPacket.param.whatyouwant得到param而不考虑它是什么样的param包(但当然这种param packe存在woutyouwant领域))

我觉得解决方案可以是在每个“虚拟数据包”中重新定义do_dissect函数,或者为新的字段编码,特别是对于虚拟数据包,但我尝试了许多事情而没有成功。

我希望我能理解。

先感谢您 :)

弥敦道

python scapy
1个回答
0
投票

(这有点旧^^)

自从Scapy的最新版本(使用2.4.3rc +是安全的)以来,我们有一个新的MultipleTypeField,似乎正在做你想要的。这是回归测试中的一个例子:

class DebugPacket(Packet):
    fields_desc = [
        ByteEnumField("atyp", 0x1, {0x1: "IPv4", 0x3: "DNS", 0x4: "IPv6"}),
        MultipleTypeField(
            [
                # IPv4
                (IPField("addr", "0.0.0.0"), lambda pkt: pkt.atyp == 0x1),
                # DNS
                (DNSStrField("addr", ""), lambda pkt: pkt.atyp == 0x3),
                # IPv6
                (IP6Field("addr", "::"), lambda pkt: pkt.atyp == 0x4),
            ],
            StrField("addr", "")  # By default
        ),
    ]

它允许您根据条件使具有多种类型的相同字段

© www.soinside.com 2019 - 2024. All rights reserved.