Python 虚拟PacketField:如何处理多态协议?
我是一个新的scapy用户,今天我请求您的帮助 我想在斯卡皮加入一个新的协议。这个原型有点特别,因为他是非常多形的。所谓多形,我指的是他的结构和长度依赖于某些场。通常,有一个“函数”ByteField,更改此值就是更改所有下一个字段 那么,让我们看看这段代码,它说明了我想做什么。有一个简单的多态数据包,其主常量结构为//header//parameter//data//。变量是内部参数和数据结构Python 虚拟PacketField:如何处理多态协议?,python,scapy,Python,Scapy,我是一个新的scapy用户,今天我请求您的帮助 我想在斯卡皮加入一个新的协议。这个原型有点特别,因为他是非常多形的。所谓多形,我指的是他的结构和长度依赖于某些场。通常,有一个“函数”ByteField,更改此值就是更改所有下一个字段 那么,让我们看看这段代码,它说明了我想做什么。有一个简单的多态数据包,其主常量结构为//header//parameter//data//。变量是内部参数和数据结构 ### VIRTUAL PARAMETER PACKET class myPacketParam(P
### 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的示例。但在我真正的原型中,在同一个数据包中有很多形态。由于字段不能具有相同的名称,因此主数据包中没有简单的param字段,而是为每种情况指定一个新名称。因此,真正利用我的scapy实现是非常无聊和不简单的
第二种解决方案是取消头、参数和数据的链接。所以您可以像这样使用协议:p=myPacket()/myPacketParamOne()/myPacketDataOne()。但这对我来说不是一个好的解决方案,因为我真正的协议在每个部分之间都有依赖关系,对于scapy实现的用户来说仍然很复杂
因此,如果可能,我正在寻找解决方案:
-关于主结构(标题/参数/数据)
-这个协议的简单使用(myPacket.param.whatyouwant获取param,而不考虑它是什么类型的param包(当然,在这种param包中存在whatyouwant字段))
我觉得解决方法可以是在每个“虚拟数据包”中重新定义do_dissect函数,或者专门为虚拟数据包编码一个新字段,但我做了很多尝试都没有成功
我希望我是可以理解的
提前感谢:)
内森(这有点老了)
自从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
),
]
它允许您根据条件使用具有多种类型的同一字段