Merge pull request #396 from b-mueller/master

Disable function name lookup in contract search, clean up commandline arguments
pull/407/head
Bernhard Mueller 6 years ago committed by GitHub
commit 3f5465dad0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      mythril/disassembler/disassembly.py
  2. 4
      mythril/ether/ethcontract.py
  3. 3
      mythril/exceptions.py
  4. 13
      mythril/interfaces/cli.py
  5. 4
      mythril/leveldb/accountindexing.py
  6. 41
      mythril/leveldb/client.py
  7. 4
      mythril/support/loader.py
  8. 6
      mythril/support/signatures.py

@ -5,14 +5,14 @@ import logging
class Disassembly(object):
def __init__(self, code):
def __init__(self, code, enable_online_lookup=True):
self.instruction_list = asm.disassemble(util.safe_decode(code))
self.func_hashes = []
self.func_to_addr = {}
self.addr_to_func = {}
self.bytecode = code
signatures = SignatureDb(enable_online_lookup=True) # control if you want to have online sighash lookups
signatures = SignatureDb(enable_online_lookup=enable_online_lookup) # control if you want to have online sighash lookups
try:
signatures.open() # open from default locations
except FileNotFoundError:

@ -6,7 +6,7 @@ import re
class ETHContract(persistent.Persistent):
def __init__(self, code, creation_code="", name="Unknown"):
def __init__(self, code, creation_code="", name="Unknown", enable_online_lookup=True):
self.creation_code = creation_code
self.name = name
@ -17,7 +17,7 @@ class ETHContract(persistent.Persistent):
code = re.sub(r'(_+.*_+)', 'aa' * 20, code)
self.code = code
self.disassembly = Disassembly(self.code)
self.disassembly = Disassembly(self.code, enable_online_lookup=enable_online_lookup)
def as_dict(self):

@ -17,3 +17,6 @@ class NoContractFoundError(MythrilBaseException):
class CriticalError(MythrilBaseException):
pass
class AddressNotFoundError(MythrilBaseException):
pass

@ -67,11 +67,8 @@ def main():
options = parser.add_argument_group('options')
options.add_argument('-m', '--modules', help='Comma-separated list of security analysis modules', metavar='MODULES')
options.add_argument('--max-depth', type=int, default=22, help='Maximum recursion depth for symbolic execution')
options.add_argument('--execution-timeout', type=int, default=600, help="The amount of seconds to spend on "
"symbolic execution")
outputs.add_argument('--strategy', choices=['dfs', 'bfs'], default='dfs',
help='Symbolic execution strategy')
options.add_argument('--strategy', choices=['dfs', 'bfs'], default='dfs', help='Symbolic execution strategy')
options.add_argument('--execution-timeout', type=int, default=600, help="The amount of seconds to spend on symbolic execution")
options.add_argument('--solc-args', help='Extra arguments for solc')
options.add_argument('--phrack', action='store_true', help='Phrack-style call graph')
options.add_argument('--enable-physics', action='store_true', help='enable graph physics simulation')
@ -81,8 +78,6 @@ def main():
rpc.add_argument('-i', action='store_true', help='Preset: Infura Node service (Mainnet)')
rpc.add_argument('--rpc', help='custom RPC settings', metavar='HOST:PORT / ganache / infura-[network_name]')
rpc.add_argument('--rpctls', type=bool, default=False, help='RPC connection over TLS')
rpc.add_argument('--ipc', action='store_true', help='Connect via local IPC')
rpc.add_argument('--leveldb', action='store_true', help='Enable direct leveldb access operations')
# Get config values
@ -120,7 +115,7 @@ def main():
if args.dynld and not (args.ipc or args.rpc or args.i):
mythril.set_api_from_config_path()
if args.address and not args.leveldb:
if args.address:
# Establish RPC/IPC connection if necessary
if args.i:
mythril.set_api_rpc_infura()
@ -130,7 +125,7 @@ def main():
mythril.set_api_ipc()
elif not args.dynld:
mythril.set_api_rpc_localhost()
elif args.leveldb or args.search or args.contract_hash_to_address:
elif args.search or args.contract_hash_to_address:
# Open LevelDB if necessary
mythril.set_api_leveldb(mythril.leveldb_dir if not args.leveldb_dir else args.leveldb_dir)

@ -6,6 +6,7 @@ import rlp
from rlp.sedes import big_endian_int, binary
from ethereum import utils
from ethereum.utils import hash32, address, int256
from mythril.exceptions import AddressNotFoundError
BATCH_SIZE = 8 * 4096
@ -65,6 +66,9 @@ class AccountIndexer(object):
address = self.db.reader._get_address_by_hash(contract_hash)
if address is not None:
return address
else:
raise AddressNotFoundError
self.updateIfNeeded()
return self.db.reader._get_address_by_hash(contract_hash)

@ -8,6 +8,7 @@ from ethereum.block import BlockHeader, Block
from mythril.leveldb.state import State
from mythril.leveldb.eth_db import ETH_DB
from mythril.ether.ethcontract import ETHContract
from mythril.exceptions import AddressNotFoundError
# Per https://github.com/ethereum/go-ethereum/blob/master/core/database_util.go
# prefixes and suffixes for keys in geth
@ -180,25 +181,37 @@ class EthLevelDB(object):
'''
iterate through all contracts
'''
indexer = AccountIndexer(self)
for account in self.reader._get_head_state().get_all_accounts():
if account.code is not None:
code = _encode_hex(account.code)
contract = ETHContract(code)
address = indexer.get_contract_by_hash(account.address)
if address is None:
address = account.address
yield contract, _encode_hex(address), account.balance
contract = ETHContract(code, enable_online_lookup=False)
# print("Resolving: %s | %s (%d)" % (account.address, _encode_hex(account.address), len(account.address)))
# if(account.address[0] == 0):
# print("Zero first")
# print(account.address)
# if address is None:
# address = account.address
yield contract, account.address, account.balance
def search(self, expression, callback_func):
'''
searches through non-zero balance contracts
'''
cnt = 0
indexer = AccountIndexer(self)
for contract, address, balance in self.get_contracts():
for contract, address_hash, balance in self.get_contracts():
if contract.matches_expression(expression):
try:
address = _encode_hex(indexer.get_contract_by_hash(address_hash))
except AddressNotFoundError:
address = _encode_hex(address_hash)
callback_func(contract.name, contract, [address], [balance])
cnt += 1
@ -210,13 +223,13 @@ class EthLevelDB(object):
'''
tries to find corresponding account address
'''
indexer = AccountIndexer(self)
address_hash = binascii.a2b_hex(utils.remove_0x_head(hash))
address = indexer.get_contract_by_hash(address_hash)
if address:
return _encode_hex(address)
else:
return "Not found"
# indexer = AccountIndexer(self)
return binascii.a2b_hex(utils.remove_0x_head(hash))
# if address:
# return _encode_hex(address)
# else:
# return "Not found"
def eth_getBlockHeaderByNumber(self, number):
'''

@ -1,15 +1,14 @@
from mythril.ether.ethcontract import ETHContract
from mythril.disassembler.disassembly import Disassembly
import logging
import re
class DynLoader:
def __init__(self, eth):
self.eth = eth
self.storage_cache = {}
def read_storage(self, contract_address, index):
try:
@ -32,7 +31,6 @@ class DynLoader:
return data
def dynld(self, contract_address, dependency_address):
logging.info("Dynld at contract " + contract_address + ": " + dependency_address)

@ -33,7 +33,7 @@ class SimpleFileLock(object):
if self.locked:
raise Exception("SimpleFileLock: lock already aquired")
t_end = time.time()+timeout
t_end = time.time() + timeout
while time.time() < t_end:
# try to aquire lock
try:
@ -49,7 +49,7 @@ class SimpleFileLock(object):
time.sleep(0.5) # busywait is evil
continue
raise Exception("SimpleFileLock: timeout hit. failed to aquire lock: %s"% (time.time()-self.lockfile.stat().st_mtime))
raise Exception("SimpleFileLock: timeout hit. failed to aquire lock: %s" % (time.time() - self.lockfile.stat().st_mtime))
def release(self, force=False):
if not force and not self.locked:
@ -63,7 +63,6 @@ class SimpleFileLock(object):
self.locked = False
class SignatureDb(object):
def __init__(self, enable_online_lookup=True):
@ -172,7 +171,6 @@ class SignatureDb(object):
return [self.signatures[sighash]]
return self.signatures[sighash] # raise keyerror
def __getitem__(self, item):
"""
Provide dict interface Signatures()[sighash]

Loading…
Cancel
Save