Update contract<>address mapping logic

pull/62/merge
Bernhard Mueller 7 years ago
parent 1a69b7f658
commit bd4be45032
  1. 15
      myth
  2. 1
      mythril/analysis/modules/delegatecall_to_dynamic.py
  3. 4
      mythril/analysis/modules/ether_send.py
  4. 2
      mythril/analysis/ops.py
  5. 14
      mythril/analysis/symbolic.py
  6. 2
      mythril/ether/ethcontract.py
  7. 22
      mythril/ether/soliditycontract.py
  8. 2
      requirements.txt
  9. 4
      setup.py
  10. 2
      tests/svm_test.py

15
myth

@ -215,7 +215,6 @@ if (args.address or len(args.solidity_file) or args.init_db):
else: else:
eth = EthIpc() eth = EthIpc()
# Database search ops # Database search ops
if args.search or args.init_db: if args.search or args.init_db:
@ -245,12 +244,16 @@ if args.search or args.init_db:
contracts = [] contracts = []
if (args.code): if (args.code):
address = util.get_indexed_address(0)
contracts.append(ETHContract(args.code, name="MAIN")) contracts.append(ETHContract(args.code, name="MAIN"))
# Get bytecode from a contract address # Get bytecode from a contract address
elif (args.address): elif (args.address):
address = args.address
if not re.match(r'0x[a-fA-F0-9]{40}', 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...'.") exitWithError(args.outform, "Invalid contract address. Expected format is '0x...'.")
@ -273,6 +276,8 @@ elif (args.address):
elif (len(args.solidity_file)): elif (len(args.solidity_file)):
address = util.get_indexed_address(0)
if(args.graph and len(args.solidity_file) > 1): 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.") 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: # try:
if (args.dynld): 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: else:
sym = SymExecWrapper(contracts, max_depth=args.max_depth) sym = SymExecWrapper(contracts[0], address, max_depth=args.max_depth)
# except: # except:
# exitWithError(args.outform, "Symbolic execution error: " + str(e)) # exitWithError(args.outform, "Symbolic execution error: " + str(e))
@ -392,9 +397,9 @@ elif (args.graph) or (args.fire_lasers):
# try: # try:
if (args.dynld): 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: else:
sym = SymExecWrapper([contract], max_depth=args.max_depth) sym = SymExecWrapper(contract, address, max_depth=args.max_depth)
# except Exception as e: # except Exception as e:
# exitWithError(args.outform, "Symbolic exection error: " + str(e)) # exitWithError(args.outform, "Symbolic exection error: " + str(e))

@ -11,6 +11,7 @@ MODULE DESCRIPTION:
Check for invocations of delegatecall/callcode to a user-supplied address Check for invocations of delegatecall/callcode to a user-supplied address
''' '''
def execute(statespace): def execute(statespace):
logging.debug("Executing module: DELEGATECALL_TO_DYNAMIC") logging.debug("Executing module: DELEGATECALL_TO_DYNAMIC")

@ -15,6 +15,7 @@ If msg.sender is checked against a value in storage, check whether that storage
to that index). to that index).
''' '''
def execute(statespace): def execute(statespace):
logging.debug("Executing module: ETHER_SEND") logging.debug("Executing module: ETHER_SEND")
@ -100,7 +101,6 @@ def execute(statespace):
can_solve = False can_solve = False
break break
if not constrained: if not constrained:
description += "It seems that this function can be called without restrictions." description += "It seems that this function can be called without restrictions."
@ -117,6 +117,6 @@ def execute(statespace):
issues.append(issue) issues.append(issue)
except UnsatError: except UnsatError:
logging.debug("[ETHER_SEND] no model found") logging.debug("[ETHER_SEND] no model found")
return issues return issues

@ -50,5 +50,3 @@ class SStore(Op):
def __init__(self, node, state, state_index, value): def __init__(self, node, state, state_index, value):
super().__init__(node, state, state_index) super().__init__(node, state, state_index)
self.value = value self.value = value

@ -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. 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 self.accounts = {address: account}
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.laser = svm.LaserEVM(self.accounts, dynamic_loader=dynloader, max_depth=max_depth) 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.nodes = self.laser.nodes
self.edges = self.laser.edges self.edges = self.laser.edges

@ -6,7 +6,7 @@ import re
class ETHContract(persistent.Persistent): 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.creation_code = creation_code
self.name = name self.name = name

@ -20,7 +20,7 @@ class SolidityFile:
class SolidityContract(ETHContract): class SolidityContract(ETHContract):
def __init__(self, input_file, contract_name=None): def __init__(self, input_file, name=None):
data = get_solc_json(input_file) 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 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(): for key, contract in data['contracts'].items():
filename, name = key.split(":") filename, _name = key.split(":")
if filename == input_file and name == contract_name: if filename == input_file and name == _name:
self.name = name name = name
self.code = contract['bin-runtime'] code = contract['bin-runtime']
self.creation_code = contract['bin'] creation_code = contract['bin']
srcmap = contract['srcmap-runtime'].split(";") srcmap = contract['srcmap-runtime'].split(";")
has_contract = True has_contract = True
break break
@ -54,9 +54,9 @@ class SolidityContract(ETHContract):
filename, name = key.split(":") filename, name = key.split(":")
if filename == input_file and len(contract['bin-runtime']): if filename == input_file and len(contract['bin-runtime']):
self.name = name name = name
self.code = contract['bin-runtime'] code = contract['bin-runtime']
self.creation_code = contract['bin'] creation_code = contract['bin']
srcmap = contract['srcmap-runtime'].split(";") srcmap = contract['srcmap-runtime'].split(";")
has_contract = True has_contract = True
@ -81,4 +81,4 @@ class SolidityContract(ETHContract):
self.mappings.append(SourceMapping(idx, offset, length, lineno)) self.mappings.append(SourceMapping(idx, offset, length, lineno))
super().__init__(self.code, self.creation_code, name) super().__init__(code, creation_code, name=name)

@ -2,7 +2,7 @@ ethereum>=2.0.4
ZODB>=5.3.0 ZODB>=5.3.0
z3-solver>=4.5 z3-solver>=4.5
web3 web3
laser-ethereum==0.5.2 laser-ethereum==0.5.3
requests requests
BTrees BTrees
py-solc py-solc

@ -254,7 +254,7 @@ Credit
setup( setup(
name='mythril', name='mythril',
version='0.13.4', version='0.13.5',
description='Security analysis tool for Ethereum smart contracts', description='Security analysis tool for Ethereum smart contracts',
long_description=long_description, long_description=long_description,
@ -291,7 +291,7 @@ setup(
'web3', 'web3',
'ZODB>=5.3.0', 'ZODB>=5.3.0',
'z3-solver>=4.5', 'z3-solver>=4.5',
'laser-ethereum==0.5.2', 'laser-ethereum==0.5.3',
'requests', 'requests',
'BTrees', 'BTrees',
'py-solc' 'py-solc'

@ -11,7 +11,7 @@ class SVMTestCase(unittest.TestCase):
code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029" code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029"
contract = ETHContract(code) contract = ETHContract(code)
sym = SymExecWrapper([contract]) sym = SymExecWrapper(contract, "0xd0a6E6C543bC68Db5db3A191B171A77407Ff7ccf")
html = generate_graph(sym) html = generate_graph(sym)

Loading…
Cancel
Save