Merge pull request #567 from JoranHonig/features/dynamictransactions

Dynamic transaction execution
pull/573/head
JoranHonig 6 years ago committed by GitHub
commit d005944458
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      mythril/laser/ethereum/call.py
  2. 2
      mythril/laser/ethereum/instructions.py
  3. 21
      mythril/laser/ethereum/svm.py

@ -49,7 +49,7 @@ def get_callee_address(global_state:GlobalState, dynamic_loader: DynLoader, symb
try: try:
callee_address = hex(util.get_concrete_int(symbolic_to_address)) callee_address = hex(util.get_concrete_int(symbolic_to_address))
except AttributeError: except AttributeError:
logging.info("Symbolic call encountered") logging.debug("Symbolic call encountered")
match = re.search(r'storage_(\d+)', str(simplify(symbolic_to_address))) match = re.search(r'storage_(\d+)', str(simplify(symbolic_to_address)))
logging.debug("CALL to: " + str(simplify(symbolic_to_address))) logging.debug("CALL to: " + str(simplify(symbolic_to_address)))
@ -58,7 +58,7 @@ def get_callee_address(global_state:GlobalState, dynamic_loader: DynLoader, symb
raise ValueError() raise ValueError()
index = int(match.group(1)) index = int(match.group(1))
logging.info("Dynamic contract address at storage index {}".format(index)) logging.debug("Dynamic contract address at storage index {}".format(index))
# attempt to read the contract address from instance storage # attempt to read the contract address from instance storage
try: try:
@ -89,22 +89,22 @@ def get_callee_account(global_state, callee_address, dynamic_loader):
return global_state.accounts[callee_address] return global_state.accounts[callee_address]
except KeyError: except KeyError:
# We have a valid call address, but contract is not in the modules list # We have a valid call address, but contract is not in the modules list
logging.info("Module with address " + callee_address + " not loaded.") logging.debug("Module with address " + callee_address + " not loaded.")
if dynamic_loader is None: if dynamic_loader is None:
raise ValueError() raise ValueError()
logging.info("Attempting to load dependency") logging.debug("Attempting to load dependency")
try: try:
code = dynamic_loader.dynld(environment.active_account.address, callee_address) code = dynamic_loader.dynld(environment.active_account.address, callee_address)
except Exception as e: except Exception as e:
logging.info("Unable to execute dynamic loader.") logging.debug("Unable to execute dynamic loader.")
raise ValueError() raise ValueError()
if code is None: if code is None:
logging.info("No code returned, not a contract account?") logging.debug("No code returned, not a contract account?")
raise ValueError() raise ValueError()
logging.info("Dependency loaded: " + callee_address) logging.debug("Dependency loaded: " + callee_address)
callee_account = Account(callee_address, code, callee_address, dynamic_loader=dynamic_loader) callee_account = Account(callee_address, code, callee_address, dynamic_loader=dynamic_loader)
accounts[callee_address] = callee_account accounts[callee_address] = callee_account

@ -1028,7 +1028,7 @@ class Instruction:
callee_address, callee_account, call_data, value, call_data_type, gas, memory_out_offset, memory_out_size = get_call_parameters( callee_address, callee_account, call_data, value, call_data_type, gas, memory_out_offset, memory_out_size = get_call_parameters(
global_state, self.dynamic_loader, True) global_state, self.dynamic_loader, True)
except ValueError as e: except ValueError as e:
logging.info( logging.debug(
"Could not determine required parameters for call, putting fresh symbol on the stack. \n{}".format(e) "Could not determine required parameters for call, putting fresh symbol on the stack. \n{}".format(e)
) )
# TODO: decide what to do in this case # TODO: decide what to do in this case

@ -60,7 +60,7 @@ class LaserEVM:
def accounts(self): def accounts(self):
return self.world_state.accounts return self.world_state.accounts
def sym_exec(self, main_address=None, creation_code=None, contract_name=None): def sym_exec(self, main_address=None, creation_code=None, contract_name=None, max_transactions=3):
logging.debug("Starting LASER execution") logging.debug("Starting LASER execution")
self.time = datetime.now() self.time = datetime.now()
@ -77,19 +77,30 @@ class LaserEVM:
# Reset code coverage # Reset code coverage
self.coverage = {} self.coverage = {}
self.time = datetime.now() for i in range(max_transactions):
logging.info("Starting message call transaction") initial_coverage = self._get_covered_instructions()
execute_message_call(self, created_account.address)
self.time = datetime.now() self.time = datetime.now()
logging.info("Starting message call transaction, iteration: {}".format(i))
execute_message_call(self, created_account.address) execute_message_call(self, created_account.address)
end_coverage = self._get_covered_instructions()
if end_coverage == initial_coverage:
break
logging.info("Finished symbolic execution") logging.info("Finished symbolic execution")
logging.info("%d nodes, %d edges, %d total states", len(self.nodes), len(self.edges), self.total_states) logging.info("%d nodes, %d edges, %d total states", len(self.nodes), len(self.edges), self.total_states)
for code, coverage in self.coverage.items(): for code, coverage in self.coverage.items():
cov = reduce(lambda sum_, val: sum_ + 1 if val else sum_, coverage[1]) / float(coverage[0]) * 100 cov = reduce(lambda sum_, val: sum_ + 1 if val else sum_, coverage[1]) / float(coverage[0]) * 100
logging.info("Achieved {} coverage for code: {}".format(cov, code)) logging.info("Achieved {} coverage for code: {}".format(cov, code))
def _get_covered_instructions(self) -> int:
""" Gets the total number of covered instructions for all accounts in the svm"""
total_covered_instructions = 0
for _, cv in self.coverage.items():
total_covered_instructions += reduce(lambda sum_, val: sum_ + 1 if val else sum_, cv[1])
return total_covered_instructions
def exec(self, create=False): def exec(self, create=False):
for global_state in self.strategy: for global_state in self.strategy:
if self.execution_timeout and not create: if self.execution_timeout and not create:
@ -252,7 +263,7 @@ class LaserEVM:
environment.active_function_name = disassembly.addr_to_func[address] environment.active_function_name = disassembly.addr_to_func[address]
new_node.flags |= NodeFlags.FUNC_ENTRY new_node.flags |= NodeFlags.FUNC_ENTRY
logging.info( logging.debug(
"- Entering function " + environment.active_account.contract_name + ":" + new_node.function_name) "- Entering function " + environment.active_account.contract_name + ":" + new_node.function_name)
elif address == 0: elif address == 0:
environment.active_function_name = "fallback" environment.active_function_name = "fallback"

Loading…
Cancel
Save