def execute_state(self, global_state): instructions = global_state.environment.code.instruction_list op_code = instructions[global_state.mstate.pc]['opcode'] # Only count coverage for the main contract if len(global_state.transaction_stack) == 0: self.instructions_covered[global_state.mstate.pc] = True self._execute_pre_hook(op_code, global_state) try: new_global_states = Instruction( op_code, self.dynamic_loader).evaluate(global_state) except TransactionStartSignal as e: # Setup new global state new_global_state = e.transaction.initial_global_state() new_global_state.transaction_stack = copy( global_state.transaction_stack) + [ (e.transaction, global_state) ] new_global_state.node = global_state.node new_global_state.mstate.constraints = global_state.mstate.constraints return [new_global_state], op_code except TransactionEndSignal as e: transaction, return_global_state = e.global_state.transaction_stack.pop( ) if return_global_state is None: self.open_states.append(e.global_state) new_global_states = [] else: # First execute the post hook for the transaction ending instruction self._execute_post_hook(op_code, [e.global_state]) # Resume execution of the transaction initializing instruction op_code = return_global_state.environment.code.instruction_list[ return_global_state.mstate.pc]['opcode'] # Set execution result in the return_state return_global_state.last_return_data = transaction.return_data return_global_state.world_state = copy( global_state.world_state) return_global_state.environment.active_account =\ global_state.accounts[return_global_state.environment.active_account.address] # Execute the post instruction handler new_global_states = Instruction(op_code, self.dynamic_loader).evaluate( return_global_state, True) # In order to get a nice call graph we need to set the nodes here for state in new_global_states: state.node = global_state.node self._execute_post_hook(op_code, new_global_states) return new_global_states, op_code
def test_staticness(input): # Arrange state = get_global_state() state.environment.static = True state.mstate.stack = [] instruction = Instruction(input, dynamic_loader=None) # Act and Assert with pytest.raises(WriteProtection): instruction.evaluate(state)
def test_concrete_shr(val1, val2, expected): state = get_state() state.mstate.stack = [BVV(int(val1, 16), 256), BVV(int(val2, 16), 256)] expected = BVV(int(expected, 16), 256) instruction = Instruction("shr", dynamic_loader=None) # Act new_state = instruction.evaluate(state)[0] # Assert assert simplify(new_state.mstate.stack[-1]) == expected
def test_staticcall(f1): # Arrange state = get_global_state() state.mstate.stack = [10, 10, 10, 10, 10, 10, 10, 10, 0] instruction = Instruction("staticcall", dynamic_loader=None) # Act and Assert with pytest.raises(TransactionStartSignal) as ts: instruction.evaluate(state) assert ts.value.transaction.static assert ts.value.transaction.initial_global_state().environment.static
def test_shr(inputs, output): # Arrange state = get_state() state.mstate.stack = inputs instruction = Instruction("shr", dynamic_loader=None) # Act new_state = instruction.evaluate(state)[0] # Assert assert simplify(new_state.mstate.stack[-1]) == output
def test_codecopy_concrete(): # Arrange active_account = Account("0x0", code=Disassembly("60606040")) environment = Environment(active_account, None, None, None, None, None) og_state = GlobalState(None, environment, None, MachineState(gas=10000000)) og_state.mstate.stack = [2, 2, 2] instruction = Instruction("codecopy", dynamic_loader=None) # Act new_state = instruction.evaluate(og_state)[0] # Assert assert new_state.mstate.memory[2] == 96 assert new_state.mstate.memory[3] == 64
def _end_message_call( self, return_global_state: GlobalState, global_state: GlobalState, revert_changes=False, return_data=None, ) -> List[GlobalState]: # Resume execution of the transaction initializing instruction op_code = return_global_state.environment.code.instruction_list[ return_global_state.mstate.pc]["opcode"] # Set execution result in the return_state return_global_state.last_return_data = return_data if not revert_changes: return_global_state.world_state = copy(global_state.world_state) return_global_state.environment.active_account = global_state.accounts[ return_global_state.environment.active_account.address] # Execute the post instruction handler new_global_states = Instruction(op_code, self.dynamic_loader).evaluate( return_global_state, True) # In order to get a nice call graph we need to set the nodes here for state in new_global_states: state.node = global_state.node return new_global_states
def test_staticness_call_symbolic(f1): # Arrange state = get_global_state() state.environment.static = True state.mstate.stack = [] call_value = symbol_factory.BitVecSym("x", 256) code = Disassembly(code="616263") f1.return_value = ("0", Account(code=code, address="0x19"), 0, call_value, 0, 0, 0) instruction = Instruction("call", dynamic_loader=None) # Act and Assert with pytest.raises(TransactionStartSignal) as ts: instruction.evaluate(state) assert ts.value.transaction.static assert ts.value.global_state.mstate.constraints[-1] == (call_value == 0)
def execute_state(self, global_state): instructions = global_state.environment.code.instruction_list try: op_code = instructions[global_state.mstate.pc]['opcode'] except IndexError: self.open_states.append(global_state.world_state) return [], None self._execute_pre_hook(op_code, global_state) try: self._measure_coverage(global_state) new_global_states = Instruction(op_code, self.dynamic_loader).evaluate(global_state) except VmException as e: transaction, return_global_state = global_state.transaction_stack.pop() if return_global_state is None: # In this case we don't put an unmodified world state in the open_states list Since in the case of an # exceptional halt all changes should be discarded, and this world state would not provide us with a # previously unseen world state logging.debug("Encountered a VmException, ending path: `{}`".format(str(e))) new_global_states = [] else: # First execute the post hook for the transaction ending instruction self._execute_post_hook(op_code, [global_state]) new_global_states = self._end_message_call(return_global_state, global_state, revert_changes=True, return_data=None) except TransactionStartSignal as e: # Setup new global state new_global_state = e.transaction.initial_global_state() new_global_state.transaction_stack = copy(global_state.transaction_stack) + [(e.transaction, global_state)] new_global_state.node = global_state.node new_global_state.mstate.constraints = global_state.mstate.constraints return [new_global_state], op_code except TransactionEndSignal as e: transaction, return_global_state = e.global_state.transaction_stack.pop() if return_global_state is None: if not isinstance(transaction, ContractCreationTransaction) or transaction.return_data: e.global_state.world_state.node = global_state.node self.open_states.append(e.global_state.world_state) new_global_states = [] else: # First execute the post hook for the transaction ending instruction self._execute_post_hook(op_code, [e.global_state]) new_global_states = self._end_message_call(return_global_state, global_state, revert_changes=False, return_data=transaction.return_data) self._execute_post_hook(op_code, new_global_states) return new_global_states, op_code
def test_codecopy_concrete(): # Arrange active_account = Account("0x0", code=Disassembly("60606040")) environment = Environment(active_account, None, None, None, None, None) og_state = GlobalState(None, environment, None, MachineState(gas_limit=8000000)) og_state.transaction_stack.append( (MessageCallTransaction(world_state=WorldState(), gas_limit=8000000), None)) og_state.mstate.stack = [2, 2, 2] instruction = Instruction("codecopy", dynamic_loader=None) # Act new_state = instruction.evaluate(og_state)[0] # Assert assert new_state.mstate.memory[2] == 96 assert new_state.mstate.memory[3] == 64
def execute_state(self, global_state): instructions = global_state.environment.code.instruction_list op_code = instructions[global_state.mstate.pc]['opcode'] self.instructions_covered[global_state.mstate.pc] = True self._execute_pre_hook(op_code, global_state) new_global_states = Instruction( op_code, self.dynamic_loader).evaluate(global_state) self._execute_post_hook(op_code, new_global_states) return new_global_states, op_code
def test_extcodecopy_fail(): # Arrange new_world_state = WorldState() new_account = new_world_state.create_account(balance=10, address=101) new_account.code = Disassembly("60616240") new_environment = Environment(new_account, None, None, None, None, None) state = GlobalState( new_world_state, new_environment, None, MachineState(gas_limit=8000000) ) state.transaction_stack.append( (MessageCallTransaction(world_state=WorldState(), gas_limit=8000000), None) ) state.mstate.stack = [2, 2, 2, symbol_factory.BitVecSym("FAIL", 256)] instruction = Instruction("extcodecopy", dynamic_loader=None) # Act new_state = instruction.evaluate(state)[0] # Assert assert new_state.mstate.stack == [] assert new_state.mstate.memory._memory == state.mstate.memory._memory
def test_extcodecopy(): # Arrange new_world_state = WorldState() new_account = new_world_state.create_account(balance=10, address=101) new_account.code = Disassembly("60616240") ext_account = new_world_state.create_account(balance=1000, address=121) ext_account.code = Disassembly("6040404040") new_environment = Environment(new_account, None, None, None, None, None) state = GlobalState( new_world_state, new_environment, None, MachineState(gas_limit=8000000) ) state.transaction_stack.append( (MessageCallTransaction(world_state=WorldState(), gas_limit=8000000), None) ) state.mstate.stack = [3, 0, 0, 121] instruction = Instruction("extcodecopy", dynamic_loader=None) # Act new_state = instruction.evaluate(state)[0] # Assert assert new_state.mstate.memory[0:3] == [96, 64, 64]
def execute_state(self, global_state): instructions = global_state.environment.code.instruction_list op_code = instructions[global_state.mstate.pc]['opcode'] # Only count coverage for the main contract if len(global_state.call_stack) == 0: self.instructions_covered[global_state.mstate.pc] = True self._execute_pre_hook(op_code, global_state) new_global_states = Instruction( op_code, self.dynamic_loader).evaluate(global_state) self._execute_post_hook(op_code, new_global_states) return new_global_states, op_code
def _end_message_call( self, return_global_state: GlobalState, global_state: GlobalState, revert_changes=False, return_data=None, ) -> List[GlobalState]: """ :param return_global_state: :param global_state: :param revert_changes: :param return_data: :return: """ return_global_state.mstate.constraints += global_state.mstate.constraints # Resume execution of the transaction initializing instruction op_code = return_global_state.environment.code.instruction_list[ return_global_state.mstate.pc]["opcode"] # Set execution result in the return_state return_global_state.last_return_data = return_data if not revert_changes: return_global_state.world_state = copy(global_state.world_state) return_global_state.environment.active_account = global_state.accounts[ return_global_state.environment.active_account.address.value] if isinstance(global_state.current_transaction, ContractCreationTransaction): return_global_state.mstate.min_gas_used += ( global_state.mstate.min_gas_used) return_global_state.mstate.max_gas_used += ( global_state.mstate.max_gas_used) # Execute the post instruction handler new_global_states = Instruction(op_code, self.dynamic_loader, self.iprof).evaluate( return_global_state, True) # In order to get a nice call graph we need to set the nodes here for state in new_global_states: state.node = global_state.node return new_global_states
def test_staticness_call_concrete(f1, input, success): # Arrange state = get_global_state() state.environment.static = True state.mstate.stack = [] code = Disassembly(code="616263") f1.return_value = ("0", Account(code=code, address="0x19"), 0, input, 0, 0, 0) instruction = Instruction("call", dynamic_loader=None) # Act and Assert if success: with pytest.raises(TransactionStartSignal) as ts: instruction.evaluate(state) assert ts.value.transaction.static else: with pytest.raises(WriteProtection): instruction.evaluate(state)
def execute_state( self, global_state: GlobalState ) -> Tuple[List[GlobalState], Optional[str]]: """Execute a single instruction in global_state. :param global_state: :return: A list of successor states. """ # Execute hooks for hook in self._execute_state_hooks: hook(global_state) instructions = global_state.environment.code.instruction_list try: op_code = instructions[global_state.mstate.pc]["opcode"] except IndexError: self._add_world_state(global_state) return [], None if len(global_state.mstate.stack) < get_required_stack_elements( op_code): error_msg = ("Stack Underflow Exception due to insufficient " "stack elements for the address {}".format( instructions[global_state.mstate.pc]["address"])) new_global_states = self.handle_vm_exception( global_state, op_code, error_msg) self._execute_post_hook(op_code, new_global_states) return new_global_states, op_code try: self._execute_pre_hook(op_code, global_state) except PluginSkipState: self._add_world_state(global_state) return [], None try: new_global_states = Instruction(op_code, self.dynamic_loader, self.iprof).evaluate(global_state) except VmException as e: new_global_states = self.handle_vm_exception( global_state, op_code, str(e)) except TransactionStartSignal as start_signal: # Setup new global state new_global_state = start_signal.transaction.initial_global_state() new_global_state.transaction_stack = copy( global_state.transaction_stack) + [ (start_signal.transaction, global_state) ] new_global_state.node = global_state.node new_global_state.mstate.constraints = ( start_signal.global_state.mstate.constraints) log.debug("Starting new transaction %s", start_signal.transaction) return [new_global_state], op_code except TransactionEndSignal as end_signal: transaction, return_global_state = end_signal.global_state.transaction_stack[ -1] log.debug("Ending transaction %s.", transaction) if return_global_state is None: if (not isinstance(transaction, ContractCreationTransaction) or transaction.return_data) and not end_signal.revert: check_potential_issues(global_state) end_signal.global_state.world_state.node = global_state.node self._add_world_state(end_signal.global_state) new_global_states = [] else: # First execute the post hook for the transaction ending instruction self._execute_post_hook(op_code, [end_signal.global_state]) # Propogate codecall based annotations if return_global_state.get_current_instruction()["opcode"] in ( "DELEGATECALL", "CALLCODE", ): new_annotations = [ annotation for annotation in global_state.get_annotations(MutationAnnotation) ] return_global_state.add_annotations(new_annotations) new_global_states = self._end_message_call( copy(return_global_state), global_state, revert_changes=False or end_signal.revert, return_data=transaction.return_data, ) self._execute_post_hook(op_code, new_global_states) return new_global_states, op_code
def execute_state(self, global_state): instructions = global_state.environment.code.instruction_list op_code = instructions[global_state.mstate.pc]['opcode'] return Instruction(op_code, self.dynamic_loader).evaluate(global_state), op_code
def execute_state(self, global_state): instructions = global_state.environment.code.instruction_list try: op_code = instructions[global_state.mstate.pc]['opcode'] except IndexError: self.open_states.append(global_state.world_state) return [], None self._execute_pre_hook(op_code, global_state) try: self._measure_coverage(global_state) if self.prepostprocessor: global_state = self.prepostprocessor.preprocess(global_state) op_code = global_state.get_current_instruction()['opcode'] new_global_states = Instruction(op_code, self.dynamic_loader).evaluate(global_state) if self.prepostprocessor: new_global_states = self.prepostprocessor.postprocess(global_state, new_global_states) except CreateNewContractSignal as c: laser_evm = LaserEVM(self.accounts, self.dynamic_loader, self.max_depth, self.execution_timeout, self.create_timeout, strategy=DepthFirstSearchStrategy, prepostprocessor=self.prepostprocessor) laser_evm.open_states = [self.world_state] printd("Start subconstruction") code_extension = SymbolicCodeExtension("calldata", "Subcontract", c.extension_byte_size, c.predefined_map) created_account = execute_contract_creation(laser_evm, c.bytecode, contract_name="Subcontract", code_extension=code_extension, callvalue=c.callvalue) if laser_evm.open_states: created_account = laser_evm.open_states[0].accounts[created_account.address] paused_state = c.paused_state paused_state.accounts[created_account.address] = created_account # Computing address from hex str returned to z3 BitVec representation address_as_int = 0 new_address = created_account.address.replace("0x", "") i = 0 while i < len(new_address): address_as_int *= 256 address_as_int += int(new_address[i:i + 2], 16) i += 2 paused_state.mstate.stack.append(BitVecVal(address_as_int, 256)) paused_state.mstate.pc += 1 # Because the post code of instruction wrapper was not executed after Signal new_global_states = [paused_state] if self.prepostprocessor: new_global_states = self.prepostprocessor.postprocess(global_state, new_global_states) printd("End subcontruction") except TransactionStartSignal as e: printd("Transaction start") # Setup new global state new_global_state = e.transaction.initial_global_state() new_global_state.transaction_stack = copy(global_state.transaction_stack) + [(e.transaction, global_state)] new_global_state.node = global_state.node new_global_state.mstate.constraints = global_state.mstate.constraints return [new_global_state], op_code except TransactionEndSignal as e: printd("Transaction end") transaction, return_global_state = e.global_state.transaction_stack.pop() if return_global_state is None: if not isinstance(transaction, ContractCreationTransaction) or transaction.return_data: e.global_state.world_state.node = global_state.node self.open_states.append(e.global_state.world_state) new_global_states = [] else: # First execute the post hook for the transaction ending instruction self._execute_post_hook(op_code, [e.global_state]) # Resume execution of the transaction initializing instruction op_code = return_global_state.environment.code.instruction_list[return_global_state.mstate.pc]['opcode'] # Set execution result in the return_state return_global_state.last_return_data = transaction.return_data return_global_state.world_state = copy(global_state.world_state) return_global_state.environment.active_account = \ global_state.accounts[return_global_state.environment.active_account.address] #if self.prepostprocessor: # global_state = self.prepostprocessor.preprocess(global_state) # op_code = global_state.get_current_instruction()['opcode'] # Execute the post instruction handler new_global_states = Instruction(op_code, self.dynamic_loader).evaluate(return_global_state, True) #if self.prepostprocessor: # new_global_states = self.prepostprocessor.postprocess(global_state, new_global_states) # In order to get a nice call graph we need to set the nodes here for state in new_global_states: state.node = global_state.node self._execute_post_hook(op_code, new_global_states) # Todo Maybe also filter here return new_global_states, op_code
def execute_state( self, global_state: GlobalState ) -> Tuple[List[GlobalState], Union[str, None]]: """ :param global_state: :return: """ # Execute hooks for hook in self._execute_state_hooks: hook(global_state) instructions = global_state.environment.code.instruction_list try: op_code = instructions[global_state.mstate.pc]["opcode"] except IndexError: self._add_world_state(global_state) return [], None self._execute_pre_hook(op_code, global_state) try: self._measure_coverage(global_state) new_global_states = Instruction( op_code, self.dynamic_loader, self.iprof ).evaluate(global_state) except VmException as e: transaction, return_global_state = global_state.transaction_stack.pop() if return_global_state is None: # In this case we don't put an unmodified world state in the open_states list Since in the case of an # exceptional halt all changes should be discarded, and this world state would not provide us with a # previously unseen world state log.debug("Encountered a VmException, ending path: `{}`".format(str(e))) new_global_states = [] else: # First execute the post hook for the transaction ending instruction self._execute_post_hook(op_code, [global_state]) new_global_states = self._end_message_call( return_global_state, global_state, revert_changes=True, return_data=None, ) except TransactionStartSignal as start_signal: # Setup new global state new_global_state = start_signal.transaction.initial_global_state() new_global_state.transaction_stack = copy( global_state.transaction_stack ) + [(start_signal.transaction, global_state)] new_global_state.node = global_state.node new_global_state.mstate.constraints = global_state.mstate.constraints return [new_global_state], op_code except TransactionEndSignal as end_signal: transaction, return_global_state = end_signal.global_state.transaction_stack[ -1 ] if return_global_state is None: if ( not isinstance(transaction, ContractCreationTransaction) or transaction.return_data ) and not end_signal.revert: end_signal.global_state.world_state.node = global_state.node self._add_world_state(end_signal.global_state) new_global_states = [] else: # First execute the post hook for the transaction ending instruction self._execute_post_hook(op_code, [end_signal.global_state]) new_global_states = self._end_message_call( copy(return_global_state), global_state, revert_changes=False or end_signal.revert, return_data=transaction.return_data, ) self._execute_post_hook(op_code, new_global_states) return new_global_states, op_code
def execute_state(self, global_state): instructions = global_state.environment.code.instruction_list try: op_code = instructions[global_state.mstate.pc]['opcode'] except IndexError: self.open_states.append(global_state.world_state) return [], None self._execute_pre_hook(op_code, global_state) try: self._measure_coverage(global_state) new_global_states = Instruction( op_code, self.dynamic_loader).evaluate(global_state) except VmException as e: logging.debug( "Encountered a VmException, ending path: `{}`".format(str(e))) new_global_states = [] except TransactionStartSignal as e: # Setup new global state new_global_state = e.transaction.initial_global_state() new_global_state.transaction_stack = copy( global_state.transaction_stack) + [ (e.transaction, global_state) ] new_global_state.node = global_state.node new_global_state.mstate.constraints = global_state.mstate.constraints return [new_global_state], op_code except TransactionEndSignal as e: transaction, return_global_state = e.global_state.transaction_stack.pop( ) if return_global_state is None: if not isinstance(transaction, ContractCreationTransaction ) or transaction.return_data: e.global_state.world_state.node = global_state.node self.open_states.append(e.global_state.world_state) new_global_states = [] else: # First execute the post hook for the transaction ending instruction self._execute_post_hook(op_code, [e.global_state]) # Resume execution of the transaction initializing instruction op_code = return_global_state.environment.code.instruction_list[ return_global_state.mstate.pc]['opcode'] # Set execution result in the return_state return_global_state.last_return_data = transaction.return_data return_global_state.world_state = copy( global_state.world_state) return_global_state.environment.active_account = \ global_state.accounts[return_global_state.environment.active_account.address] # Execute the post instruction handler new_global_states = Instruction(op_code, self.dynamic_loader).evaluate( return_global_state, True) # In order to get a nice call graph we need to set the nodes here for state in new_global_states: state.node = global_state.node self._execute_post_hook(op_code, new_global_states) return new_global_states, op_code
from mythril.laser.smt import symbol_factory # Arrange world_state = WorldState() account = world_state.create_account(balance=10, address=101) account.code = Disassembly("60606040") world_state.create_account(balance=10, address=1000) environment = Environment(account, None, None, None, None, None) og_state = GlobalState(world_state, environment, None, MachineState(gas_limit=8000000)) og_state.transaction_stack.append( (MessageCallTransaction(world_state=WorldState(), gas_limit=8000000), None)) instruction = Instruction("extcodehash", dynamic_loader=None) def test_extcodehash_no_account(): # If account does not exist, return 0 og_state.mstate.stack = [symbol_factory.BitVecVal(1, 256)] new_state = instruction.evaluate(og_state)[0] assert new_state.mstate.stack[-1] == 0 def test_extcodehash_no_code(): # If account code does not exist, return hash of empty set. og_state.mstate.stack = [symbol_factory.BitVecVal(1000, 256)] new_state = instruction.evaluate(og_state)[0]