Scapy - adding a new field with a dynamic length

与世无争的帅哥 提交于 2019-12-12 17:57:43

问题


I am adding a new protocol to Scapy and I am having difficulties with a concrete field. This field specifies the length of a package payload. The field can be 1, 2, 3 or 4 bytes long depending on the length of the payload. Additionally, it is encoded. The way I found to determine if the size of the field is 1, 2, 3 or 4 bytes, is taking the first byte of the value and if it is less than 127 the field is represented by 1 byte, if it is more than 127 and less than x it is represented by 2 bytes and so on (this is because the encoding algorithm).

So, the problem is that I can't define this field length dynamically based on the value of the first byte. The first thing I tried is handling this problem with ConditionalFields, but this feels like the wrong path.

    ConditionalField(ByteField("length",1), lambda pkt:pkt.length <= 127),
    ConditionalField(ShortField("length",None), lambda pkt:pkt.length > 127),]

I think the solution is to define a new Scapy Field, but I don't know how to access the first byte and setup the length based on that. Any proposal will be appreciated. Thanks in advance.

Decoding algorithm:

def test(encoded_byte):
    if((encoded_byte & 128) != 0):
        return True
    else:
        return False


def decoding(bytes):
    multiplier = 1
    value = 0
    offset = 0
    condition = True

    while condition:
        encoded_byte = bytes[offset]
        value += (encoded_byte & 127) * multiplier
        multiplier *= 128
        if multiplier > 128 ** 3:
            raise Exception('Malformed Remaining Length')
        offset += 1
        condition = test(encoded_byte)

    return value

回答1:


You need to implement your own field here, with specific .addfield() and .getfield() methods. Based on your example, here is an example that should work:

class VariableFieldLenField(FieldLenField):
    def addfield(self, pkt, s, val):
        val = self.i2m(pkt, val)
        data = []
        while val:
            if val > 127:
                data.append(val & 127)
                val /= 127
            else:
                data.append(val)
                lastoffset = len(data) - 1
                data = "".join(chr(val | (0 if i == lastoffset else 128))
                               for i, val in enumerate(data))
                return s + data
            if len(data) > 3:
                raise Scapy_Exception("%s: malformed length field" %
                                      self.__class__.__name__)
    def getfield(self, pkt, s):
        value = 0
        for offset, curbyte in enumerate(s):
            curbyte = ord(curbyte)
            value += (curbyte & 127) * (128 ** offset)
            if curbyte & 128 == 0:
                return s[offset + 1:], value
            if offset > 2:
                raise Scapy_Exception("%s: malformed length field" %
                                      self.__class__.__name__)

Now the hardest part of the job has been done, you just need to create a layer that uses VariableFieldLenField field:

class NewLayer(Packet):
    fields_desc = [
        VariableFieldLenField("length", None, length_of="data"),
        StrLenField("data", "", length_from=lambda pkt: pkt.length),
    ]

And now, some tests to check everything works as expected:

NewLayer('\x01x')
str(_)
NewLayer(_)
NewLayer(data='x')
str(_)
NewLayer(_)
NewLayer(data='x' * 128)
str(_)
NewLayer(_)
str(NewLayer(data='x' * 16385))[:10]
NewLayer(str(NewLayer(data='x' * 16385))).length


来源:https://stackoverflow.com/questions/43711208/scapy-adding-a-new-field-with-a-dynamic-length

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!