diff --git a/myth b/myth index 2a3157a4..5efa57e7 100755 --- a/myth +++ b/myth @@ -215,7 +215,6 @@ if (args.address or len(args.solidity_file) or args.init_db): else: eth = EthIpc() - # Database search ops if args.search or args.init_db: @@ -245,12 +244,16 @@ if args.search or args.init_db: contracts = [] if (args.code): + address = util.get_indexed_address(0) + contracts.append(ETHContract(args.code, name="MAIN")) # Get bytecode from a contract address elif (args.address): + address = args.address + if not re.match(r'0x[a-fA-F0-9]{40}', args.address): exitWithError(args.outform, "Invalid contract address. Expected format is '0x...'.") @@ -273,6 +276,8 @@ elif (args.address): elif (len(args.solidity_file)): + address = util.get_indexed_address(0) + if(args.graph and len(args.solidity_file) > 1): exitWithError(args.outform, "Cannot generate call graphs from multiple input files. Please do it one at a time.") @@ -366,9 +371,9 @@ elif (args.graph) or (args.fire_lasers): # try: if (args.dynld): - sym = SymExecWrapper(contracts, dynloader=DynLoader(eth), max_depth=args.max_depth) + sym = SymExecWrapper(contracts[0], address, dynloader=DynLoader(eth), max_depth=args.max_depth) else: - sym = SymExecWrapper(contracts, max_depth=args.max_depth) + sym = SymExecWrapper(contracts[0], address, max_depth=args.max_depth) # except: # exitWithError(args.outform, "Symbolic execution error: " + str(e)) @@ -392,9 +397,9 @@ elif (args.graph) or (args.fire_lasers): # try: if (args.dynld): - sym = SymExecWrapper([contract], dynloader=DynLoader(eth), max_depth=args.max_depth) + sym = SymExecWrapper(contract, address, dynloader=DynLoader(eth), max_depth=args.max_depth) else: - sym = SymExecWrapper([contract], max_depth=args.max_depth) + sym = SymExecWrapper(contract, address, max_depth=args.max_depth) # except Exception as e: # exitWithError(args.outform, "Symbolic exection error: " + str(e)) diff --git a/mythril/analysis/modules/delegatecall_to_dynamic.py b/mythril/analysis/modules/delegatecall_to_dynamic.py index 73ad765d..0c688d90 100644 --- a/mythril/analysis/modules/delegatecall_to_dynamic.py +++ b/mythril/analysis/modules/delegatecall_to_dynamic.py @@ -11,6 +11,7 @@ MODULE DESCRIPTION: Check for invocations of delegatecall/callcode to a user-supplied address ''' + def execute(statespace): logging.debug("Executing module: DELEGATECALL_TO_DYNAMIC") diff --git a/mythril/analysis/modules/ether_send.py b/mythril/analysis/modules/ether_send.py index 04ae22ef..53fee4eb 100644 --- a/mythril/analysis/modules/ether_send.py +++ b/mythril/analysis/modules/ether_send.py @@ -15,6 +15,7 @@ If msg.sender is checked against a value in storage, check whether that storage to that index). ''' + def execute(statespace): logging.debug("Executing module: ETHER_SEND") @@ -100,7 +101,6 @@ def execute(statespace): can_solve = False break - if not constrained: description += "It seems that this function can be called without restrictions." @@ -117,6 +117,6 @@ def execute(statespace): issues.append(issue) except UnsatError: - logging.debug("[ETHER_SEND] no model found") + logging.debug("[ETHER_SEND] no model found") return issues diff --git a/mythril/analysis/ops.py b/mythril/analysis/ops.py index 4f0be22c..0b1ab5be 100644 --- a/mythril/analysis/ops.py +++ b/mythril/analysis/ops.py @@ -50,5 +50,3 @@ class SStore(Op): def __init__(self, node, state, state_index, value): super().__init__(node, state, state_index) self.value = value - - diff --git a/mythril/analysis/symbolic.py b/mythril/analysis/symbolic.py index 7c8e773d..ff939106 100644 --- a/mythril/analysis/symbolic.py +++ b/mythril/analysis/symbolic.py @@ -10,19 +10,15 @@ class SymExecWrapper: Wrapper class for the LASER Symbolic virtual machine. Symbolically executes the code and does a bit of pre-analysis for convenience. ''' - def __init__(self, contracts, dynloader=None, max_depth=12): + def __init__(self, contract, address, dynloader=None, max_depth=12): - self.accounts = {} + account = svm.Account(address, contract.get_disassembly(), contract_name=contract.name) - idx = 0 - - for contract in contracts: - address = ether.util.get_indexed_address(idx) - self.accounts[address] = svm.Account(address, contract.get_disassembly(), contract.name) - idx += 1 + self.accounts = {address: account} self.laser = svm.LaserEVM(self.accounts, dynamic_loader=dynloader, max_depth=max_depth) - self.laser.sym_exec(ether.util.get_indexed_address(0)) + + self.laser.sym_exec(address) self.nodes = self.laser.nodes self.edges = self.laser.edges diff --git a/mythril/ether/ethcontract.py b/mythril/ether/ethcontract.py index 42355186..e892fe7c 100644 --- a/mythril/ether/ethcontract.py +++ b/mythril/ether/ethcontract.py @@ -6,7 +6,7 @@ import re class ETHContract(persistent.Persistent): - def __init__(self, code, creation_code="", name=""): + def __init__(self, code, creation_code="", name="Unknown"): self.creation_code = creation_code self.name = name diff --git a/mythril/ether/soliditycontract.py b/mythril/ether/soliditycontract.py index a3310fd8..568942ea 100644 --- a/mythril/ether/soliditycontract.py +++ b/mythril/ether/soliditycontract.py @@ -20,7 +20,7 @@ class SolidityFile: class SolidityContract(ETHContract): - def __init__(self, input_file, contract_name=None): + def __init__(self, input_file, name=None): data = get_solc_json(input_file) @@ -35,14 +35,14 @@ class SolidityContract(ETHContract): # If a contract name has been specified, find the bytecode of that specific contract - if contract_name: + if name: for key, contract in data['contracts'].items(): - filename, name = key.split(":") + filename, _name = key.split(":") - if filename == input_file and name == contract_name: - self.name = name - self.code = contract['bin-runtime'] - self.creation_code = contract['bin'] + if filename == input_file and name == _name: + name = name + code = contract['bin-runtime'] + creation_code = contract['bin'] srcmap = contract['srcmap-runtime'].split(";") has_contract = True break @@ -54,9 +54,9 @@ class SolidityContract(ETHContract): filename, name = key.split(":") if filename == input_file and len(contract['bin-runtime']): - self.name = name - self.code = contract['bin-runtime'] - self.creation_code = contract['bin'] + name = name + code = contract['bin-runtime'] + creation_code = contract['bin'] srcmap = contract['srcmap-runtime'].split(";") has_contract = True @@ -81,4 +81,4 @@ class SolidityContract(ETHContract): self.mappings.append(SourceMapping(idx, offset, length, lineno)) - super().__init__(self.code, self.creation_code, name) + super().__init__(code, creation_code, name=name) diff --git a/requirements.txt b/requirements.txt index 30bc0c8e..86359ef0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ ethereum>=2.0.4 ZODB>=5.3.0 z3-solver>=4.5 web3 -laser-ethereum==0.5.2 +laser-ethereum==0.5.3 requests BTrees py-solc diff --git a/setup.py b/setup.py index 6040aa2d..69f660fe 100755 --- a/setup.py +++ b/setup.py @@ -254,7 +254,7 @@ Credit setup( name='mythril', - version='0.13.4', + version='0.13.5', description='Security analysis tool for Ethereum smart contracts', long_description=long_description, @@ -291,7 +291,7 @@ setup( 'web3', 'ZODB>=5.3.0', 'z3-solver>=4.5', - 'laser-ethereum==0.5.2', + 'laser-ethereum==0.5.3', 'requests', 'BTrees', 'py-solc' diff --git a/tests/svm_test.py b/tests/svm_test.py index 61c99ec7..6ad191d3 100644 --- a/tests/svm_test.py +++ b/tests/svm_test.py @@ -11,7 +11,7 @@ class SVMTestCase(unittest.TestCase): code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029" contract = ETHContract(code) - sym = SymExecWrapper([contract]) + sym = SymExecWrapper(contract, "0xd0a6E6C543bC68Db5db3A191B171A77407Ff7ccf") html = generate_graph(sym)