def execute_message_call(laser_evm, callee_address): """ Executes a message call transaction from all open states """ 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, callee_account=open_world_state[callee_address], caller=BitVec("caller{}".format(next_transaction_id), 256), identifier=next_transaction_id, call_data=Calldata(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, ) _setup_global_state_for_execution(laser_evm, transaction) laser_evm.exec()
def execute_message_call( laser_evm, callee_address, caller_address, origin_address, code, data, gas, gas_price, value, ): """ Executes a message call transaction from all open states """ open_states = laser_evm.open_states[:] del laser_evm.open_states[:] for open_world_state in open_states: next_transaction_id = get_next_transaction_id() transaction = MessageCallTransaction( identifier=next_transaction_id, world_state=open_world_state, callee_account=open_world_state[callee_address], caller=caller_address, call_data=Calldata(next_transaction_id, data), gas_price=gas_price, call_value=value, origin=origin_address, call_data_type=CalldataType.SYMBOLIC, code=Disassembly(code), ) _setup_global_state_for_execution(laser_evm, transaction) laser_evm.exec()
def __init__( self, world_state, callee_account, caller, call_data=None, 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 = (Calldata(self.id, call_data) if not isinstance(call_data, Calldata) else 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
def test_concrete_calldata_uninitialized_index(starting_calldata): # Arrange calldata = Calldata(0, starting_calldata) solver = Solver() # Act value = calldata[100] value2 = calldata.get_word_at(200) solver.add(calldata.constraints) solver.check() model = solver.model() value = model.eval(value) value2 = model.eval(value2) # Assert assert value == 0 assert value2 == 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 = Calldata(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 = Calldata("{}_internalcall".format(transaction_id)) return call_data, call_data_type
def __init__( self, world_state, caller, identifier=None, callee_account=None, code=None, call_data=None, 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 = ( Calldata(self.id, call_data) if not isinstance(call_data, Calldata) else call_data ) self.origin = origin self.code = code self.return_data = None
def test_concrete_calldata_constrain_index(): # Arrange calldata = Calldata(0, [1, 4, 7, 3, 7, 2, 9]) solver = Solver() # Act constraint = calldata[2] == 3 solver.add(calldata.constraints + [constraint]) result = solver.check() # Assert assert str(result) == "unsat"
def test_concrete_calldata_calldatasize(): # Arrange calldata = Calldata(0, [1, 4, 7, 3, 7, 2, 9]) solver = Solver() # Act solver.check() model = solver.model() result = model.eval(calldata.calldatasize) # Assert assert result == 7
def test_concrete_calldata_constrain_index(): # Arrange calldata = Calldata(0, [1, 4, 7, 3, 7, 2, 9]) solver = Solver() # Act value, calldata_constraints = calldata[2] constraint = value == 3 solver.add([constraint] + calldata_constraints) result = solver.check() # Assert assert str(result) == "unsat"
def test_concrete_calldata_constrain_index(): # Arrange calldata = Calldata(0) solver = Solver() # Act constraints = [] constraints.append(calldata[51] == 1) constraints.append(calldata.calldatasize == 50) solver.add(calldata.constraints + constraints) result = solver.check() # Assert assert str(result) == "unsat"
def test_concrete_calldata_constrain_index(): # Arrange calldata = Calldata(0) mstate = MagicMock() mstate.constraints = [] solver = Solver() # Act constraints = [] value, calldata_constraints = calldata[51] constraints.append(value == 1) constraints.append(calldata.calldatasize == 50) solver.add(constraints + calldata_constraints) result = solver.check() # Assert assert str(result) == "unsat"
def test_symbolic_calldata_constrain_index(): # Arrange calldata = Calldata(0) solver = Solver() # Act constraint = calldata[100] == 50 value = calldata[100] solver.add(calldata.constraints + [constraint]) solver.check() model = solver.model() value = model.eval(value) calldatasize = model.eval(calldata.calldatasize) # Assert assert value == 50 assert simplify(calldatasize >= 100)