Esempio n. 1
0
def _arithmetic_helper(
    a: "BitVecFunc", b: Union[BitVec, int], operation: Callable
) -> "BitVecFunc":
    """
    Helper function for arithmetic operations on BitVecFuncs.

    :param a: The BitVecFunc to perform the operation on.
    :param b: A BitVec or int to perform the operation on.
    :param operation: The arithmetic operation to perform.
    :return: The resulting BitVecFunc
    """
    if isinstance(b, int):
        b = BitVec(z3.BitVecVal(b, a.size()))

    raw = operation(a.raw, b.raw)
    union = a.annotations.union(b.annotations)

    if isinstance(b, BitVecFunc):
        return BitVecFunc(
            raw=raw,
            func_name="Hybrid",
            input_=BitVec(z3.BitVec("", 256), annotations=union),
            nested_functions=a.nested_functions + b.nested_functions + [a, b],
        )

    return BitVecFunc(
        raw=raw,
        func_name=a.func_name,
        input_=a.input_,
        annotations=union,
        nested_functions=a.nested_functions + [a],
    )
Esempio n. 2
0
def _arithmetic_helper(a: "BitVecFunc", b: Union[BitVec, int],
                       operation: Callable) -> "BitVecFunc":
    """
    Helper function for arithmetic operations on BitVecFuncs.

    :param a: The BitVecFunc to perform the operation on.
    :param b: A BitVec or int to perform the operation on.
    :param operation: The arithmetic operation to perform.
    :return: The resulting BitVecFunc
    """
    if isinstance(b, int):
        b = BitVec(z3.BitVecVal(b, a.size()))

    raw = operation(a.raw, b.raw)
    union = a.annotations.union(b.annotations)

    if isinstance(b, BitVecFunc):
        # TODO: Find better value to set input and name to in this case?
        input_string = "MisleadingNotationop(invhash({}) {} invhash({})".format(
            hash(a), operation, hash(b))
        return BitVecFunc(
            raw=raw,
            func_name="Hybrid",
            input_=BitVec(z3.BitVec(input_string, 256), annotations=union),
        )

    return BitVecFunc(raw=raw,
                      func_name=a.func_name,
                      input_=a.input_,
                      annotations=union)
Esempio n. 3
0
def Concat(*args: Union[BitVec, List[BitVec]]) -> BitVec:
    """Create a concatenation expression.

    :param args:
    :return:
    """
    # The following statement is used if a list is provided as an argument to concat
    if len(args) == 1 and isinstance(args[0], list):
        bvs = args[0]  # type: List[BitVec]
    else:
        bvs = cast(List[BitVec], args)

    nraw = z3.Concat([a.raw for a in bvs])
    annotations = set()  # type: Annotations

    nested_functions = []  # type: List[BitVecFunc]
    for bv in bvs:
        annotations = annotations.union(bv.annotations)
        if isinstance(bv, BitVecFunc):
            nested_functions += bv.nested_functions
            nested_functions += [bv]

    if nested_functions:
        return BitVecFunc(
            raw=nraw,
            func_name="Hybrid",
            input_=BitVec(z3.BitVec("", 256), annotations=annotations),
            nested_functions=nested_functions,
        )

    return BitVec(nraw, annotations)
Esempio n. 4
0
def BVAddNoOverflow(a: Union[BitVec, int], b: Union[BitVec, int],
                    signed: bool) -> Bool:
    """Creates predicate that verifies that the addition doesn't overflow.

    :param a:
    :param b:
    :param signed:
    :return:
    """
    if not isinstance(a, BitVec):
        a = BitVec(z3.BitVecVal(a, 256))
    if not isinstance(b, BitVec):
        b = BitVec(z3.BitVecVal(b, 256))
    return Bool(z3.BVAddNoOverflow(a.raw, b.raw, signed))
Esempio n. 5
0
 def __getitem__(self, item: BitVec) -> BitVec:
     """Gets item from the array, item can be symbolic."""
     if isinstance(item, slice):
         raise ValueError(
             "Instance of BaseArray, does not support getitem with slices")
     return BitVec(cast(z3.BitVecRef, z3.Select(self.raw,
                                                item.raw)))  # type: ignore
Esempio n. 6
0
def _comparison_helper(
    a: "BitVecFunc",
    b: Union[BitVec, int],
    operation: Callable,
    default_value: bool,
    inputs_equal: bool,
) -> Bool:
    """
    Helper function for comparison operations with BitVecFuncs.

    :param a: The BitVecFunc to compare.
    :param b: A BitVec or int to compare to.
    :param operation: The comparison operation to perform.
    :return: The resulting Bool
    """
    # Is there some hack for gt/lt comparisons?
    if isinstance(b, int):
        b = BitVec(z3.BitVecVal(b, a.size()))
    union = a.annotations.union(b.annotations)

    if not a.symbolic and not b.symbolic:
        return Bool(z3.BoolVal(operation(a.value, b.value)), annotations=union)

    if (not isinstance(b, BitVecFunc) or not a.func_name or not a.input_
            or not a.func_name == b.func_name):
        return Bool(z3.BoolVal(default_value), annotations=union)

    return And(
        Bool(cast(z3.BoolRef, operation(a.raw, b.raw)), annotations=union),
        a.input_ == b.input_ if inputs_equal else a.input_ != b.input_,
    )

    return a.input_ == b.input_
Esempio n. 7
0
def _arithmetic_helper(a: "BitVecFunc", b: Union[BitVec, int],
                       operation: Callable) -> "BitVecFunc":
    """
    Helper function for arithmetic operations on BitVecFuncs.

    :param a: The BitVecFunc to perform the operation on.
    :param b: A BitVec or int to perform the operation on.
    :param operation: The arithmetic operation to perform.
    :return: The resulting BitVecFunc
    """
    if isinstance(b, int):
        b = BitVec(z3.BitVecVal(b, a.size()))

    raw = operation(a.raw, b.raw)
    union = a.annotations.union(b.annotations)

    if isinstance(b, BitVecFunc):
        # TODO: Find better value to set input and name to in this case?
        return BitVecFunc(raw=raw,
                          func_name=None,
                          input_=None,
                          annotations=union)

    return BitVecFunc(raw=raw,
                      func_name=a.func_name,
                      input_=a.input_,
                      annotations=union)
Esempio n. 8
0
    def __xor__(self, other: Union[int, "BitVec"]) -> "BitVecFunc":
        """Create a xor expression.

        :param other: The int or BitVec to xor with this BitVecFunc
        :return: The resulting BitVecFunc
        """
        if not isinstance(other, BitVec):
            other = BitVec(z3.BitVecVal(other, self.size()))
        return _arithmetic_helper(self, other, operator.xor)
Esempio n. 9
0
    def __ge__(self, other: Union[int, "BitVec"]) -> Bool:
        """Create a signed greater than or equal to expression.

        :param other: The int or BitVec to compare to this BitVecFunc
        :return: The resulting Bool
        """
        if not isinstance(other, BitVec):
            other = BitVec(z3.BitVecVal(other, self.size()))
        return Or(self > other, self == other)
Esempio n. 10
0
def _arithmetic_helper(a: BitVec, b: BitVec, operation: Callable) -> BitVec:
    raw = operation(a.raw, b.raw)
    union = a.annotations.union(b.annotations)

    if isinstance(a, BitVecFunc):
        return _func_arithmetic_helper(a, b, operation)
    elif isinstance(b, BitVecFunc):
        return _func_arithmetic_helper(b, a, operation)

    return BitVec(raw, annotations=union)
Esempio n. 11
0
    def __ne__(self, other: Union[int, "BitVec"]) -> Bool:  # type: ignore
        """Create an inequality expression.

        :param other: The int or BitVec to compare to this BitVecFunc
        :return: The resulting Bool
        """
        if not isinstance(other, BitVec):
            other = BitVec(z3.BitVecVal(other, self.size()))
        return _comparison_helper(
            self, other, operator.ne, default_value=True, inputs_equal=False
        )
Esempio n. 12
0
    def __gt__(self, other: Union[int, "BitVec"]) -> Bool:
        """Create a signed greater than expression.

        :param other: The int or BitVec to compare to this BitVecFunc
        :return: The resulting Bool
        """
        if not isinstance(other, BitVec):
            other = BitVec(z3.BitVecVal(other, self.size()))
        return _comparison_helper(
            self, other, operator.gt, default_value=False, inputs_equal=False
        )
Esempio n. 13
0
def Extract(high: int, low: int, bv: BitVec) -> BitVec:
    """Create an extract expression.

    :param high:
    :param low:
    :param bv:
    :return:
    """
    raw = z3.Extract(high, low, bv.raw)
    if isinstance(bv, BitVecFunc):
        input_string = ""
        # Is there a better value to set func_name and input to in this case?
        return BitVecFunc(
            raw=raw,
            func_name="Hybrid",
            input_=BitVec(z3.BitVec(input_string, 256),
                          annotations=bv.annotations),
            nested_functions=bv.nested_functions + [bv],
        )

    return BitVec(raw, annotations=bv.annotations)
Esempio n. 14
0
def If(a: Union[Bool, bool], b: Union[BitVec, int], c: Union[BitVec,
                                                             int]) -> BitVec:
    """Create an if-then-else expression.

    :param a:
    :param b:
    :param c:
    :return:
    """
    # TODO: Handle BitVecFunc

    if not isinstance(a, Bool):
        a = Bool(z3.BoolVal(a))
    if not isinstance(b, BitVec):
        b = BitVec(z3.BitVecVal(b, 256))
    if not isinstance(c, BitVec):
        c = BitVec(z3.BitVecVal(c, 256))
    union = a.annotations.union(b.annotations).union(c.annotations)

    bvf = []  # type: List[BitVecFunc]
    if isinstance(a, BitVecFunc):
        bvf += [a]
    if isinstance(b, BitVecFunc):
        bvf += [b]
    if isinstance(c, BitVecFunc):
        bvf += [c]
    if bvf:
        raw = z3.If(a.raw, b.raw, c.raw)
        nested_functions = [
            nf for func in bvf for nf in func.nested_functions
        ] + bvf
        return BitVecFunc(raw,
                          func_name="Hybrid",
                          nested_functions=nested_functions)

    return BitVec(z3.If(a.raw, b.raw, c.raw), union)
Esempio n. 15
0
def Sum(*args: BitVec) -> BitVec:
    """Create sum expression.

    :return:
    """
    raw = z3.Sum([a.raw for a in args])
    annotations = set()  # type: Annotations
    bitvecfuncs = []

    for bv in args:
        annotations = annotations.union(bv.annotations)
        if isinstance(bv, BitVecFunc):
            bitvecfuncs.append(bv)

    nested_functions = [
        nf for func in bitvecfuncs for nf in func.nested_functions
    ] + bitvecfuncs

    if len(bitvecfuncs) >= 2:
        return BitVecFunc(
            raw=raw,
            func_name="Hybrid",
            input_=None,
            annotations=annotations,
            nested_functions=nested_functions,
        )
    elif len(bitvecfuncs) == 1:
        return BitVecFunc(
            raw=raw,
            func_name=bitvecfuncs[0].func_name,
            input_=bitvecfuncs[0].input_,
            annotations=annotations,
            nested_functions=nested_functions,
        )

    return BitVec(raw, annotations)
Esempio n. 16
0
 def BitVecSym(name: str,
               size: int,
               annotations: Annotations = None) -> BitVec:
     """Creates a new bit vector with a symbolic value."""
     raw = z3.BitVec(name, size)
     return BitVec(raw, annotations)
Esempio n. 17
0
 def BitVecVal(value: int,
               size: int,
               annotations: Annotations = None) -> BitVec:
     """Creates a new bit vector with a concrete value."""
     raw = z3.BitVecVal(value, size)
     return BitVec(raw, annotations)
Esempio n. 18
0
def _comparison_helper(
    a: "BitVecFunc",
    b: Union[BitVec, int],
    operation: Callable,
    default_value: bool,
    inputs_equal: bool,
) -> Bool:
    """
    Helper function for comparison operations with BitVecFuncs.

    :param a: The BitVecFunc to compare.
    :param b: A BitVec or int to compare to.
    :param operation: The comparison operation to perform.
    :return: The resulting Bool
    """
    # Is there some hack for gt/lt comparisons?
    if isinstance(b, int):
        b = BitVec(z3.BitVecVal(b, a.size()))
    union = a.annotations.union(b.annotations)

    if not a.symbolic and not b.symbolic:
        if operation == z3.UGT:
            operation = operator.gt
        if operation == z3.ULT:
            operation = operator.lt
        return Bool(z3.BoolVal(operation(a.value, b.value)), annotations=union)
    if (
        not isinstance(b, BitVecFunc)
        or not a.func_name
        or not a.input_
        or not a.func_name == b.func_name
        or str(operation) not in ("<built-in function eq>", "<built-in function ne>")
    ):
        return Bool(z3.BoolVal(default_value), annotations=union)

    condition = True
    for a_nest, b_nest in product(a.nested_functions, b.nested_functions):
        if a_nest.func_name != b_nest.func_name:
            continue
        if a_nest.func_name == "Hybrid":
            continue
        # a.input (eq/neq) b.input ==> a == b
        if inputs_equal:
            condition = z3.And(
                condition,
                z3.Or(
                    z3.Not((a_nest.input_ == b_nest.input_).raw),
                    (a_nest.raw == b_nest.raw),
                ),
                z3.Or(
                    z3.Not((a_nest.raw == b_nest.raw)),
                    (a_nest.input_ == b_nest.input_).raw,
                ),
            )
        else:
            condition = z3.And(
                condition,
                z3.Or(
                    z3.Not((a_nest.input_ != b_nest.input_).raw),
                    (a_nest.raw == b_nest.raw),
                ),
                z3.Or(
                    z3.Not((a_nest.raw == b_nest.raw)),
                    (a_nest.input_ != b_nest.input_).raw,
                ),
            )

    return And(
        Bool(cast(z3.BoolRef, operation(a.raw, b.raw)), annotations=union),
        Bool(condition) if b.nested_functions else Bool(True),
        a.input_ == b.input_ if inputs_equal else a.input_ != b.input_,
    )