I'm a new scapy user and today I'm asking for your help.
I'm trying to add a new protocole in scapy. This protocole is a little bit special because he is extremely polymorph. By polymorph, i mean his structure and his length is dependent of some fields. Typically, there is a 'function' ByteField, and changing this value is changing all the next fields.
So, let's look this code ilustrating what i want to do. There is a simple polymorphic packet with a main constant structure //header//parameter//data//. Variations are inside parameter and data structure.
### 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)
]
Well, the point is the "param" and "data" fields in the main packet "myPacket". By example, "param" packetfield is asking a myPacketParam packet. But i want this packet virtual: the real packet behind can be myPacketParamOne or myPacketParamTwo. Same thing for Data.
Building this packet looks like ok.
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'
But i guess dissecting is not working correctly.
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
This is totally wrong.
I found some solutions. By example using conditionalField. But in my real protocole there is a lot of morphology in the same packet. And because fields cant have the same name, there is not a simple param field in the main packet, but a new name for each case. So, a real utilization of my scapy implementation is very boring and not simple.
A second solution is to unlink header, param and data. So you can use the protocole like this: p = myPacket() / myPacketParamOne() / myPacketDataOne(). But it's not a good solution for me because my real protocole got dependencies between every part, and it's still complicated for the user of my scapy implementation.
So if possible, i'm looking for a solution: - Respecting the main structure (header/parameter/data) - Simple use of this protocole (myPacket.param.whatyouwant to get param without consideration of what kind of param packet it is (but of course whatyouwant field exists in this kind of param packe))
I feel that the solution can be to redefine do_dissect function in every "virtual packet", or coding a new field especially for virtual packet, but i tried a lot of things without success.
I hope i was comprehensible.
Thank you in advance :)
Nathan