Ejemplo n.º 1
0
 def __init__(self, view: BinaryView):
     self.view = view
     super().__init__()
     addr_size = self.view.address_size
     self.mem = {
         1: Array("mem1", BitVecSort(addr_size * 8), BitVecSort(8)),
         2: Array('mem2', BitVecSort(addr_size * 8), BitVecSort(16)),
         4: Array('mem4', BitVecSort(addr_size * 8), BitVecSort(32)),
         8: Array('mem8', BitVecSort(addr_size * 8), BitVecSort(64)),
         16: Array('mem16', BitVecSort(addr_size * 8), BitVecSort(128))
     }
Ejemplo n.º 2
0
    def __init__(self, num, addr, raw):
        """
        (raw) is the raw string of the instructions of the gadget 
        """
        # irsb is an array of BARF instructions
        # ins is an array of Assembly instructions
        try:
            (irsb, ins) = Analysis.getIR(raw, addr)
        except Exception as e:
            raise GadgetException(str(e.msg))

        # Some strings representations
        self.asmStr = "; ".join(str(i) for i in ins)
        self.hexStr = "\\x" + "\\x".join("{:02x}".format(ord(c)) for c in raw)
        # Initializing the memory in Z3 for this gadget
        memorySMT = Array("MEM", BitVecSort(REGSIZE.size), BitVecSort(8))
        self.addr = addr  # int
        # Get the string for the address, depends on the architecture size
        self.addrStr = '0x' + format(
            addr, '0' + str(Analysis.ArchInfo.bits / 4) + 'x')
        self.graph = Graph()
        self.regCount = {
        }  # Keys are integers, values are integers. regCount[2] = 0 <=> R2_0 have appeared but R2_1 not yet
        self.spInc = None  # How much have Stack Pointer been incremented by
        self.num = num  # Identifier or the gadget
        self.normalRet = None  # True iff the gadgets ends up by a normal ret; instruction
        self.nbInstr = 0  # Number of REIL instructions of this gadget
        self.dep = None
        self.valuesTable = {}  # Used dinamically when building graph
        # Building graph and computing the dependencies
        self.buildGraph(irsb)
        self.getDependencies()
Ejemplo n.º 3
0
    def __init__(self, tx_id, starting_calldata=None):
        """
        Constructor for Calldata
        :param tx_id: unique value representing the transaction the calldata is for
        :param starting_calldata: byte array representing the concrete calldata of a transaction
        """
        self.tx_id = tx_id
        if starting_calldata:
            self._calldata = []
            self.calldatasize = BitVecVal(len(starting_calldata), 256)
            self.concrete = True
        else:
            self._calldata = Array("{}_calldata".format(self.tx_id),
                                   BitVecSort(256), BitVecSort(8))
            self.calldatasize = BitVec("{}_calldatasize".format(self.tx_id),
                                       256)
            self.concrete = False

        self.starting_calldata = starting_calldata or []
Ejemplo n.º 4
0
def prove_adversarial_property_z3(a_pace, b_pace, min_a, max_b, n_iterations):
    '''
    Using z3 to probe the formula
    checking ReLu(sk * w) <= ylim[1] while sk <= sklim
    :param invariant_property: maximum value for sk
    :param weight: the weight between sk and the output
    :param ylim: max output
    :return: True if for every sk <= sklim implies that ReLu(sk * w) <= ylim
    '''
    from math import log2, ceil
    num_bytes = ceil(log2(n_iterations)) + 1
    print('n_iterations', n_iterations, '\nnum_bytes', num_bytes)
    assert n_iterations <= 2**num_bytes  # if the bit vec is 32 z3 takes to long
    a_invariants = Array('a_invariants', BitVecSort(num_bytes), RealSort())
    b_invariants = Array('b_invariants', BitVecSort(num_bytes), RealSort())
    i = BitVec('i', num_bytes)
    n = BitVec('n', num_bytes)

    s = Solver()
    s.add(a_invariants[0] == min_a)
    s.add(b_invariants[0] == max_b)
    s.add(n == BitVecVal(n_iterations, num_bytes))

    # The invariant
    s.add(ForAll(i, a_invariants[i] >= a_invariants[0] + BV2Int(i) * a_pace))
    s.add(ForAll(i, b_invariants[i] <= b_invariants[0] + BV2Int(i) * b_pace))
    # s.add(ForAll(i, a_invariants[i] >= a_invariants[0] + BV2Int(i * BitVecVal(a_pace, num_bytes))))
    # s.add(ForAll(i, b_invariants[i] <= b_invariants[0] + BV2Int(i * BitVecVal(b_pace, num_bytes))))

    # NOT the property to prove
    s.add(a_invariants[n] < b_invariants[n])

    t = s.check()
    if t == sat:
        print("z3 result:", s.model())
        return False
    else:
        print('proved adversarial property using z3')
        return True
Ejemplo n.º 5
0
    def __init__(self, tx_id, starting_calldata=None):
        """
        Constructor for Calldata
        :param tx_id: unique value representing the transaction the calldata is for
        :param starting_calldata: byte array representing the concrete calldata of a transaction
        """
        self.tx_id = tx_id
        if starting_calldata is not None:
            self._calldata = []
            self.calldatasize = BitVecVal(len(starting_calldata), 256)
            self.concrete = True
        else:
            self._calldata = Array("{}_calldata".format(self.tx_id),
                                   BitVecSort(256), BitVecSort(8))
            self.calldatasize = BitVec("{}_calldatasize".format(self.tx_id),
                                       256)
            self.concrete = False

        if self.concrete:
            for calldata_byte in starting_calldata:
                if type(calldata_byte) == int:
                    self._calldata.append(BitVecVal(calldata_byte, 8))
                else:
                    self._calldata.append(calldata_byte)
Ejemplo n.º 6
0
    def __init__(self, var, address_size):
        super(ByteSwapModeler, self).__init__()

        if (not isinstance(var, MediumLevelILInstruction)
                or var.operation != MediumLevelILOperation.MLIL_VAR_SSA):
            raise TypeError('var must be an MLIL_VAR_SSA operation')

        self.address_size = address_size
        self._memory = Array('Memory', BitVecSort(address_size * 8),
                             BitVecSort(8))
        self.solver = Solver()
        self.visited = set()
        self.to_visit = list()
        self.byte_values = dict()
        self.byte_vars = set()
        self.var = var
        self.function = var.function
Ejemplo n.º 7
0
def main():
    dim = int(input("size of the array: "))

    i = [Int(f"i_{x}") for x in range(dim + 1)]
    j = [Int(f"j_{x}") for x in range(dim + 1)]
    A = [Array(f"A_{x}", IntSort(), IntSort()) for x in range(dim + 1)]
    tmp = [Int(f"tmp_{x}") for x in range(dim)]

    s = Solver()

    init_condition = init(i[0], j[0])
    s.add(init_condition)

    tran_condition = mk_tran_condition(A, i, j, tmp, dim)
    s.add(And(*tran_condition))

    values = [Int(f"n_{x}") for x in range(dim)]
    init_check_condition = check(values, A[-1], dim)
    s.add(And(*init_check_condition))

    post_condition = mk_post_condition(values)

    print("Bubble sort")
    print("---------------------")

    s.push()
    s.add(Not(post_condition))

    print("Testing the validity of the algorithm; `valid expected`:")

    if s.check() == sat:
        print(f"counterexample:\n{s.model()}")
    else:
        print("valid")

    print("---------------------")

    s.pop()

    s.add(post_condition)
    print("Getting a model...")
    print("Model:")

    if s.check() == sat:
        print(s.model())
Ejemplo n.º 8
0
def make_load(src, size):
    mem = Array('mem', BitVecSort(32), BitVecSort(8))

    load_bytes = [mem[src + i] for i in range(0, size)]

    return Concat(*load_bytes)
Ejemplo n.º 9
0
 def env_variable(self, type, expr, instance, name):
     return Array(self.env_variable_name(type, expr, instance, name),
                  BitVecSort(32), BitVecSort(8))
Ejemplo n.º 10
0
    for e in range(dim):
        yield variables[e] == Select(Ar, e)


def mk_post_condition(values):
    condition = []
    for v1, v2 in zip(values, values[1:]):
        condition.append(v1 <= v2)
    return And(*condition)


dim = int(input("size of the array: "))

i = [Int(f"i_{x}") for x in range(dim + 1)]
j = [Int(f"j_{x}") for x in range(dim + 1)]
A = [Array(f"A_{x}", IntSort(), IntSort()) for x in range(dim + 1)]
tmp = [Int(f"tmp_{x}") for x in range(dim)]

s = Solver()

init_condition = init(i[0], j[0])
s.add(init_condition)

tran_condition = mk_tran_condition(A, i, j, tmp, dim)
s.add(And(*tran_condition))

values = [Int(f"n_{x}") for x in range(dim)]
init_check_condition = check(values, A[-1], dim)
s.add(And(*init_check_condition))

post_condition = mk_post_condition(values)
Ejemplo n.º 11
0
    def __init__(
        self,
        problem,
        debug: Optional[bool] = False,
        max_time: Optional[int] = 10,
        parallel: Optional[bool] = False,
        random_values: Optional[bool] = False,
        logics: Optional[str] = None,
        verbosity: Optional[int] = 0,
    ):
        """Scheduling Solver

        debug: True or False, False by default
        max_time: time in seconds, 60 by default
        parallel: True to enable mutlthreading, False by default
        """
        self.problem = problem
        self.problem_context = problem.context
        self.debug = debug
        # objectives list
        self.objective = None  # the list of all objectives defined in this problem
        self.current_solution = None  # no solution until the problem is solved

        # set_option('smt.arith.auto_config_simplex', True)
        if debug:
            set_option("verbose", 2)
        else:
            set_option("verbose", verbosity)

        if random_values:
            set_option("sat.random_seed", random.randint(1, 1e3))
            set_option("smt.random_seed", random.randint(1, 1e3))
            set_option("smt.arith.random_initial_value", True)
        else:
            set_option("sat.random_seed", 0)
            set_option("smt.random_seed", 0)
            set_option("smt.arith.random_initial_value", False)

        # set timeout
        self.max_time = max_time  # in seconds
        set_option("timeout", int(self.max_time * 1000))  # in milliseconds

        # create the solver
        print("Solver type:\n===========")

        # check if the problem is an optimization problem
        self.is_not_optimization_problem = len(
            self.problem_context.objectives) == 0
        self.is_optimization_problem = len(self.problem_context.objectives) > 0
        self.is_multi_objective_optimization_problem = (len(
            self.problem_context.objectives) > 1)
        # the Optimize() solver is used only in the case of a mutli-optimization
        # problem. This enables to choose the priority method.
        # in the case of a single objective optimization, the Optimize() solver
        # apperas to be less robust than the basic Solver(). The
        # incremental solver is then used.

        # see this url for a documentation about logics
        # http://smtlib.cs.uiowa.edu/logics.shtml
        if logics is None:
            self._solver = Solver()
            print("\t-> Standard SAT/SMT solver")
        else:
            self._solver = SolverFor(logics)
            print("\t-> SMT solver using logics", logics)
        if debug:
            set_option(unsat_core=True)

        if parallel:
            set_option("parallel.enable", True)  # enable parallel computation

        # add all tasks assertions to the solver
        for task in self.problem_context.tasks:
            self.add_constraint(task.get_assertions())
            self.add_constraint(task.end <= self.problem.horizon)

        # then process tasks constraints
        for constraint in self.problem_context.constraints:
            self.add_constraint(constraint)

        # process resources requirements
        for ress in self.problem_context.resources:
            self.add_constraint(ress.get_assertions())

        # process resource intervals
        for ress in self.problem_context.resources:
            busy_intervals = ress.get_busy_intervals()
            nb_intervals = len(busy_intervals)
            for i in range(nb_intervals):
                start_task_i, end_task_i = busy_intervals[i]
                for k in range(i + 1, nb_intervals):
                    start_task_k, end_task_k = busy_intervals[k]
                    self.add_constraint(
                        Or(start_task_k >= end_task_i,
                           start_task_i >= end_task_k))

        # process indicators
        for indic in self.problem_context.indicators:
            self.add_constraint(indic.get_assertions())

        # work amounts
        # for each task, compute the total work for all required resources"""
        for task in self.problem_context.tasks:
            if task.work_amount > 0.0:
                work_total_for_all_resources = []
                for required_resource in task.required_resources:
                    # work contribution for the resource
                    interv_low, interv_up = required_resource.busy_intervals[
                        task]
                    work_contribution = required_resource.productivity * (
                        interv_up - interv_low)
                    work_total_for_all_resources.append(work_contribution)
                self.add_constraint(
                    Sum(work_total_for_all_resources) >= task.work_amount)

        # process buffers
        for buffer in self.problem_context.buffers:
            #
            # create an array that stores the mapping between start times and
            # quantities. For example, if a start T1 starts at 2 and consumes
            # 8, and T3 ends at 6 and consumes 5 then the mapping array
            # will look like : A[2]=8 and A[6]=-5
            # SO far, no way to have the same start time at different inst
            buffer_mapping = Array("Buffer_%s_mapping" % buffer.name,
                                   IntSort(), IntSort())
            for t in buffer.unloading_tasks:
                self.add_constraint(buffer_mapping == Store(
                    buffer_mapping, t.start, -buffer.unloading_tasks[t]))
            for t in buffer.loading_tasks:
                self.add_constraint(buffer_mapping == Store(
                    buffer_mapping, t.end, +buffer.loading_tasks[t]))
            # sort consume/feed times in asc order
            tasks_start_unload = [t.start for t in buffer.unloading_tasks]
            tasks_end_load = [t.end for t in buffer.loading_tasks]

            sorted_times, sort_assertions = sort_no_duplicates(
                tasks_start_unload + tasks_end_load)
            self.add_constraint(sort_assertions)
            # create as many buffer state changes as sorted_times
            buffer.state_changes_time = [
                Int("%s_sc_time_%i" % (buffer.name, k))
                for k in range(len(sorted_times))
            ]

            # add the constraints that give the buffer state change times
            for st, bfst in zip(sorted_times, buffer.state_changes_time):
                self.add_constraint(st == bfst)

            # compute the different buffer states according to state changes
            buffer.buffer_states = [
                Int("%s_state_%i" % (buffer.name, k))
                for k in range(len(buffer.state_changes_time) + 1)
            ]
            # add constraints for buffer states
            # the first buffer state is equal to the buffer initial level
            if buffer.initial_state is not None:
                self.add_constraint(
                    buffer.buffer_states[0] == buffer.initial_state)
            if buffer.final_state is not None:
                self.add_constraint(
                    buffer.buffer_states[-1] == buffer.final_state)
            if buffer.lower_bound is not None:
                for st in buffer.buffer_states:
                    self.add_constraint(st >= buffer.lower_bound)
            if buffer.upper_bound is not None:
                for st in buffer.buffer_states:
                    self.add_constraint(st <= buffer.upper_bound)
            # and, for the other, the buffer state i+1 is the buffer state i +/- the buffer change
            for i in range(len(buffer.buffer_states) - 1):
                self.add_constraint(
                    buffer.buffer_states[i + 1] == buffer.buffer_states[i] +
                    buffer_mapping[buffer.state_changes_time[i]])

        # optimization
        if self.is_optimization_problem:
            self.create_objective()
Ejemplo n.º 12
0
 def output_variable(type, name, instance):
     s = '{}!output!{}!{}'.format(type, name, instance)
     if type == 'long':
         return Array(s, BitVecSort(32), BitVecSort(8))
     else:
         return Array(s, BitVecSort(32), BitVecSort(8))
Ejemplo n.º 13
0
 def env_variable(expr, instance, name):
     pattern = 'int!choice!{}!{}!{}!{}!{}!env!{}'
     s = pattern.format(expr[0], expr[1], expr[2], expr[3],
                        instance, name)
     return Array(s, BitVecSort(32), BitVecSort(8))
Ejemplo n.º 14
0
 def original_variable(self, type, expr, instance):
     return Array(self.original_variable_name(type, expr, instance),
                  BitVecSort(32), BitVecSort(8))
Ejemplo n.º 15
0
class Calldata:
    """
    Calldata class representing the calldata of a transaction
    """
    def __init__(self, tx_id, starting_calldata=None):
        """
        Constructor for Calldata
        :param tx_id: unique value representing the transaction the calldata is for
        :param starting_calldata: byte array representing the concrete calldata of a transaction
        """
        self.tx_id = tx_id
        if starting_calldata is not None:
            self._calldata = []
            self.calldatasize = BitVecVal(len(starting_calldata), 256)
            self.concrete = True
        else:
            self._calldata = Array("{}_calldata".format(self.tx_id),
                                   BitVecSort(256), BitVecSort(8))
            self.calldatasize = BitVec("{}_calldatasize".format(self.tx_id),
                                       256)
            self.concrete = False

        if self.concrete:
            for calldata_byte in starting_calldata:
                if type(calldata_byte) == int:
                    self._calldata.append(BitVecVal(calldata_byte, 8))
                else:
                    self._calldata.append(calldata_byte)

    def concretized(self, model):
        result = []
        for i in range(
                get_concrete_int(
                    model.eval(self.calldatasize, model_completion=True))):
            result.append(
                get_concrete_int(
                    model.eval(self._calldata[i], model_completion=True)))

        return result

    def get_word_at(self, index: int):
        return self[index:index + 32]

    def __getitem__(self, item: Union[int, slice]) -> Any:
        if isinstance(item, slice):
            start, step, stop = item.start, item.step, item.stop
            try:
                if start is None:
                    start = 0
                if step is None:
                    step = 1
                if stop is None:
                    stop = self.calldatasize
                current_index = (start if isinstance(start, BitVecRef) else
                                 BitVecVal(start, 256))
                dataparts = []
                while simplify(current_index != stop):
                    dataparts.append(self[current_index])
                    current_index = simplify(current_index + step)
            except Z3Exception:
                raise IndexError("Invalid Calldata Slice")

            values, constraints = zip(*dataparts)
            result_constraints = []
            for c in constraints:
                result_constraints.extend(c)
            return simplify(Concat(values)), result_constraints

        if self.concrete:
            try:
                return self._calldata[get_concrete_int(item)], ()
            except IndexError:
                return BitVecVal(0, 8), ()
        else:
            constraints = [
                Implies(self._calldata[item] != 0, UGT(self.calldatasize,
                                                       item))
            ]

            return self._calldata[item], constraints
Ejemplo n.º 16
0
class Calldata:
    """
    Calldata class representing the calldata of a transaction
    """
    def __init__(self, tx_id, starting_calldata=None):
        """
        Constructor for Calldata
        :param tx_id: unique value representing the transaction the calldata is for
        :param starting_calldata: byte array representing the concrete calldata of a transaction
        """
        self.tx_id = tx_id
        if starting_calldata:
            self._calldata = []
            self.calldatasize = BitVecVal(len(starting_calldata), 256)
            self.concrete = True
        else:
            self._calldata = Array("{}_calldata".format(self.tx_id),
                                   BitVecSort(256), BitVecSort(8))
            self.calldatasize = BitVec("{}_calldatasize".format(self.tx_id),
                                       256)
            self.concrete = False

        self.starting_calldata = starting_calldata or []

    @property
    def constraints(self):
        constraints = []

        if self.concrete:
            for calldata_byte in self.starting_calldata:
                if type(calldata_byte) == int:
                    self._calldata.append(BitVecVal(calldata_byte, 8))
                else:
                    self._calldata.append(calldata_byte)
            constraints.append(
                self.calldatasize == len(self.starting_calldata))
        else:
            x = BitVec("x", 256)
            constraints.append(
                ForAll(x, Implies(self[x] != 0, UGT(self.calldatasize, x))))

        return constraints

    def concretized(self, model):
        result = []
        for i in range(
                get_concrete_int(
                    model.eval(self.calldatasize, model_completion=True))):
            result.append(
                get_concrete_int(model.eval(self[i], model_completion=True)))

        return result

    def get_word_at(self, index: int):
        return self[index:index + 32]

    def __getitem__(self, item):
        if isinstance(item, slice):
            try:
                current_index = (item.start if isinstance(
                    item.start, BitVecRef) else BitVecVal(item.start, 256))
                dataparts = []
                while simplify(current_index != item.stop):
                    dataparts.append(self[current_index])
                    current_index = simplify(current_index + 1)
            except Z3Exception:
                raise IndexError("Invalid Calldata Slice")

            return simplify(Concat(dataparts))

        if self.concrete:
            try:
                return self._calldata[get_concrete_int(item)]
            except IndexError:
                return BitVecVal(0, 8)
        else:
            return self._calldata[item]
Ejemplo n.º 17
0
 def output_variable(self, type, name, instance):
     return Array(self.output_variable_name(type, name, instance),
                  BitVecSort(32), BitVecSort(8))
Ejemplo n.º 18
0
 def original_variable(type, expr, instance):
     pattern = '{}!choice!{}!{}!{}!{}!{}!original'
     s = pattern.format(type, expr[0], expr[1], expr[2], expr[3],
                        instance)
     return Array(s, BitVecSort(32), BitVecSort(8))
Ejemplo n.º 19
0
 def angelic_variable(self, type, expr, instance):
     return Array(self.angelic_variable_name(type, expr, instance),
                  BitVecSort(32), BitVecSort(8))