Scapy:如何实现条件字段列表?

时间:2016-02-10 11:20:54

标签: python scapy

我是Scapy的新手,我想剖析复杂的协议。这是我被阻止的地方:我有一个数据包,在两个字段中保存记录的类型和数量。数据包的其余部分构成记录。

我用两层实现它:第一个,MainPacket类,持有record_type,record_nb和记录列表。第二层,Record类,完全由条件字段组成,每个记录类型一个,如下所示:

from scapy.all import Packet, IntField, IntEnumField, FieldLenField\
,PacketListField, StrNullField, ConditionalField

class Record(Packet):
    fields_desc = [
        #IntField("data_long_record", 0)
        #StrNullField("data_sz_record", "")
        ConditionalField(IntField("data_long_record", 0),
                         lambda pkt:pkt.underlayer.record_type==3),
        ConditionalField(StrNullField("data_sz_record", ""),
                         lambda pkt:pkt.underlayer.record_type==8)
    ]
    def extract_padding(self, s):
        return '', s

class MainPacket(Packet):
    fields_desc = [
        IntEnumField("record_type", 1, {
            3:"DATA_LONG",            
            8:"DATA_SZ"}),
        FieldLenField("record_nb", 0, fmt="I", count_of="records"),
        PacketListField("records", None, Record, count_from=lambda pkt:pkt.record_nb)
    ]
    def extract_padding(self, s):
        return '', s

if __name__ == "__main__":
    p1 = MainPacket("\x00\x00\x00\x03" # Type is DATA_LONG
               "\x00\x00\x00\x04" # 4 records
               "\x00\x00\x00\x01" 
               "\x00\x00\x00\x02"
               "\x00\x00\x00\x03"
               "\x00\x00\x00\x04")
    p1.show()
    p2 = MainPacket("\x00\x00\x00\x08" # Type is DATA_SZ
               "\x00\x00\x00\x02" # 2 records
               "Hello\x00"
               " world.\x00")
    p2.show()

以下是测试代码时得到的结果:

WARNING: No route found for IPv6 destination :: (no default route?)
###[ MainPacket ]###
  record_type= DATA_LONG
  record_nb = 4
  \records   \
   |###[ Raw ]###
   |  load      = '\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04'
###[ MainPacket ]###
  record_type= DATA_SZ
  record_nb = 2
  \records   \
   |###[ Raw ]###
   |  load      = 'Hello\x00 world.\x00'

未解剖子图层。但是,通过IntField或StrNullField替换条件效果很好,除了它无法处理所有情况......

我的Python版本是2.7.6。 我的Scapy版本是2.3.2。 我使用Linux Mint 17。

你有任何线索吗?

2 个答案:

答案 0 :(得分:1)

也许你可以将条件移到MainPacket?此外,您可以使用bind_layers()代替.extract_padding()

from scapy.all import Packet, IntField, IntEnumField, FieldLenField, \
PacketListField, StrNullField, ConditionalField, Padding, bind_layers

class RecordLONG(Packet):
    fields_desc = [
        IntField("data_long_record", 0),
    ]

class RecordSZ(Packet):
    fields_desc = [
        StrNullField("data_sz_record", ""),
    ]

bind_layers(RecordLONG, Padding)
bind_layers(RecordSZ, Padding)

class MainPacket(Packet):
    fields_desc = [
        IntEnumField("record_type", 1, {
            3:"DATA_LONG",            
            8:"DATA_SZ"}),
        FieldLenField("record_nb", 0, fmt="I", count_of="records"),
        ConditionalField(PacketListField("records", None, RecordLONG, count_from=lambda pkt:pkt.record_nb), lambda pkt: pkt.record_type == 3),
        ConditionalField(PacketListField("records", None, RecordSZ, count_from=lambda pkt:pkt.record_nb), lambda pkt: pkt.record_type == 8),
    ]

if __name__ == "__main__":
    p1 = MainPacket("\x00\x00\x00\x03" # Type is DATA_LONG
               "\x00\x00\x00\x04" # 4 records
               "\x00\x00\x00\x01" 
               "\x00\x00\x00\x02"
               "\x00\x00\x00\x03"
               "\x00\x00\x00\x04")
    p1.show()
    p2 = MainPacket("\x00\x00\x00\x08" # Type is DATA_SZ
               "\x00\x00\x00\x02" # 2 records
               "Hello\x00"
               " world.\x00")
    p2.show()

输出:

###[ MainPacket ]###
  record_type= DATA_LONG
  record_nb = 4
  \records   \
   |###[ RecordLONG ]###
   |  data_long_record= 1
   |###[ RecordLONG ]###
   |  data_long_record= 2
   |###[ RecordLONG ]###
   |  data_long_record= 3
   |###[ RecordLONG ]###
   |  data_long_record= 4
###[ MainPacket ]###
  record_type= DATA_SZ
  record_nb = 2
  \records   \
   |###[ RecordSZ ]###
   |  data_sz_record= 'Hello'
   |###[ RecordSZ ]###
   |  data_sz_record= ' world.'

答案 1 :(得分:0)

潜入Scapy之后,我找到了原因:lambda函数中的pkt.underlayer等于None。 Scapy没有报告错误。

我发现的解决方案是将底层存储在一个全局变量中,如下所示:

from scapy.all import Packet, IntField, IntEnumField, FieldLenField\
,PacketListField, StrNullField, ConditionalField, PacketLenField

current_main_packet = None

class Record(Packet):
    current_main_packet
    fields_desc = [
        #IntField("data_long_record", 0)
        #StrNullField("data_sz_record", "")
        ConditionalField(IntField("data_long_record", 0),
                         lambda pkt:pkt.underlayer.record_type==3),
        ConditionalField(StrNullField("data_sz_record", ""),
                         lambda pkt:pkt.underlayer.record_type==8)
    ]
    def extract_padding(self, s):
        return '', s

    def pre_dissect(self, s):
        self.underlayer = current_main_packet
        return s



class MainPacket(Packet):
    fields_desc = [
        IntEnumField("record_type", 1, {
            3:"DATA_LONG",            
            8:"DATA_SZ"}),
        FieldLenField("record_nb", 0, fmt="I", count_of="records"),
        PacketListField("records", None, Record, count_from=lambda pkt:pkt.record_nb)
    ]
    def extract_padding(self, s):
        return '', s

    def pre_dissect(self, s):
        global current_main_packet
        current_main_packet = self
        return s

if __name__ == "__main__":
    p1 = MainPacket("\x00\x00\x00\x03" # Type is DATA_LONG
               "\x00\x00\x00\x04" # 4 records
               "\x00\x00\x00\x01" 
               "\x00\x00\x00\x02"
               "\x00\x00\x00\x03"
               "\x00\x00\x00\x04")
    p1.show()
    p2 = MainPacket("\x00\x00\x00\x08" # Type is DATA_SZ
               "\x00\x00\x00\x02" # 2 records
               "Hello\x00"
               " world.\x00")
    p2.show()

我还在等待更优雅的解决方案: - )