Merge pull request #1344 from ConsenSys/dld_updates

Load intial account balances from blockchain and refactor loader flags
pull/1348/head
Bernhard Mueller 5 years ago committed by GitHub
commit ae6a70f802
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      mythril/analysis/symbolic.py
  2. 7
      mythril/ethereum/interface/rpc/client.py
  3. 26
      mythril/interfaces/cli.py
  4. 14
      mythril/laser/ethereum/state/account.py
  5. 23
      mythril/mythril/mythril_analyzer.py
  6. 34
      mythril/support/loader.py

@ -96,10 +96,10 @@ class SymExecWrapper:
raise ValueError("Invalid strategy argument supplied")
creator_account = Account(
hex(ACTORS.creator.value), "", dynamic_loader=dynloader, contract_name=None
hex(ACTORS.creator.value), "", dynamic_loader=None, contract_name=None
)
attacker_account = Account(
hex(ACTORS.attacker.value), "", dynamic_loader=dynloader, contract_name=None
hex(ACTORS.attacker.value), "", dynamic_loader=None, contract_name=None
)
requires_statespace = (
@ -176,8 +176,9 @@ class SymExecWrapper:
contract.disassembly,
dynamic_loader=dynloader,
contract_name=contract.name,
balances=world_state.balances,
concrete_storage=True
if (dynloader is not None and dynloader.storage_loading)
if (dynloader is not None and dynloader.active)
else False,
)
world_state.put_account(account)

@ -52,12 +52,7 @@ class EthJsonRpc(BaseClient):
:return:
"""
params = params or []
data = {
"jsonrpc": "2.0",
"method": method,
"params": params,
"id": _id,
}
data = {"jsonrpc": "2.0", "method": method, "params": params, "id": _id}
scheme = "http"
if self.tls:
scheme += "s"

@ -387,9 +387,7 @@ def create_analyzer_parser(analyzer_parser: ArgumentParser):
action="store_true",
help="analyze a truffle project (run from project dir)",
)
commands.add_argument(
"--infura-id", help="set infura id for onchain analysis",
)
commands.add_argument("--infura-id", help="set infura id for onchain analysis")
options = analyzer_parser.add_argument_group("options")
options.add_argument(
@ -444,18 +442,10 @@ def create_analyzer_parser(analyzer_parser: ArgumentParser):
help="The amount of seconds to spend on the initial contract creation",
)
options.add_argument(
"-l",
"--dynld",
action="store_true",
help="auto-load dependencies from the blockchain",
)
options.add_argument(
"--no-onchain-storage-access",
"--no-onchain-access",
"--no-onchain-data",
action="store_true",
help="turns off getting the data from onchain contracts (both loading storage and contract code)",
help="Don't attempt to retrieve contract code, variables and balances from the blockchain",
)
options.add_argument(
"--phrack", action="store_true", help="Phrack-style call graph"
)
@ -548,10 +538,9 @@ def set_config(args: Namespace):
config = MythrilConfig()
if args.__dict__.get("infura_id", None):
config.set_api_infura_id(args.infura_id)
if (
args.command in ANALYZE_LIST
and (args.dynld or not args.no_onchain_storage_access)
) and not (args.rpc or args.i):
if (args.command in ANALYZE_LIST and not args.no_onchain_data) and not (
args.rpc or args.i
):
config.set_api_from_config_path()
if args.__dict__.get("address", None):
@ -678,9 +667,8 @@ def execute_command(
create_timeout=args.create_timeout,
enable_iprof=args.enable_iprof,
disable_dependency_pruning=args.disable_dependency_pruning,
onchain_storage_access=not args.no_onchain_storage_access,
use_onchain_data=not args.no_onchain_data,
solver_timeout=args.solver_timeout,
requires_dynld=not args.no_onchain_storage_access,
enable_coverage_strategy=args.enable_coverage_strategy,
custom_modules_directory=args.custom_modules_directory
if args.custom_modules_directory

@ -40,7 +40,7 @@ class Storage:
and self.address.value != 0
and item.symbolic is False
and int(item.value) not in self.storage_keys_loaded
and (self.dynld and self.dynld.storage_loading)
and (self.dynld and self.dynld.active)
):
try:
storage[item] = symbol_factory.BitVecVal(
@ -115,7 +115,7 @@ class Account:
# Metadata
if contract_name is None:
self.contract_name = (
"{0:#0{1}x}".format(self.address.value, 40)
"{0:#0{1}x}".format(self.address.value, 42)
if not self.address.symbolic
else "unknown"
)
@ -127,6 +127,16 @@ class Account:
self._balances = balances
self.balance = lambda: self._balances[self.address]
if not self.address.symbolic and dynamic_loader is not None:
try:
_balance = dynamic_loader.read_balance(
"{0:#0{1}x}".format(self.address.value, 42)
)
self.set_balance(_balance)
except:
# Initial balance will be a symbolic variable
pass
def __str__(self) -> str:
return str(self.as_dict)

@ -33,7 +33,7 @@ class MythrilAnalyzer:
self,
disassembler: MythrilDisassembler,
requires_dynld: bool = False,
onchain_storage_access: bool = True,
use_onchain_data: bool = True,
strategy: str = "dfs",
address: Optional[str] = None,
max_depth: Optional[int] = None,
@ -55,8 +55,7 @@ class MythrilAnalyzer:
self.eth = disassembler.eth
self.contracts = disassembler.contracts or [] # type: List[EVMContract]
self.enable_online_lookup = disassembler.enable_online_lookup
self.dynld = requires_dynld
self.onchain_storage_access = onchain_storage_access
self.use_onchain_data = use_onchain_data
self.strategy = strategy
self.address = address
self.max_depth = max_depth
@ -81,11 +80,7 @@ class MythrilAnalyzer:
contract or self.contracts[0],
self.address,
self.strategy,
dynloader=DynLoader(
self.eth,
storage_loading=self.onchain_storage_access,
contract_loading=self.dynld,
),
dynloader=DynLoader(self.eth, active=self.use_onchain_data),
max_depth=self.max_depth,
execution_timeout=self.execution_timeout,
create_timeout=self.create_timeout,
@ -118,11 +113,7 @@ class MythrilAnalyzer:
contract or self.contracts[0],
self.address,
self.strategy,
dynloader=DynLoader(
self.eth,
storage_loading=self.onchain_storage_access,
contract_loading=self.dynld,
),
dynloader=DynLoader(self.eth, active=self.use_onchain_data),
max_depth=self.max_depth,
execution_timeout=self.execution_timeout,
transaction_count=transaction_count,
@ -155,11 +146,7 @@ class MythrilAnalyzer:
contract,
self.address,
self.strategy,
dynloader=DynLoader(
self.eth,
storage_loading=self.onchain_storage_access,
contract_loading=self.dynld,
),
dynloader=DynLoader(self.eth, active=self.use_onchain_data),
max_depth=self.max_depth,
execution_timeout=self.execution_timeout,
loop_bound=self.loop_bound,

@ -15,18 +15,14 @@ log = logging.getLogger(__name__)
class DynLoader:
"""The dynamic loader class."""
def __init__(
self, eth: Optional[EthJsonRpc], contract_loading=True, storage_loading=True
):
def __init__(self, eth: Optional[EthJsonRpc], active=True):
"""
:param eth:
:param contract_loading:
:param storage_loading:
:param active:
"""
self.eth = eth
self.contract_loading = contract_loading
self.storage_loading = storage_loading
self.active = active
@functools.lru_cache(LRU_CACHE_SIZE)
def read_storage(self, contract_address: str, index: int) -> str:
@ -36,10 +32,8 @@ class DynLoader:
:param index:
:return:
"""
if not self.storage_loading:
raise ValueError(
"Cannot load from the storage when the storage_loading flag is false"
)
if not self.active:
raise ValueError("Loader is disabled")
if not self.eth:
raise ValueError("Cannot load from the storage when eth is None")
@ -47,14 +41,28 @@ class DynLoader:
contract_address, position=index, block="latest"
)
@functools.lru_cache(LRU_CACHE_SIZE)
def read_balance(self, address: str) -> str:
"""
:param address:
:return:
"""
if not self.active:
raise ValueError("Cannot load from storage when the loader is disabled")
if not self.eth:
raise ValueError("Cannot load from the chain when eth is None")
return self.eth.eth_getBalance(address)
@functools.lru_cache(LRU_CACHE_SIZE)
def dynld(self, dependency_address: str) -> Optional[Disassembly]:
"""
:param dependency_address:
:return:
"""
if not self.contract_loading:
raise ValueError("Cannot load contract when contract_loading flag is false")
if not self.active:
raise ValueError("Loader is disabled")
if not self.eth:
raise ValueError("Cannot load from the storage when eth is None")

Loading…
Cancel
Save