我是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。
你有任何线索吗?
答案 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()
我还在等待更优雅的解决方案: - )