Пример #1
0
def execute_message_call(laser_evm, callee_address: str) -> None:
    """Executes a message call transaction from all open states.

    :param laser_evm:
    :param callee_address:
    """
    # TODO: Resolve circular import between .transaction and ..svm to import LaserEVM here
    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:
            log.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=symbol_factory.BitVecSym(
                "gas_price{}".format(next_transaction_id), 256),
            gas_limit=8000000,  # block gas limit
            origin=symbol_factory.BitVecSym(
                "origin{}".format(next_transaction_id), 256),
            caller=symbol_factory.BitVecVal(ATTACKER_ADDRESS, 256),
            callee_account=open_world_state[callee_address],
            call_data=SymbolicCalldata(next_transaction_id),
            call_value=symbol_factory.BitVecSym(
                "call_value{}".format(next_transaction_id), 256),
        )
        _setup_global_state_for_execution(laser_evm, transaction)

    laser_evm.exec()
Пример #2
0
def get_call_data(
    global_state: GlobalState,
    memory_start: Union[int, BitVec],
    memory_size: Union[int, BitVec],
):
    """Gets call_data from the global_state.

    :param global_state: state to look in
    :param memory_start: Start index
    :param memory_size: Size
    :return: Tuple containing: call_data array from memory or empty array if symbolic, type found
    """
    state = global_state.mstate
    transaction_id = "{}_internalcall".format(global_state.current_transaction.id)

    memory_start = cast(
        BitVec,
        (
            symbol_factory.BitVecVal(memory_start, 256)
            if isinstance(memory_start, int)
            else memory_start
        ),
    )
    memory_size = cast(
        BitVec,
        (
            symbol_factory.BitVecVal(memory_size, 256)
            if isinstance(memory_size, int)
            else memory_size
        ),
    )

    uses_entire_calldata = simplify(
        memory_size == global_state.environment.calldata.calldatasize
    )

    if is_true(uses_entire_calldata):
        return global_state.environment.calldata

    try:
        calldata_from_mem = state.memory[
            util.get_concrete_int(memory_start) : util.get_concrete_int(
                memory_start + memory_size
            )
        ]
        return ConcreteCalldata(transaction_id, calldata_from_mem)
    except TypeError:
        log.debug(
            "Unsupported symbolic memory offset %s size %s", memory_start, memory_size
        )
        return SymbolicCalldata(transaction_id)
Пример #3
0
def test_symbolic_calldata_equal_indices():
    calldata = SymbolicCalldata(0)

    index_a = BitVec("index_a", 256)
    index_b = BitVec("index_b", 256)

    # Act
    a = calldata[index_a]
    b = calldata[index_b]

    s = Solver()
    s.append(index_a == index_b)
    s.append(a != b)

    # Assert
    assert unsat == s.check()
Пример #4
0
def test_symbolic_calldata_constrain_index():
    # Arrange
    calldata = SymbolicCalldata(0)
    solver = Solver()

    # Act
    value = calldata[51]

    constraints = [value == 1, calldata.calldatasize == 50]

    solver.add(constraints)

    result = solver.check()

    # Assert
    assert str(result) == "unsat"
Пример #5
0
    def __init__(
        self,
        world_state: WorldState,
        callee_account: Account = None,
        caller: ExprRef = None,
        call_data=None,
        identifier: Optional[str] = None,
        gas_price=None,
        gas_limit=None,
        origin=None,
        code=None,
        call_value=None,
        init_call_data=True,
        static=False,
    ) -> None:
        assert isinstance(world_state, WorldState)
        self.world_state = world_state
        self.id = identifier or get_next_transaction_id()

        self.gas_price = (gas_price if gas_price is not None else
                          symbol_factory.BitVecSym(
                              "gasprice{}".format(identifier), 256))
        self.gas_limit = gas_limit

        self.origin = (origin
                       if origin is not None else symbol_factory.BitVecSym(
                           "origin{}".format(identifier), 256))
        self.code = code

        self.caller = caller
        self.callee_account = callee_account
        if call_data is None and init_call_data:
            self.call_data = SymbolicCalldata(self.id)  # type: BaseCalldata
        else:
            self.call_data = (call_data if isinstance(call_data, BaseCalldata)
                              else ConcreteCalldata(self.id, []))

        self.call_value = (call_value if call_value is not None else
                           symbol_factory.BitVecSym(
                               "callvalue{}".format(identifier), 256))
        self.static = static
        self.return_data = None  # type: str
Пример #6
0
def get_call_data(
    global_state: GlobalState,
    memory_start: Union[int, ExprRef],
    memory_size: Union[int, ExprRef],
):
    """
    Gets call_data from the global_state
    :param global_state: state to look in
    :param memory_start: Start index
    :param memory_size: Size
    :return: Tuple containing: call_data array from memory or empty array if symbolic, type found
    """
    state = global_state.mstate
    transaction_id = "{}_internalcall".format(
        global_state.current_transaction.id)
    try:
        # TODO: This only allows for either fully concrete or fully symbolic calldata.
        # Improve management of memory and callata to support a mix between both types.
        calldata_from_mem = state.memory[util.get_concrete_int(
            memory_start):util.get_concrete_int(memory_start + memory_size)]
        i = 0
        starting_calldata = []
        while i < len(calldata_from_mem):
            elem = calldata_from_mem[i]
            if isinstance(elem, int):
                starting_calldata.append(elem)
                i += 1
            else:  # BitVec
                for j in range(0, elem.size(), 8):
                    starting_calldata.append(Extract(j + 7, j, elem))
                    i += 1

        call_data = ConcreteCalldata(transaction_id, starting_calldata)
        call_data_type = CalldataType.CONCRETE
        logging.debug("Calldata: " + str(call_data))
    except TypeError:
        logging.debug("Unsupported symbolic calldata offset")
        call_data_type = CalldataType.SYMBOLIC
        call_data = SymbolicCalldata("{}_internalcall".format(transaction_id))

    return call_data, call_data_type
Пример #7
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)
Пример #8
0
def heuristic_message_call_helper(laser_evm,
                                  callee_address: str,
                                  priority=None):
    jump = False

    open_states_copy = copy(laser_evm.open_states)

    for open_state in open_states_copy:
        name = open_state.node.function_name

        for priority_list in priority['RAW']:
            if name == priority_list.first.function_name:
                laser_evm.first_order_work_list.append(open_state)
                laser_evm.open_states.remove(open_state)
                jump = True
                break

        if jump:
            jump = False
            continue

        for priority_list in priority['WAR']:
            if name == priority_list.first.function_name:
                laser_evm.second_order_work_list.append(open_state)
                laser_evm.open_states.remove(open_state)
                jump = True
                break

        if jump:
            jump = False
            continue

        for priority_list in priority['WAW']:
            if name == priority_list.first.function_name:
                laser_evm.third_order_work_list.append(open_state)
                laser_evm.open_states.remove(open_state)
                jump = True
                break

        if jump:
            jump = False
            continue

        for priority_list in priority['RAR']:
            if name == priority_list.first.function_name:
                laser_evm.forth_order_work_list.append(open_state)
                laser_evm.open_states.remove(open_state)
                jump = True
                break
        if jump:
            jump = False
            continue

    laser_evm.ranking.append(laser_evm.first_order_work_list)
    laser_evm.ranking.append(laser_evm.second_order_work_list)
    laser_evm.ranking.append(laser_evm.third_order_work_list)
    laser_evm.ranking.append(laser_evm.forth_order_work_list)

    del laser_evm.open_states[:]

    for items in laser_evm.ranking:
        title = items[0]
        list1 = items[1:]

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

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

            # the open states from last iterations are appended to work list here
            _setup_global_state_for_execution(laser_evm, transaction,
                                              last_func_called)
        laser_evm.exec(priority=priority, title=title, laser_obj=laser_evm)

        # Execute the new open states added to the work list in Instruction.jumpi_ function

        if title == 'RAW':
            for gs in laser_evm.second_work_list:
                laser_evm.work_list.append(gs)
            laser_evm.exec(priority=priority, title=title, laser_obj=laser_evm)
        elif title == 'WAR':
            for gs in laser_evm.third_work_list:
                laser_evm.work_list.append(gs)
            laser_evm.exec(priority=priority, title=title, laser_obj=laser_evm)
        elif title == 'WAW':
            for gs in laser_evm.forth_work_list:
                laser_evm.work_list.append(gs)
            laser_evm.exec(priority=priority, title=title, laser_obj=laser_evm)