Scapy 可变长度字段

Pra*_*eep 3 python scapy

我试图理解 PacketListField 和 FieldListField 之间的区别。有人可以让我知道在添加新协议时如何使用它们吗?

我也不清楚StrLenField、FieldLenField和PacketLenField。我正在尝试制作一条 BGP 更新消息,以便我能够了解它是如何工作的。我看到这就是 BGPUpdate 消息的定义方式。当我尝试制作 BGP 数据包时,我不确定如何传递“撤回路由”字段和 nlri 字段的值。我也不确定如何传递路径属性的值。

>>> pkt=BGPUpdate()
>>> pkt.show()
###[ BGP Update fields ]###
  withdrawn_len= None
  withdrawn= []
  tp_len= None
  \total_path\
  nlri= []
>>>                        

class BGPPathAttribute(Packet):
"the attribute of total path"
    name = "BGP Attribute fields"
    fields_desc = [
    FlagsField("flags", 0x40, 8, ["NA0","NA1","NA2","NA3","Extended-Length","Partial","Transitive","Optional"]), #Extened leght may not work
    ByteEnumField("type", 1, {1:"ORIGIN", 2:"AS_PATH", 3:"NEXT_HOP", 4:"MULTI_EXIT_DISC", 5:"LOCAL_PREF", 6:"ATOMIC_AGGREGATE", 7:"AGGREGATOR"}),
    ByteField("attr_len", None),
    StrLenField("value", "", length_from = lambda p: p.attr_len),
   ]
   def post_build(self, p, pay):
        if self.attr_len is None:
            l = len(p) - 3 # 3 is regular length with no additional options
            p = p[:2] + struct.pack("!B",l)  +p[3:]
        return p+pay
    def extract_padding(self, p):
        """any thing after this packet is extracted is padding"""
        return "",p

class BGPUpdate(Packet):
    """Update the routes WithdrawnRoutes = UnfeasiableRoutes"""
    name = "BGP Update fields"
    fields_desc = [
        ShortField("withdrawn_len", None),
        FieldListField("withdrawn",[], BGPIPField("","0.0.0.0/0"), length_from=lambda p:p.withdrawn_len),
        ShortField("tp_len", None),
        PacketListField("total_path", [], BGPPathAttribute, length_from = lambda p: p.tp_len),
        FieldListField("nlri",[], BGPIPField("","0.0.0.0/0"), length_from=lambda p:p.underlayer.len - 23 - p.tp_len - p.withdrawn_len), # len should be BGPHeader.len
        ]
    def post_build(self,p,pay):
        wl = self.withdrawn_len
        subpacklen = lambda p: len ( str( p ))
        subfieldlen = lambda p: BGPIPField("", "0.0.0.0/0").i2len(self,  p )
        if wl is None:
            wl = sum ( map ( subfieldlen , self.withdrawn))
            p = p[:0]+struct.pack("!H", wl)+p[2:]
        if self.tp_len is None:
            l = sum ( map ( subpacklen , self.total_path))
            p = p[:2+wl]+struct.pack("!H", l)+p[4+wl:]
        return p+pay
Run Code Online (Sandbox Code Playgroud)

tin*_*tin 6

它们只是对不同类型的对象进行操作。请参阅scapy 构建解剖

数据包列表字段

描述相同类型的PacketField列表,而一个PacketField表示放入另一个数据包字段中的数据包类型对象。它采用数据包原型作为第三个参数cls __init__(self, name, default, cls, count_from=None, length_from=None)。PacketListField 的构造函数需要设置 count_from (对象数量)或 lengt_from (字节)参数,以便知道要传递到数据包列表的字节数或要剖析的对象数。(例如,您可以将其作为BGPUpdate原型PacketField 或 PacketListField)。

例如:

PacketListField("total_path", [], BGPPathAttribute, length_from = lambda p: p.tp_len),
Run Code Online (Sandbox Code Playgroud)

创建一个名为“total_path”的字段,默认值为空列表 [],并尝试将 raw_bytestream 的 length_from 字节解析为 BGPPathAttribute(Packet)。

字段列表字段

相比之下,FieldListField将 Field 作为原型,并尝试将 raw_bytestream 剖析为原型字段列表__init__(self, name, default, field, length_from=None, count_from=None):

FieldListField("withdrawn",[], BGPIPField("","0.0.0.0/0"), length_from=lambda p:p.withdrawn_len),
Run Code Online (Sandbox Code Playgroud)

字段长度

DataField 通常最多可容纳 length_from bytes __init__(self, name, default, fld=None, length_from=None):

场Len场

保存同一数据包中另一个字段长度的数字字段__init__(self, name, default, length_of=None, fmt = "H", count_of=None, adjust=lambda pkt,x:x, fld=None):

class SomePacket(Packet):
    name = "SomePacket"
    fields_desc = [ByteEnumField("type", 0x00, {0x00:"SomeType"}),  
                  FieldLenField("length", None, length_of="data"),          # hold length of data
                  StrLenField("data", "", length_from=lambda x:x.length),   # holds data
                  ]
Run Code Online (Sandbox Code Playgroud)

在 dissect 上,scapy 会将第一个字节放入“type”,接下来的 2 个字节(默认 fmt="H" 表示短整型“length”,最多将“length”个字节放入“data”

在 build 时,scapy 将自动用 len(data) 填充“length”。

数据包长度字段

是一个将 length_from 字节解析为一个原型数据包的字段__init__(self, name, default, cls, length_from=None):

class AnotherPacket(Packet):
    name = "AnotherPacket"
    fields_desc = [
                  BLenField("length", None, length_of="data"),
                  PacketLenField("data", None, SomePacket, length_from=lambda x:x.length),]
                  ]
Run Code Online (Sandbox Code Playgroud)

在 dissect 上,scapy 会将第一个 Byte 放入 ByteLengthField 'length' 中,并将最多 'length' 个字节解析为 'SomePacket' 放入 'data' 中

在 build 时,scapy 将自动使用序列化 SomePacket 的大小填充“length”。