def __init__(self, value, encoder=ENC_BITS_DEFAULT, fuzzable=True, name=None): ''' :param value: default value :type encoder: :class:`~kitty.model.low_level.encoder.BaseEncoder` :param encoder: encoder for the field :param fuzzable: is field fuzzable (default: True) :param name: name of the object (default: None) ''' if name and '/' in name: raise KittyException('Name (%s) includes invalid chars /' % (name)) super(BaseField, self).__init__(name, logger=logging.getLogger('DataModel')) kassert.is_of_types(encoder, self.__class__._encoder_type_) self._encoder = encoder self._num_mutations = 0 self._fuzzable = fuzzable self._default_value = value self._default_rendered = self._encode_value(self._default_value) self._current_value = value self._current_rendered = self._default_rendered self._current_index = -1 self.enclosing = None self._initialized = False self._hash = None self._need_second_pass = False self.offset = None self._controlled = False
def encode(self, value): ''' :param value: value to encode ''' kassert.is_of_types(value, str) encoded = value + '\x00' return Bits(bytes=encoded)
def __init__(self, value, num_bytes=1, fuzzable=True, name=None): ''' :type value: str or bytes :param value: value to mutate :param num_bytes: number of consequtive bytes to flip (invert) :param fuzzable: is field fuzzable (default: True) :param name: name of the object (default: None) :raises: ``KittyException`` if num_bytes is bigger than the value length :raises: ``KittyException`` if num_bytes is not positive ''' kassert.is_of_types(value, (bytes, bytearray, str)) value = strToBytes(value) if len(value) < num_bytes: raise KittyException('len(value) <= num_bytes', (len(value), num_bytes)) if num_bytes <= 0: raise KittyException('num_bytes(%d) <= 0' % (num_bytes)) super(ByteFlip, self).__init__(value=value, encoder=ENC_STR_DEFAULT, fuzzable=fuzzable, name=name) self._data_len = len(value) self._num_bytes = num_bytes self._num_mutations = self._data_len - (num_bytes - 1)
def push(self, field): """ Method overwrite to be able to deal with same name in container KittyException Add a field to the container, if the field is a Container itself, it should be poped() when done pushing into it. :param field: BaseField to push """ kassert.is_of_types(field, BaseField) container = self._container() field.enclosing = self if isinstance(field, Container): self._containers.append(field) if container: container.push(field) else: name = field.get_name() if name in self._fields_dict: pre_name = name name = random.randint(0, 99999) self.logger.debug( f'field with the name {pre_name} already exists in this container' ) self.logger.debug(f'So it has been changed to {name}.') if name: self._fields_dict[name] = field self._fields.append(field)
def encode(self, value): ''' :type value: ``str`` :param value: value to encode ''' kassert.is_of_types(value, str) return Bits(bytes=value)
def encode(self, value): ''' :type value: Bits :param value: value to encode ''' kassert.is_of_types(value, Bits) return value
def encode(self, value): ''' :param value: value to encode ''' kassert.is_of_types(value, str) encoded = value + '\x00' return Bits(bytes=encoded)
def encode(self, value): ''' :type value: Bits :param value: value to encode ''' kassert.is_of_types(value, Bits) return value
def __init__(self, value, encoder=ENC_BITS_DEFAULT, fuzzable=True, name=None): ''' :param value: default value :type encoder: :class:`~kitty.model.low_level.encoder.BaseEncoder` :param encoder: encoder for the field :param fuzzable: is field fuzzable (default: True) :param name: name of the object (default: None) ''' if name and '/' in name: raise KittyException('Name (%s) includes invalid chars /' % (name)) super(BaseField, self).__init__(name, logger=logging.getLogger('DataModel')) kassert.is_of_types(encoder, self.__class__._encoder_type_) self._encoder = encoder self._num_mutations = 0 self._fuzzable = fuzzable self._default_value = value self._default_rendered = self._encode_value(self._default_value) self._current_value = value self._current_rendered = self._default_rendered self._current_index = -1 self.enclosing = None self._initialized = False self._hash = None self._need_second_pass = False self.offset = None self._controlled = False
def encode(self, value): ''' :type value: ``str`` :param value: value to encode ''' kassert.is_of_types(value, str) return Bits(bytes=value)
def __init__(self, depends_on, algorithm, encoder=ENC_STR_DEFAULT, fuzzable=False, name=None): ''' :param depends_on: (name of) field to be hashed :param algorithm: hash algorithm name (from Hash._algos) or a function to calculate the value of the field. func(str) -> str :type encoder: :class:`~kitty.model.low_levele.encoder.StrEncoder` :param encoder: encoder for the field (default: ENC_STR_DEFAULT) :param fuzzable: is field fuzzable (default: False) :param name: (unique) name of the field (default: None) ''' if algorithm in Hash._algos: algo = Hash._algos[algorithm][0] def algo_func(x): return algo(x).digest() func = algo_func self._hash_length = Hash._algos[algorithm][1] else: try: res = algorithm('') kassert.is_of_types(res, types.StringTypes) func = algorithm self._hash_length = len(res) * 8 except: raise KittyException('algorithm should be a func(str)->str or one of the strings %s' % (Hash._algos.keys(),)) super(Hash, self).__init__(depends_on=depends_on, func=func, encoder=encoder, fuzzable=fuzzable, name=name)
def __init__(self, depends_on, length, algorithm='crc32', encoder=ENC_INT_DEFAULT, fuzzable=False, name=None): ''' :param depends_on: (name of) field to be checksummed :param length: length of the checksum field (in bits) :param algorithm: checksum algorithm name (from Checksum._algos) or a function to calculate the value of the field. func(Bits) -> int :type encoder: :class:`~kitty.model.low_levele.encoder.BitFieldEncoder` :param encoder: encoder for the field (default: ENC_INT_DEFAULT) :param fuzzable: is field fuzzable (default: False) :param name: (unique) name of the field (default: None) ''' if algorithm in Checksum._algos: func = Checksum._algos[algorithm] else: try: res = algorithm(empty_bits) kassert.is_of_types(res, types.IntType) func = algorithm except: raise KittyException('algorithm should be a func(str)->int or one of the strings %s' % (Checksum._algos.keys(),)) def calc_func(x): return func(x.bytes) & 0xffffffff bit_field = BitField(value=0, length=length, encoder=encoder) super(Checksum, self).__init__(depends_on=depends_on, bit_field=bit_field, calc_func=calc_func, fuzzable=fuzzable, name=name)
def encode(self, value): ''' :param value: value to encode ''' kassert.is_of_types(value, Bits) result = BitArray(value) result.reverse() return result
def encode(self, value): ''' :param value: value to encode ''' kassert.is_of_types(value, Bits) result = BitArray(value) result.reverse() return result
def encode(self, value): ''' :param value: value to encode ''' kassert.is_of_types(value, Bits) if len(value) % 8 != 0: raise KittyException('this encoder cannot encode bits that are not byte aligned') return self._encoder.encode(value.bytes)
def strToUtf8(value): ''' :type value: ``str`` :param value: value to encode ''' kassert.is_of_types(value, str) if sys.version_info < (3, ): return ''.join([unichr(ord(x)) for x in value]) return value
def encode(self, value): ''' :param value: value to encode ''' kassert.is_of_types(value, Bits) remainder = len(value) % 8 if remainder: value += Bits(remainder) return value
def encode(self, value): ''' :param value: value to encode ''' kassert.is_of_types(value, Bits) remainder = len(value) % 8 if remainder: value += Bits(bin='0' * (8 - remainder)) return value
def encode(self, value): ''' :param value: value to encode ''' kassert.is_of_types(value, str) encoded = value.encode('base64') if encoded: encoded = encoded[:-1] return Bits(bytes=encoded)
def encode(self, value): ''' :param value: value to encode ''' kassert.is_of_types(value, Bits) if len(value) % 8 != 0: raise KittyException( 'this encoder cannot encode bits that are not byte aligned') return self._encoder.encode(value.bytes)
def encode(self, value): ''' :param value: value to encode ''' kassert.is_of_types(value, str) encoded = value.encode('base64') if encoded: encoded = encoded[:-1] return Bits(bytes=encoded)
def str_to_bytes(value): """ :type value: ``str`` :param value: value to encode """ kassert.is_of_types(value, (bytes, bytearray, six.string_types)) if isinstance(value, six.string_types): return value.encode(encoding='utf-8') if isinstance(value, bytearray): return bytes(value) return value
def strToBytes(value): ''' :type value: ``str`` :param value: value to encode ''' kassert.is_of_types(value, (bytes, bytearray, six.string_types)) if isinstance(value, six.string_types): return bytes(bytearray([ord(x) for x in value])) elif isinstance(value, bytearray): return bytes(value) return value
def encode(self, value): ''' :param value: value to encode ''' kassert.is_of_types(value, str) try: encoded = value.encode(self._encoding) except UnicodeError: # TODO: make it better try: encoded = ''.join(unichr(ord(x)) for x in value).encode(self._encoding) except UnicodeError: encoded = value return Bits(bytes=encoded)
def __init__(self, depends_on, func, encoder=ENC_STR_DEFAULT, fuzzable=False, name=None): ''' :param depends_on: (name of) field we depend on :param func: function for processing of the dependant data. func(str)->str :type encoder: :class:`~kitty.model.low_levele.encoder.StrEncoder` :param encoder: encoder for the field (default: ENC_STR_DEFAULT) :param fuzzable: is container fuzzable :param name: (unique) name of the container ''' try: res = func('') kassert.is_of_types(res, types.StringTypes) self._func = func except: raise KittyException('func should be func(str)->str') super(CalculatedStr, self).__init__(depends_on=depends_on, encoder=encoder, fuzzable=fuzzable, name=name)
def __init__(self, depends_on, func, encoder=ENC_BITS_DEFAULT, fuzzable=True, name=None): ''' :param depends_on: (name of) field we depend on :type encoder: :class:`~kitty.model.low_levele.encoder.BitsEncoder` :param func: function for processing of the dependant data. func(Bits)->Bits :param encoder: encoder for the field :param fuzzable: is container fuzzable :param name: (unique) name of the container ''' try: res = func(empty_bits) kassert.is_of_types(res, Bits) self._func = func except: raise KittyException('func should be func(Bits)->Bits') super(CalculatedBits, self).__init__(depends_on=depends_on, encoder=encoder, fuzzable=fuzzable, name=name)
def encode(self, value): ''' :param value: value to encode ''' kassert.is_of_types(value, str) try: encoded = value.encode(self._encoding) except UnicodeError: # TODO: make it better try: encoded = ''.join(unichr(ord(x)) for x in value).encode(self._encoding) except UnicodeError: encoded = value return Bits(bytes=encoded)
def __init__(self, value, num_bits=1, fuzzable=True, name=None): """ :param value: value to mutate (str) :param num_bits: number of consequtive bits to flip (invert) :param fuzzable: is field fuzzable (default: True) :param name: name of the object (default: None) """ kassert.is_of_types(value, types.StringTypes) if len(value) * 8 <= num_bits: raise KittyException("len of value in bits(%d) <= num_bits(%d)", (len(value) * 8, num_bits)) if num_bits <= 0: raise KittyException("num_bits(%d) <= 0" % (num_bits)) super(BitFlip, self).__init__(value=Bits(bytes=value), encoder=ENC_BITS_DEFAULT, fuzzable=fuzzable, name=name) self._data_len = len(value) * 8 self._num_bits = num_bits self._num_mutations = self._data_len - (num_bits - 1)
def __init__(self, depends_on, algorithm, encoder=ENC_STR_DEFAULT, fuzzable=False, name=None): ''' :param depends_on: (name of) field to be hashed :param algorithm: hash algorithm name (from Hash._algos) or a function to calculate the value of the field. func(str) -> str :type encoder: :class:`~kitty.model.low_level.encoder.StrEncoder` :param encoder: encoder for the field (default: ENC_STR_DEFAULT) :param fuzzable: is field fuzzable (default: False) :param name: (unique) name of the field (default: None) :example: :: Container(name='SHA1 hashed string', fields=[ Meta(String(name='secret', value='s3cr3t')), Hash(name='secret_hash', algorithm='sha1', depends_on='secret') ]) ''' if algorithm in Hash._algos: algo = Hash._algos[algorithm][0] def algo_func(x): return algo(x).digest() func = algo_func self._hash_length = Hash._algos[algorithm][1] else: try: res = algorithm(b'') kassert.is_of_types(res, str) func = algorithm self._hash_length = len(res) * 8 except: raise KittyException( 'algorithm should be a func(str)->str or one of the strings %s' % (Hash._algos.keys(), )) super(Hash, self).__init__(depends_on=depends_on, func=func, encoder=encoder, fuzzable=fuzzable, name=name)
def __init__(self, depends_on, length, algorithm='crc32', encoder=ENC_INT_DEFAULT, fuzzable=False, name=None): ''' :param depends_on: (name of) field to be checksummed :param length: length of the checksum field (in bits) :param algorithm: checksum algorithm name (from Checksum._algos) or a function to calculate the value of the field. func(Bits) -> int :type encoder: :class:`~kitty.model.low_level.encoder.BitFieldEncoder` :param encoder: encoder for the field (default: ENC_INT_DEFAULT) :param fuzzable: is field fuzzable (default: False) :param name: (unique) name of the field (default: None) :example: :: Container(name='checksummed chunk', fields=[ RandomBytes(name='chunk', value='1234', min_length=0, max_length=75), Checksum(name='CRC', depends_on='chunk', length=32) ]) ''' if algorithm in Checksum._algos: func = Checksum._algos[algorithm] else: try: res = algorithm(empty_bits) kassert.is_of_types(res, int) func = algorithm except: raise KittyException( 'algorithm should be a func(str)->int or one of the strings %s' % (Checksum._algos.keys(), )) def calc_func(x): return func(x.bytes) & 0xffffffff bit_field = BitField(value=0, length=length, encoder=encoder) super(Checksum, self).__init__(depends_on=depends_on, bit_field=bit_field, calc_func=calc_func, fuzzable=fuzzable, name=name)
def __init__(self, value, num_bytes=1, fuzzable=True, name=None): """ :type value: str :param value: value to mutate :param num_bytes: number of consequtive bytes to flip (invert) :param fuzzable: is field fuzzable (default: True) :param name: name of the object (default: None) """ kassert.is_of_types(value, types.StringTypes) if len(value) < num_bytes: raise KittyException("len(value) <= num_bytes", (len(value), num_bytes)) if num_bytes <= 0: raise KittyException("num_bytes(%d) <= 0" % (num_bytes)) super(ByteFlip, self).__init__(value=value, encoder=ENC_STR_DEFAULT, fuzzable=fuzzable, name=name) self._data_len = len(value) self._num_bytes = num_bytes self._num_mutations = self._data_len - (num_bytes - 1)
def __init__(self, value, num_bits=1, fuzzable=True, name=None): ''' :param value: value to mutate (str) :param num_bits: number of consequtive bits to flip (invert) :param fuzzable: is field fuzzable (default: True) :param name: name of the object (default: None) :raises: ``KittyException`` if num_bits is bigger than the value length in bits :raises: ``KittyException`` if num_bits is not positive ''' kassert.is_of_types(value, types.StringTypes) if len(value) * 8 < num_bits: raise KittyException('len of value in bits(%d) < num_bits(%d)' % (len(value) * 8, num_bits)) if num_bits <= 0: raise KittyException('num_bits(%d) <= 0' % (num_bits)) super(BitFlip, self).__init__(value=Bits(bytes=value), encoder=ENC_BITS_DEFAULT, fuzzable=fuzzable, name=name) self._data_len = len(value) * 8 self._num_bits = num_bits self._num_mutations = self._data_len - (num_bits - 1)
def __init__(self, value, encoder=ENC_BITS_DEFAULT, fuzzable=True, name=None): ''' :param value: default value :type encoder: :class:`~kitty.model.low_levele.encoder.BaseEncoder` :param encoder: encoder for the field :param fuzzable: is field fuzzable (default: True) :param name: name of the object (default: None) ''' super(BaseField, self).__init__(name, logger=logging.getLogger('DataModel')) kassert.is_of_types(encoder, self.__class__._encoder_type_) self._encoder = encoder self._num_mutations = 0 self._fuzzable = fuzzable self._default_value = value self._default_rendered = self._encode_value(self._default_value) self._current_value = value self._current_rendered = self._default_rendered self._current_index = -1 self._enclosing = None self._mutating = False
def __init__(self, value, num_bytes=1, fuzzable=True, name=None): ''' :type value: str or bytes :param value: value to mutate :param num_bytes: number of consequtive bytes to flip (invert) :param fuzzable: is field fuzzable (default: True) :param name: name of the object (default: None) :raises: ``KittyException`` if num_bytes is bigger than the value length :raises: ``KittyException`` if num_bytes is not positive ''' kassert.is_of_types(value, (bytes, bytearray, str)) value = strToBytes(value) if len(value) < num_bytes: raise KittyException('len(value) <= num_bytes', (len(value), num_bytes)) if num_bytes <= 0: raise KittyException('num_bytes(%d) <= 0' % (num_bytes)) super(ByteFlip, self).__init__(value=value, encoder=ENC_STR_DEFAULT, fuzzable=fuzzable, name=name) self._data_len = len(value) self._num_bytes = num_bytes self._num_mutations = self._data_len - (num_bytes - 1)
def push(self, field): ''' Add a field to the container, if the field is a Container itself, it should be poped() when done pushing into it :param field: BaseField to push ''' kassert.is_of_types(field, BaseField) container = self._container() field.enclosing = self if isinstance(field, Container): self._containers.append(field) if container: container.push(field) else: name = field.get_name() if name in self._fields_dict: raise KittyException('field with the name (%s) already exists in this container' % (name)) if name: self._fields_dict[name] = field self._fields.append(field) return True
def __init__(self, depends_on, bit_field, calc_func, encoder=ENC_BITS_DEFAULT, fuzzable=False, name=None): ''' :param depends_on: (name of) field we depend on :param bit_field: a BitField to be used for holding the value :param calc_func: function to calculate the value of the field. func(bits) -> int :type encoder: :class:`~kitty.model.low_levele.encoder.BitsEncoder` :param encoder: encoder for the field (default: ENC_BITS_DEFAULT) :param fuzzable: is container fuzzable :param name: (unique) name of the container ''' kassert.is_of_types(bit_field, BitField) try: res = calc_func(empty_bits) kassert.is_of_types(res, (types.IntType, types.LongType)) except: raise KittyException('algorithm should be a func(str)->int') super(CalculatedInt, self).__init__(depends_on=depends_on, encoder=encoder, fuzzable=fuzzable, name=name) self._bit_field = bit_field self._calc_func = calc_func self._first_render = False self._num_mutations = self._bit_field.num_mutations()
def push(self, field): ''' Add a field to the container, if the field is a Container itself, it should be poped() when done pushing into it :param field: BaseField to push ''' kassert.is_of_types(field, BaseField) container = self._container() field._set_enclosing(self) if isinstance(field, Container): self._containers.append(field) if container: container.push(field) else: name = field.get_name() if name in self._fields_dict: raise KittyException('field with the name (%s) already exists in this container' % (name)) if name: self._fields_dict[name] = field self._fields.append(field) return True
def __init__(self, value, num_bits=1, fuzzable=True, name=None): ''' :param value: value to mutate (str) :param num_bits: number of consequtive bits to flip (invert) :param fuzzable: is field fuzzable (default: True) :param name: name of the object (default: None) :raises: ``KittyException`` if num_bits is bigger than the value length in bits :raises: ``KittyException`` if num_bits is not positive ''' kassert.is_of_types(value, types.StringTypes) if len(value) * 8 < num_bits: raise KittyException('len of value in bits(%d) < num_bits(%d)' % (len(value) * 8, num_bits)) if num_bits <= 0: raise KittyException('num_bits(%d) <= 0' % (num_bits)) super(BitFlip, self).__init__(value=Bits(bytes=value), encoder=ENC_BITS_DEFAULT, fuzzable=fuzzable, name=name) self._data_len = len(value) * 8 self._num_bits = num_bits self._num_mutations = self._data_len - (num_bits - 1)
def __init__(self, depends_on, func, encoder=ENC_BITS_DEFAULT, fuzzable=True, name=None): ''' :param depends_on: (name of) field we depend on :type encoder: :class:`~kitty.model.low_level.encoder.BitsEncoder` :param func: function for processing of the dependant data. func(Bits)->Bits :param encoder: encoder for the field :param fuzzable: is container fuzzable :param name: (unique) name of the container ''' try: res = func(empty_bits) kassert.is_of_types(res, Bits) self._func = func except: raise KittyException('func should be func(Bits)->Bits') super(CalculatedBits, self).__init__(depends_on=depends_on, encoder=encoder, fuzzable=fuzzable, name=name)
def __init__(self, depends_on, func, encoder=ENC_STR_DEFAULT, fuzzable=False, name=None): ''' :param depends_on: (name of) field we depend on :param func: function for processing of the dependant data. func(str)->str :type encoder: :class:`~kitty.model.low_level.encoder.StrEncoder` :param encoder: encoder for the field (default: ENC_STR_DEFAULT) :param fuzzable: is container fuzzable :param name: (unique) name of the container ''' try: res = func(b'') kassert.is_of_types(res, bytes) self._func = func except: raise KittyException('func should be func(str)->str') super(CalculatedStr, self).__init__(depends_on=depends_on, encoder=encoder, fuzzable=fuzzable, name=name)
def encode(self, value): kassert.is_of_types(value, Bits) encoded = self._func(value) return encoded
def encode(self, value): kassert.is_of_types(value, str) encoded = self._func(value) return Bits(bytes=encoded)
def encode(self, value): kassert.is_of_types(value, Bits) encoded = self._func(value) return encoded
def encode(self, value): kassert.is_of_types(value, str) encoded = self._func(value) return Bits(bytes=encoded)