Пример #1
0
 def __getitem__(self, item):
     try:
         return self._storage[item]
     except KeyError:
         if self.address and int(self.address[2:], 16) != 0 and self.dynld:
             try:
                 self._storage[item] = int(self.dynld.read_storage(contract_address=self.address, index=int(item)), 16)
                 return self._storage[item]
             except ValueError:
                 pass
     if self.concrete:
         return 0
     self._storage[item] = BitVec("storage_" + str(item), 256)
     return self._storage[item]
Пример #2
0
    def sha3_(self, global_state):
        state = global_state.mstate
        environment = global_state.environment
        op0, op1 = state.stack.pop(), state.stack.pop()

        try:
            index, length = util.get_concrete_int(op0), util.get_concrete_int(
                op1)
        # FIXME: broad exception catch
        except:
            # Can't access symbolic memory offsets
            state.stack.append(BitVec("KECCAC_mem_" + str(op0) + ")", 256))
            return [global_state]

        try:
            data = b''

            for i in range(index, index + length):
                data += util.get_concrete_int(state.memory[i]).to_bytes(
                    1, byteorder='big')
                i += 1
            # FIXME: broad exception catch
        except:

            svar = str(state.memory[index])

            svar = svar.replace(" ", "_")

            state.stack.append(BitVec("keccac_" + svar, 256))
            return [global_state]

        keccac = utils.sha3(utils.bytearray_to_bytestr(data))
        logging.debug("Computed SHA3 Hash: " + str(binascii.hexlify(keccac)))

        state.stack.append(
            BitVecVal(util.concrete_int_from_bytes(keccac, 0), 256))
        return [global_state]
Пример #3
0
    def extcodesize_(self, global_state):
        state = global_state.mstate
        addr = state.stack.pop()
        environment = global_state.environment
        try:
            addr = hex(helper.get_concrete_int(addr))
        except AttributeError:
            logging.info("unsupported symbolic address for EXTCODESIZE")
            state.stack.append(BitVec("extcodesize_" + str(addr), 256))
            return [global_state]

        try:
            code = self.dynamic_loader.dynld(environment.active_account.address, addr)
        except Exception as e:
            logging.info("error accessing contract storage due to: " + str(e))
            state.stack.append(BitVec("extcodesize_" + str(addr), 256))
            return [global_state]

        if code is None:
            state.stack.append(0)
        else:
            state.stack.append(len(code.bytecode) // 2)

        return [global_state]
Пример #4
0
    def __init__(
        self,
        world_state,
        caller,
        identifier=None,
        callee_account=None,
        code=None,
        call_data=(),
        gas_price=None,
        call_value=None,
        origin=None,
        call_data_type=None,
    ):
        assert isinstance(world_state, WorldState)
        self.id = identifier or get_next_transaction_id()
        self.world_state = world_state
        # TODO: set correct balance for new account
        self.callee_account = callee_account if callee_account else world_state.create_account(
            0, concrete_storage=True)

        self.caller = caller

        self.gas_price = BitVec("gasprice{}".format(identifier),
                                256) if gas_price is None else gas_price
        self.call_value = BitVec("callvalue{}".format(identifier),
                                 256) if call_value is None else call_value
        self.origin = BitVec("origin{}".format(identifier),
                             256) if origin is None else origin
        self.call_data_type = BitVec(
            "call_data_type{}".format(identifier),
            256) if call_data_type is None else call_data_type

        self.call_data = call_data
        self.origin = origin
        self.code = code
        self.return_data = None
Пример #5
0
    def exp_(self, global_state):
        state = global_state.mstate
        # we only implement 2 ** x
        base, exponent = util.pop_bitvec(state), util.pop_bitvec(state)

        if (type(base) != BitVecNumRef) or (type(exponent) != BitVecNumRef):
            state.stack.append(BitVec("(" + str(simplify(base)) + ")^(" + str(simplify(exponent)) + ")", 256))
        elif base.as_long() == 2:
            if exponent.as_long() == 0:
                state.stack.append(BitVecVal(1, 256))
            else:
                state.stack.append(base << (exponent - 1))
        else:
            state.stack.append(base)
        return [global_state]
Пример #6
0
    def byte_(self, global_state):
        mstate = global_state.mstate
        op0, op1 = mstate.stack.pop(), mstate.stack.pop()

        try:
            index = util.get_concrete_int(op0)
            offset = (31 - index) * 8
            result = Concat(BitVecVal(0, 248), Extract(offset + 7, offset,
                                                       op1))
        except AttributeError:
            logging.debug("BYTE: Unsupported symbolic byte offset")
            result = BitVec(str(simplify(op1)) + "_" + str(simplify(op0)), 256)

        mstate.stack.append(simplify(result))
        return [global_state]
Пример #7
0
    def set_function_id(self, fid: BitVecRef = None):
        if isinstance(fid, str) and len(fid) == 8:
            fid = BitVecVal(int(fid, 16), 32)
        elif isinstance(fid, int):
            fid = BitVecVal(fid, 32)
        elif isinstance(fid, BitVecRef) and fid.size() == 32:
            pass
        elif fid is None:
            fid = BitVec('function_id', 32)
        else:
            raise SettingError('illegal function id given')

        for i in range(4):
            fragment = Extract(i * 8 + 7, i * 8, fid)
            self.mstore8(3 - i, fragment)
Пример #8
0
def get_constr_glbstate(contract, address):

    mstate = MachineState(gas=10000000)

    minimal_const_byte_len = get_minimal_constructor_param_encoding_len(
        abi_json_to_abi(contract.abi))

    # better would be to append symbolic params to the bytecode such that the codecopy instruction that copies the
    # params into memory takes care of placing them onto the memory with the respective size.
    for i in range(int(minimal_const_byte_len / 32)):
        mstate.mem_extend(128 + 32 * i, 32)
        mstate.memory.insert(
            128 + 32 * i,
            BitVec('calldata_' + contract.name + '_' + str(i * 32), 256))

    # Todo Replace pure placement of enough symbolic 32 Byte-words with placement of symbolic variables that contain
    # the name of the solidity variables

    accounts = {
        address:
        Account(address, contract.disassembly, contract_name=contract.name)
    }

    environment = Environment(
        accounts[address],
        BitVec("caller", 256),
        [],
        BitVec("gasprice", 256),
        BitVec("callvalue", 256),
        BitVec("origin", 256),
        calldata_type=CalldataType.SYMBOLIC,
    )

    # Todo find source for account info, maybe the std statespace?

    return GlobalState(accounts, environment, mstate)
Пример #9
0
 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
Пример #10
0
def execute_message_call(laser_evm,
                         callee_address: str,
                         priority=None) -> None:
    """ Executes a message call transaction from all open states """
    # TODO: Resolve circular import between .transaction and ..svm to import LaserEVM here
    # TODO: if the function of openstate.node.funcname is not in priority list, dont add it
    # TODO: This is for deleting repeated variables read
    # copy the open states from last iteration to this iteration
    # The working list is always empty when an iteration is done
    open_states = laser_evm.open_states[:]
    del laser_evm.open_states[:]

    for open_world_state in open_states:
        if open_world_state[callee_address].deleted:
            debug("Can not execute dead contract, skipping.")
            continue

        next_transaction_id = get_next_transaction_id()
        transaction = MessageCallTransaction(
            world_state=open_world_state,
            identifier=next_transaction_id,
            gas_price=BitVec("gas_price{}".format(next_transaction_id), 256),
            gas_limit=8000000,  # block gas limit
            origin=BitVec("origin{}".format(next_transaction_id), 256),
            caller=BitVecVal(ATTACKER_ADDRESS, 256),
            callee_account=open_world_state[callee_address],
            call_data=SymbolicCalldata(next_transaction_id),
            call_data_type=CalldataType.SYMBOLIC,
            call_value=BitVec("call_value{}".format(next_transaction_id), 256),
        )

        # the open states from last iterations are appended to work list here
        _setup_global_state_for_execution(laser_evm, transaction,
                                          open_world_state.node.function_name)

    laser_evm.exec(priority=None)
Пример #11
0
def execute_contract_creation(laser_evm,
                              contract_initialization_code,
                              contract_name=None):
    """ Executes a contract creation transaction from all open states"""
    open_states = laser_evm.open_states[:]
    del laser_evm.open_states[:]

    new_account = laser_evm.world_state.create_account(0,
                                                       concrete_storage=True,
                                                       dynamic_loader=None)
    if contract_name:
        new_account.contract_name = contract_name

    for open_world_state in open_states:
        transaction = ContractCreationTransaction(
            open_world_state, BitVec("caller", 256), new_account,
            Disassembly(contract_initialization_code), [],
            BitVec("gas_price", 256), BitVec("call_value", 256),
            BitVec("origin", 256), CalldataType.SYMBOLIC)

        _setup_global_state_for_execution(laser_evm, transaction)
    laser_evm.exec(True)

    return new_account
Пример #12
0
    def visit_MLIL_ADDRESS_OF(self, expr):
        if expr.src.name:
            var_name = expr.src.name
        elif (expr.src.source_type ==
              VariableSourceType.StackVariableSourceType):
            var_name = f'var_{abs(expr.src.storage):x}'
        else:
            var_name = expr.function.arch.get_reg_by_index(expr.src.storage)

        log_debug(f'var_name: {repr(var_name)}')
        return BitVec(
            f"&{var_name}",
            (expr.size * 8) if expr.size else
            expr.function.source_function.view.address_size * 8,
        )
Пример #13
0
 def __init__(self,
              world_state,
              callee_account,
              caller,
              call_data=(),
              identifier=None,
              gas_price=None,
              call_value=None,
              origin=None,
              call_data_type=None,
              code=None
              ):
     assert isinstance(world_state, WorldState)
     self.id = identifier or get_next_transaction_id()
     self.world_state = world_state
     self.callee_account = callee_account
     self.caller = caller
     self.call_data = call_data
     self.gas_price = BitVec("gasprice{}".format(identifier), 256) if gas_price is None else gas_price
     self.call_value = BitVec("callvalue{}".format(identifier), 256) if call_value is None else call_value
     self.origin = BitVec("origin{}".format(identifier), 256) if origin is None else origin
     self.call_data_type = BitVec("call_data_type{}".format(identifier), 256) if call_data_type is None else call_data_type
     self.code = code
     self.return_data = None
Пример #14
0
    def generate_input(self, length):
        """
        Generate :length: bytes of symbolic data, add it to this, and return the bytes
        """

        self._resolve_copies()
        length = self._concretize(length)

        new_bytes = []
        for _ in range(length):
            val = BitVec('inp_{}'.format(len(self.data)), 8)
            self.add(val)
            new_bytes.append(val)

        self.grouped_inputs.append(new_bytes)
        return new_bytes
Пример #15
0
    def _load(self, item: Union[int, ExprRef], clean=False) -> Any:
        x = BitVecVal(item, 256) if isinstance(item, int) else item

        symbolic_base_value = If(
            x > self._size,
            BitVecVal(0, 8),
            BitVec("{}_calldata_{}".format(self.tx_id, str(item)), 8),
        )

        return_value = symbolic_base_value
        for r_index, r_value in self._reads:
            return_value = If(r_index == item, r_value, return_value)

        if not clean:
            self._reads.append((item, symbolic_base_value))
        return simplify(return_value)
Пример #16
0
def zeroize_storage_vars(trace):
    """
    Replaces all symbolic variables referencing storage in the constraints and transaction constraints list
    by the value 0.
    :param trace: to be substituted in.
    """
    zeroize_constraints(trace.constraints)
    zeroize_constraints(trace.tran_constraints)
    for slot_idx, slot in trace.storage.items():
        trace.storage[slot_idx].slot = substitute(
            slot.slot, [(BitVec(slot_name, 256), BitVecVal(0, 256))
                        for slot_name in slot.slot_names])
        slot.tran_names = [
            sym_name for sym_name in slot.tran_names
            if sym_name in slot.slot_names
        ]
        slot.slot_names = []
Пример #17
0
def flatten_quantifier(expr):

    boundvariables = []
    quantifiers = []

    es = flatten_and_tree(expr)

    assert (len(filter(is_quant, es)) <= 1)

    for idx, e in enumerate(es):
        negated = False
        if is_not(e):
            e = e.children()[0]
            negated = True
        if is_quant(e):
            while is_quant(e):
                variables = []
                for i in range(e.num_vars()):
                    # variables += [[expr.var_name(i), expr.var_sort(i)]]
                    if str(e.var_sort(i)).startswith('BitVec'):
                        var = BitVec(e.var_name(i), e.var_sort(i).size())
                    else:
                        assert (str(e.var_sort(i)) == ('Bool'))
                        var = Bool(e.var_name(i))

                    variables.append(var)

                    # if var in boundvariables:
                    #     log('ERROR: Currently require all variable names to be unique.')
                    #     exit()

                if e.is_forall():
                    negated = not negated
                if negated:
                    new_quant = 'a'
                else:
                    new_quant = 'e'
                quantifiers += [[new_quant, variables]]
                boundvariables += variables
                e = e.body()
            es[idx] = e
            break
            # only supports the case that at most one of the conjuncts is a quantiifer

    return And(es), boundvariables, quantifiers
Пример #18
0
    def __init__(self, address, code=None, contract_name="unknown", balance=None, concrete_storage=False,
                 dynamic_loader=None):
        """
        Constructor for account
        :param address: Address of the account
        :param code: The contract code of the account
        :param contract_name: The name associated with the account
        :param balance: The balance for the account
        :param concrete_storage: Interpret storage as concrete
        """
        self.nonce = 0
        self.code = code
        self.balance = balance if balance else BitVec("balance", 256)
        self.storage = Storage(concrete_storage, address=address, dynamic_loader=dynamic_loader)

        # Metadata
        self.address = address
        self.contract_name = contract_name
Пример #19
0
    def extract_function_id(self, condition, block_state):
        if self.extracting_fid:
            m = get_model_and_time(condition)
            if m:
                fid = m[BitVec('function_id', 32)]
                # the case contract has only one function
                if fid is None:
                    self.function_ids.add(BitVecVal(0, 32))
                    if 'callable' in block_state:
                        self.callable_function_ids.add(BitVecVal(0, 32))

                else:
                    self.function_ids.add(fid)
                    if 'callable' in block_state:
                        self.callable_function_ids.add(fid)
                    return True

        return False
Пример #20
0
    def sload_(self, global_state):
        state = global_state.mstate
        index = state.stack.pop()
        logging.debug("Storage access at index " + str(index))

        try:
            index = util.get_concrete_int(index)
        except AttributeError:
            index = str(index)

        try:
            data = global_state.environment.active_account.storage[index]
        except KeyError:
            data = BitVec("storage_" + str(index), 256)
            global_state.environment.active_account.storage[index] = data

        state.stack.append(data)
        return [global_state]
Пример #21
0
def get_storage_slot(index, storage):
    """
    Returns the content of a specific storage slo
    :param index:
    :param storage:
    :return:
    """
        try:
            index = get_concrete_int(index)
        except AttributeError:
            index = str(index)

        try:
            data = storage[index]
        except KeyError:
            data = BitVec("storage[" + str(index) + "]", 256)

        return data
Пример #22
0
    def byte_(self, global_state):
        mstate = global_state.mstate
        op0, op1 = mstate.stack.pop(), mstate.stack.pop()
        if not isinstance(op1, ExprRef):
            op1 = BitVecVal(op1, 256)
        try:
            index = util.get_concrete_int(op0)
            offset = (31 - index) * 8
            if offset >= 0:
                result = simplify(Concat(BitVecVal(0, 248), Extract(offset + 7, offset, op1)))
            else:
                result = 0
        except AttributeError:
            logging.debug("BYTE: Unsupported symbolic byte offset")
            result = BitVec(str(simplify(op1)) + "[" + str(simplify(op0)) + "]", 256)

        mstate.stack.append(result)
        return [global_state]
Пример #23
0
def is_shifted_left(reg, n_instr):  # FIX solve if register is load objective
    constraints = []
    for s in range(n_instr):
        constraints.append(
            BitVec(reg + "_" +
                   str(0), x86_model.BS) != BitVec("shl_src_" +
                                                   str(s), x86_model.BS))
        constraints.append(
            BitVec(reg + "_" +
                   str(0), x86_model.BS) != BitVec("shl_dst_" +
                                                   str(s), x86_model.BS))
        constraints.append(
            BitVec(reg + "_" +
                   str(0), x86_model.BS) != BitVec("rcl_src_" +
                                                   str(s), x86_model.BS))
        constraints.append(
            BitVec(reg + "_" +
                   str(0), x86_model.BS) != BitVec("rcl_dst_" +
                                                   str(s), x86_model.BS))
    return constraints
Пример #24
0
def unmodified_during_execution(src, dest, n_instr):
    last_reg = BitVec(dest + "_" + str(n_instr), x86_model.BS)
    constraints = [BitVec(src + "_0", x86_model.BS) != last_reg]
    for s in range(n_instr):
        constraints.append(
            BitVec(dest + "_" +
                   str(s + 1), x86_model.BS) != BitVec("load_" +
                                                       str(s), x86_model.BS))
        constraints.append(
            BitVec(dest + "_" +
                   str(s), x86_model.BS) != BitVec("overwritten_" +
                                                   str(s), x86_model.BS))
    return constraints
Пример #25
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 []
Пример #26
0
    def return_(self, global_state):
        # TODO: memory
        state = global_state.mstate
        offset, length = state.stack.pop(), state.stack.pop()
        try:
            _ = state.memory[util.get_concrete_int(offset):util.get_concrete_int(offset + length)]
        except AttributeError:
            logging.debug("Return with symbolic length or offset. Not supported")

        #TODO: return 1
        return_value = BitVec("retval_" + global_state.environment.active_function_name, 256)

        state.stack.append(return_value)

        if not global_state.call_stack:
            return []

        global_state.mstate.pc = global_state.call_stack.pop()

        return [global_state]
Пример #27
0
    def __init__(self,
                 address,
                 code=None,
                 contract_name="unknown",
                 balance=None):
        """
        Constructor for account
        :param address: Address of the account
        :param code: The contract code of the account
        :param contract_name: The name associated with the account
        :param balance: The balance for the account
        """
        self.nonce = 0
        self.code = code
        self.balance = balance if balance else BitVec("balance", 256)
        self.storage = {}

        # Metadata
        self.address = address
        self.contract_name = contract_name
Пример #28
0
    def callcode_(self, global_state):
        instr = global_state.get_current_instruction()
        environment = global_state.environment

        try:
            callee_address, callee_account, call_data, value, call_data_type, gas, _, _ = get_call_parameters(
                global_state, self.dynamic_loader, True)
        except ValueError as e:
            logging.info(
                "Could not determine required parameters for call, putting fresh symbol on the stack. \n{}"
                .format(e))
            global_state.mstate.stack.append(
                BitVec("retval_" + str(instr['address']), 256))
            return [global_state]

        transaction = MessageCallTransaction(
            global_state.world_state, environment.active_account,
            environment.address, call_data, environment.gasprice, value,
            environment.origin, call_data_type, callee_account.code)
        raise TransactionStartSignal(transaction, self.op_code)
Пример #29
0
    def get_ssa_variable(self, variable: SSAVariable):
        """
        Look up SSA variable by executing the instruction in which it was defined

        :variable: SSAVariable to look up.
        """
        definition_instruction = self.function.mlil.ssa_form.get_ssa_var_definition(
            variable
        )
        result = None
        if definition_instruction and self.depth > 0:
            MLILInstructionExecutor(self.bv, definition_instruction).execute(
                self.next_state()
            )
            result = self.variables[variable]
        else:
            name = repr(variable)
            size = variable.var.type.width * 8
            result = BitVec(name, size)
            self.potential_inputs.append(result)

        self.variables[variable] = result
        return result
Пример #30
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)