Exemple #1
0
def ReadBytes(params, ctxt, scope, stream, coord):
    if len(params) != 3:
        raise errors.InvalidArguments(coord, "3 arguments (buffer, pos, n)",
                                      "{} args".format(len(params)))
    if not isinstance(params[0], pfp.fields.Array):
        raise errors.InvalidArguments(coord, "buffer must be an array",
                                      params[0].__class__.__name__)
    if params[0].field_cls not in [pfp.fields.UChar, pfp.fields.Char]:
        raise errors.InvalidArguments(
            coord, "buffer must be an array of uchar or char",
            params[0].field_cls.__name__)

    if not isinstance(params[1], pfp.fields.IntBase):
        raise errors.InvalidArguments(coord, "pos must be an integer",
                                      params[1].__class__.__name__)

    if not isinstance(params[2], pfp.fields.IntBase):
        raise errors.InvalidArguments(coord, "n must be an integer",
                                      params[2].__class__.__name__)

    bits = stream._bits
    curr_pos = stream.tell()

    vals = [
        params[0].field_cls(stream) for x in six.moves.range(PYVAL(params[2]))
    ]

    stream.seek(curr_pos, 0)
    stream._bits = bits

    params[0]._pfp__set_value(vals)
Exemple #2
0
def packer_gzip(params, ctxt, scope, stream, coord):
    """``PackerGZip`` - implements both unpacking and packing. Can be used
    as the ``packer`` for a field. When packing, concats the build output
    of all params and gzip-compresses the result. When unpacking, concats
    the build output of all params and gzip-decompresses the result.
    
    Example:

        The code below specifies that the ``data`` field is gzipped
        and that once decompressed, should be parsed with ``PACK_TYPE``.
        When building the ``PACK_TYPE`` structure, ``data`` will be updated
        with the compressed data.::

            char data[0x100]<packer=PackerGZip, packtype=PACK_TYPE>;

    :pack: True if the data should be packed, false if it should be unpacked
    :data: The data to operate on
    :returns: An array
    """
    if len(params) <= 1:
        raise errors.InvalidArguments(coord, "{} args".format(len(params)),
                                      "at least two arguments")

    # to gzip it (pack it)
    if params[0]:
        return pack_gzip(params[1:], ctxt, scope, stream, coord)
    else:
        return unpack_gzip(params[1:], ctxt, scope, stream, coord)
Exemple #3
0
def Stricmp(params, ctxt, scope, stream, coord):
	if len(params) != 2:
		raise errors.InvalidArguments(coord, "{} args".format(len(params)), "2 arguments")
	str1 = PYSTR(params[0]).lower()
	str2 = PYSTR(params[1]).lower()
	
	return _cmp(str1, str2)
def Strncpy(params, ctxt, scope, stream, coord):
    if len(params) != 3:
        raise errors.InvalidArguments(coord, "{} args".format(len(params)),
                                      "3 arguments")

    max_len = PYVAL(params[2])
    params[0]._pfp__set_value(PYSTR(params[1])[:max_len])
Exemple #5
0
def Strnicmp(params, ctxt, scope, stream, coord):
	if len(params) != 3:
		raise errors.InvalidArguments(coord, "{} args".format(len(params)), "3 arguments")
	max_chars = PYVAL(params[2])
	str1 = PYSTR(params[0])[:max_chars].lower()
	str2 = PYSTR(params[1])[:max_chars].lower()

	return _cmp(str1, str2)
Exemple #6
0
def IsLittleEndian(params, ctxt, scope, stream, coord):
    if len(params) > 0:
        raise errors.InvalidArguments(coord, "0 arguments",
                                      "{} args".format(len(params)))
    if pfp.fields.NumberBase.endian == pfp.fields.LITTLE_ENDIAN:
        return 0
    else:
        return 1
Exemple #7
0
def Strlen(params, ctxt, scope, stream, coord):
	if len(params) != 1:
		raise errors.InvalidArguments(coord, "1 argument", "{} args".format(len(params)))
	val = params[0]
	if isinstance(val, pfp.fields.Array):
		val = val._array_to_str()
	else:
		val = PYVAL(val)
	return len(val)
Exemple #8
0
def FSkip(params, ctxt, scope, stream, coord):
    """Returns 0 if successful or -1 if the address is out of range
	"""
    if len(params) != 1:
        raise errors.InvalidArguments(coord, "{} args".format(len(params)),
                                      "FSkip accepts only one argument")

    skip_amt = PYVAL(params[0])
    pos = stream.tell()
    return FSeek([pos + skip_amt], ctxt, scope, stream, coord)
def Strcmp(params, ctxt, scope, stream, coord):
    if len(params) != 2:
        raise errors.InvalidArguments(coord, "{} args".format(len(params)),
                                      "2 arguments")
    str1 = PYSTR(params[0])
    str2 = PYSTR(params[1])

    if params[0] is None or params[1] is None:
        return 0
    return _cmp(str1, str2)
Exemple #10
0
def FEof(params, ctxt, scope, stream, coord):
    if len(params) > 0:
        raise errors.InvalidArguments(coord, "0 arguments",
                                      "{} args".format(len(params)))

    # now that streams are _ALL_ BitwrappedStreams, we can use BitwrappedStream-specific
    # functions
    if stream.is_eof():
        return 1
    else:
        return 0
def Memcpy(params, ctxt, scope, stream, coord):
    if params[0]._pfp__interp._generate:
        return
    if len(params) < 3:
        raise errors.InvalidArguments(coord, "{} args".format(len(params)),
                                      "at least 3 args")
    if len(params) > 5:
        raise errors.InvalidArguments(coord, "{} args".format(len(params)),
                                      "at most 5 args")

    dest = params[0]
    src = params[1]
    n = PYVAL(params[2])

    if len(params) > 3:
        dest_offset = PYVAL(params[3])
    else:
        dest_offset = 0

    if len(params) > 4:
        src_offset = PYVAL(params[4])
    else:
        src_offset = 0

    if not isinstance(dest, pfp.fields.Array):
        raise errors.InvalidArguments(coord, dest.__class__.__name__,
                                      "an array")

    if not isinstance(src, pfp.fields.Array):
        raise errors.InvalidArguments(coord, src.__class__.__name__,
                                      "an array")

    count = 0
    while n > 0:
        val = dest.field_cls()
        val._pfp__set_value(src[src_offset + count]._pfp__value)
        # TODO clone it
        dest[dest_offset + count] = val
        count += 1
        n -= 1
Exemple #12
0
def Strstr(params, ctxt, scope, stream, coord):
	if len(params) != 2:
		raise errors.InvalidArguments(coord, "{} args".format(len(params)), "2 arguments")
	
	haystack = PYSTR(params[0])
	needle = PYSTR(params[1])

	try:
		return haystack.index(needle)

	# expected condition when the substring doesn't exist
	except ValueError as e:
		return -1
Exemple #13
0
def FSeek(params, ctxt, scope, stream, coord):
    """Returns 0 if successful or -1 if the address is out of range
    """
    if len(params) != 1:
        raise errors.InvalidArguments(
            coord,
            "{} args".format(len(params)),
            "FSeek accepts only one argument",
        )

    if params[0] is None:
        return 0
    pos = PYVAL(params[0])
    curr_pos = stream.tell()

    fsize = stream.size()

    if pos > fsize:
        stream.seek(fsize)
        return -1
    elif pos < 0:
        stream.seek(0)
        return -1

    diff = pos - curr_pos
    if diff < 0:
        stream.seek(pos)
        return 0

    data = stream.read(diff)

    # let the ctxt automatically append numbers, as needed, unless the previous
    # child was also a skipped field
    skipped_name = "_skipped"

    if len(ctxt._pfp__children
           ) > 0 and ctxt._pfp__children[-1]._pfp__name.startswith("_skipped"):
        old_name = ctxt._pfp__children[-1]._pfp__name
        data = ctxt._pfp__children[-1].raw_data + data
        skipped_name = old_name
        ctxt._pfp__children = ctxt._pfp__children[:-1]
        del ctxt._pfp__children_map[old_name]

    tmp_stream = bitwrap.BitwrappedStream(six.BytesIO(data))
    new_field = pfp.fields.Array(len(data), pfp.fields.Char, tmp_stream)
    ctxt._pfp__add_child(skipped_name, new_field, stream)
    scope.add_var(skipped_name, new_field)

    return 0
Exemple #14
0
    def instantiate(self, scope, args, interp):
        """Create a ParamList instance for actual interpretation

        :args: TODO
        :returns: A ParamList object

        """
        param_instances = []

        BYREF = "byref"

        # TODO are default values for function parameters allowed in 010?
        #print 'self._params=',self._params,type(self._params)

        for x in self._params:
            if x == pfp.fields.Void:
                continue
            param_name, param_cls = x
            # we don't instantiate a copy of byref params
            if getattr(param_cls, "byref", False):
                param_instances.append(BYREF)
            else:
                field = param_cls()
                field._pfp__name = param_name
                param_instances.append(field)

        if len(args) != len(param_instances):
            raise errors.InvalidArguments(
                self._coords, [x.__class__.__name__ for x in args],
                [x.__class__.__name__ for x in param_instances])

        # TODO type checking on provided types

        for x in six.moves.range(len(args)):
            param = param_instances[x]

            # arrays are simply passed through into the function. We shouldn't
            # have to worry about frozenness/unfrozenness at this point
            if param is BYREF or isinstance(param, pfp.fields.Array):
                param = args[x]
                param_instances[x] = param
                scope.add_local(self._params[x][0], param)
            else:
                param._pfp__set_value(args[x])
                scope.add_local(param._pfp__name, param)
            param._pfp__interp = interp

        return ParamList(param_instances)
Exemple #15
0
def SubStr(params, ctxt, scope, stream, coord):
	if len(params) < 2:
		raise errors.InvalidArguments(coord, "2 arguments", "{} args".format(len(params)))
	
	string = PYSTR(params[0])
	start = PYVAL(params[1])
	count = -1
	if len(params) > 2:
		count = PYVAL(params[2])
	if count < 0:
		count = -1
	
	if count == -1:
		return string[start:]
	else:
		return string[start:start+count]
Exemple #16
0
def _read_data(params, stream, cls, coord):
    bits = stream._bits
    curr_pos = stream.tell()

    if len(params) == 1:
        pos = PYVAL(params[0])
        stream.seek(pos, 0)
    elif len(params) > 1:
        raise errors.InvalidArguments(coord, "at most 1 arguments",
                                      "{} args".format(len(params)))

    res = cls(stream=stream)

    # reset the stream
    stream.seek(curr_pos, 0)
    stream._bits = bits

    return res
Exemple #17
0
def SPrintf(params, ctxt, scope, stream, coord):
	if len(params) < 2:
		raise errors.InvalidArguments(coord, "{} args".format(len(params)), "at least 2 args")

	if len(params) == 2:
		params[0]._pfp__set_value(PYSTR(params[1]))
		return len(PYSTR(params[1]))

	parts = []
	for part in params[2:]:
		if isinstance(part, pfp.fields.Array) or isinstance(part, pfp.fields.String):
			parts.append(PYSTR(part))
		else:
			parts.append(PYVAL(part))

	new_value = PYSTR(params[1]) % tuple(parts)
	params[0]._pfp__set_value(new_value)
	return len(new_value)
Exemple #18
0
def unpack_gzip(params, ctxt, scope, stream, coord):
	"""``UnpackGZip`` - Concats the build output of all params and gunzips the
	resulting data, returning a char array.

	Example: ::

		char data[0x100]<pack=UnpackGZip, ...>;
	"""
	if len(params) == 0:
		raise errors.InvalidArguments(coord, "{} args".format(len(params)), "at least one argument")
	
	built = utils.binary("")
	for param in params:
		if isinstance(param, pfp.fields.Field):
			built += param._pfp__build()
		else:
			built += param
	
	return zlib.decompress(built)
Exemple #19
0
def watch_length(params, ctxt, scope, stream, coord):
    """WatchLength - Watch the total length of each of the params.
    
    Example:
        The code below uses the ``WatchLength`` update function to update
        the ``length`` field to the length of the ``data`` field ::

            int length<watch=data, update=WatchLength>;
            char data[length];
    """
    if len(params) <= 1:
        raise errors.InvalidArguments(coord, "{} args".format(len(params)), "at least two arguments")
    
    to_update = params[0]

    total_size = 0
    for param in params[1:]:
        total_size += param._pfp__width()
    
    to_update._pfp__set_value(total_size)
Exemple #20
0
def watch_crc(params, ctxt, scope, stream, coord):
    """WatchCrc32 - Watch the total crc32 of the params.
    
    Example:
        The code below uses the ``WatchCrc32`` update function to update
        the ``crc`` field to the crc of the ``length`` and ``data`` fields ::

            char length;
            char data[length];
            int crc<watch=length;data, update=WatchCrc32>;
    """
    if len(params) <= 1:
        raise errors.InvalidArguments(coord, "{} args".format(len(params)), "at least two arguments")
    
    to_update = params[0]

    total_data = utils.binary("")
    for param in params[1:]:
        total_data += param._pfp__build()
    
    to_update._pfp__set_value(binascii.crc32(total_data))
Exemple #21
0
    def instantiate(self, scope, args, interp):
        """Create a ParamList instance for actual interpretation

		:args: TODO
		:returns: A ParamList object

		"""
        param_instances = []

        BYREF = "byref"

        # TODO are default values for function parameters allowed in 010?
        for param_name, param_cls in self._params:
            # we don't instantiate a copy of byref params
            if getattr(param_cls, "byref", False):
                param_instances.append(BYREF)
            else:
                field = param_cls()
                field._pfp__name = param_name
                param_instances.append(field)

        if len(args) != len(param_instances):
            raise errors.InvalidArguments(
                self._coords, [x.__class__.__name__ for x in args],
                [x.__class__.__name__ for x in param_instances])

        # TODO type checking on provided types

        for x in six.moves.range(len(args)):
            param = param_instances[x]
            if param is BYREF:
                param = args[x]
                param_instances[x] = param
                scope.add_local(self._params[x][0], param)
            else:
                param._pfp__set_value(args[x])
                scope.add_local(param._pfp__name, param)
            param._pfp__interp = interp

        return ParamList(param_instances)
def Memcmp(params, ctxt, scope, stream, coord):
    """
    int Memcmp( const uchar s1[], const uchar s2[], int n )

    Compares the first n bytes of s1 and s2. Returns a value less than zero if
    s1 is less than s2, zero if they are equal, or a value greater than zero if
    s1 is greater than s2.
    """
    if len(params) < 3:
        raise errors.InvalidArguments(
            coord,
            "{} args".format(len(params)),
            "3 arguments",
        )
    s1 = PYSTR(params[0])
    s2 = PYSTR(params[1])
    n = PYVAL(params[2])

    s1_sub = s1[:n]
    s2_sub = s2[:n]

    return _cmp(s1_sub, s2_sub)
def Atoi(params, ctxt, scope, stream, coord):
    if len(params) < 1:
        raise errors.InvalidArguments(coord, "{} args".format(len(params)),
                                      "one arg")
    return int(PYSTR(params[0]))
def Strcpy(params, ctxt, scope, stream, coord):
    if len(params) != 2:
        raise errors.InvalidArguments(coord, "{} args".format(len(params)),
                                      "2 arguments")

    params[0]._pfp__set_value(PYSTR(params[1]))
def ToUpper(params, ctxt, scope, stream, coord):
    if len(params) != 1:
        raise errors.InvalidArguments(coord, "{} args".format(len(params)),
                                      "1 argument")
    return ord(chr(PYVAL(params[0])).upper())
Exemple #26
0
def BitfieldRightToLeft(params, ctxt, scope, stream, coord, interp):
    if len(params) > 0:
        raise errors.InvalidArguments(coord, "0 arguments",
                                      "{} args".format(len(params)))
    interp.set_bitfield_right_left()
Exemple #27
0
def BitfieldEnablePadding(params, ctxt, scope, stream, coord, interp):
    if len(params) > 0:
        raise errors.InvalidArguments(coord, "0 arguments",
                                      "{} args".format(len(params)))
    interp.set_bitfield_padded(True)
Exemple #28
0
def BigEndian(params, ctxt, scope, stream, coord):
    if len(params) > 0:
        raise errors.InvalidArguments(coord, "0 arguments",
                                      "{} args".format(len(params)))
    pfp.fields.NumberBase.endian = pfp.fields.BIG_ENDIAN
Exemple #29
0
def Exit(params, ctxt, scope, stream, coord):
    if len(params) != 1:
        raise errors.InvalidArguments(coord, "1 arguments", "{} args".format(len(params)))
    error_code = PYVAL(params[0])
    raise errors.InterpExit(error_code)
Exemple #30
0
def FTell(params, ctxt, scope, stream, coord):
    if len(params) > 0:
        raise errors.InvalidArguments(coord, "0 arguments",
                                      "{} args".format(len(params)))
    return stream.tell()