Merge branch 'develop' into feature/docs

pull/845/head
Dominik Muhs 6 years ago
commit 88be48d230
  1. 6
      .circleci/config.yml
  2. 25
      mythril/alarm.py
  3. 3
      mythril/analysis/modules/base.py
  4. 6
      mythril/analysis/security.py
  5. 12
      mythril/analysis/symbolic.py
  6. 4
      mythril/exceptions.py
  7. 12
      mythril/laser/ethereum/call.py
  8. 11
      mythril/laser/ethereum/cfg.py
  9. 19
      mythril/laser/ethereum/instructions.py
  10. 2
      mythril/laser/ethereum/state/account.py
  11. 8
      mythril/laser/ethereum/state/calldata.py
  12. 6
      mythril/laser/ethereum/state/environment.py
  13. 8
      mythril/laser/ethereum/state/memory.py
  14. 106
      mythril/laser/ethereum/svm.py
  15. 14
      mythril/laser/ethereum/transaction/concolic.py
  16. 31
      mythril/laser/ethereum/transaction/symbolic.py
  17. 14
      mythril/laser/ethereum/transaction/transaction_models.py
  18. 54
      mythril/mythril.py
  19. 2
      mythril/support/truffle.py
  20. 2
      requirements.txt
  21. 2
      setup.py
  22. 8
      tests/native_test.py

@ -74,6 +74,12 @@ jobs:
# command: if [ -z "$CIRCLE_PR_NUMBER" ]; then ./run-integration-tests.sh; fi # command: if [ -z "$CIRCLE_PR_NUMBER" ]; then ./run-integration-tests.sh; fi
# working_directory: /home # working_directory: /home
- run:
name: Call webhook
command: |
curl -I -X POST -H -d "https://circleci.com/api/v1/project/${ORGANIZATION}/${WEBHOOK_PROJECT}/tree/master?circle-token=${CIRCLE_TOKEN}" | head -n 1 | cut -d$' ' -f2
pypi_release: pypi_release:
<<: *defaults <<: *defaults
steps: steps:

@ -0,0 +1,25 @@
import signal
from types import FrameType
from mythril.exceptions import OutOfTimeError
def sigalrm_handler(signum: int, frame: FrameType) -> None:
raise OutOfTimeError
def start_timeout(timeout: int) -> None:
"""
Starts a timeout
:param timeout: Time in seconds to set the timeout for
:return: None
"""
signal.signal(signal.SIGALRM, sigalrm_handler)
signal.alarm(timeout)
def disable_timeout() -> None:
"""
Ensures that the timeout is disabled
:return: None
"""
signal.alarm(0)

@ -48,7 +48,8 @@ class DetectionModule:
"DetectionModule " "DetectionModule "
"name={0.name} " "name={0.name} "
"swc_id={0.swc_id} " "swc_id={0.swc_id} "
"hooks={0.hooks} " "pre_hooks={0.pre_hooks} "
"post_hooks={0.post_hooks} "
"description={0.description}" "description={0.description}"
">" ">"
).format(self) ).format(self)

@ -89,6 +89,12 @@ def fire_lasers(statespace, module_names=()):
log.info("Executing " + module.detector.name) log.info("Executing " + module.detector.name)
issues += module.detector.execute(statespace) issues += module.detector.execute(statespace)
issues += retrieve_callback_issues(module_names)
return issues
def retrieve_callback_issues(module_names=()):
issues = []
for module in get_detection_modules( for module in get_detection_modules(
entrypoint="callback", include_modules=module_names entrypoint="callback", include_modules=module_names
): ):

@ -1,8 +1,7 @@
"""This module contains a wrapper around LASER for extended analysis """This module contains a wrapper around LASER for extended analysis
purposes.""" purposes."""
import copy
from mythril.analysis.security import get_detection_module_hooks from mythril.analysis.security import get_detection_module_hooks, get_detection_modules
from mythril.laser.ethereum import svm from mythril.laser.ethereum import svm
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.strategy.basic import ( from mythril.laser.ethereum.strategy.basic import (
@ -33,6 +32,7 @@ class SymExecWrapper:
create_timeout=None, create_timeout=None,
transaction_count=2, transaction_count=2,
modules=(), modules=(),
compulsory_statespace=True,
): ):
""" """
@ -63,7 +63,9 @@ class SymExecWrapper:
dynamic_loader=dynloader, dynamic_loader=dynloader,
contract_name=contract.name, contract_name=contract.name,
) )
requires_statespace = (
compulsory_statespace or len(get_detection_modules("post", modules)) > 0
)
self.accounts = {address: account} self.accounts = {address: account}
self.laser = svm.LaserEVM( self.laser = svm.LaserEVM(
@ -74,6 +76,7 @@ class SymExecWrapper:
strategy=s_strategy, strategy=s_strategy,
create_timeout=create_timeout, create_timeout=create_timeout,
transaction_count=transaction_count, transaction_count=transaction_count,
requires_statespace=requires_statespace,
) )
self.laser.register_hooks( self.laser.register_hooks(
hook_type="pre", hook_type="pre",
@ -95,6 +98,9 @@ class SymExecWrapper:
else: else:
self.laser.sym_exec(address) self.laser.sym_exec(address)
if not requires_statespace:
return
self.nodes = self.laser.nodes self.nodes = self.laser.nodes
self.edges = self.laser.edges self.edges = self.laser.edges

@ -7,6 +7,10 @@ class MythrilBaseException(Exception):
pass pass
class OutOfTimeError(MythrilBaseException):
pass
class CompilerError(MythrilBaseException): class CompilerError(MythrilBaseException):
"""A Mythril exception denoting an error during code compilation.""" """A Mythril exception denoting an error during code compilation."""

@ -11,10 +11,9 @@ from mythril.laser.smt import simplify, Expression, symbol_factory
import mythril.laser.ethereum.util as util import mythril.laser.ethereum.util as util
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.calldata import ( from mythril.laser.ethereum.state.calldata import (
CalldataType, BaseCalldata,
SymbolicCalldata, SymbolicCalldata,
ConcreteCalldata, ConcreteCalldata,
BaseCalldata,
) )
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.support.loader import DynLoader from mythril.support.loader import DynLoader
@ -48,9 +47,7 @@ def get_call_parameters(
callee_address = get_callee_address(global_state, dynamic_loader, to) callee_address = get_callee_address(global_state, dynamic_loader, to)
callee_account = None callee_account = None
call_data, call_data_type = get_call_data( call_data = get_call_data(global_state, memory_input_offset, memory_input_size)
global_state, memory_input_offset, memory_input_size
)
if int(callee_address, 16) >= 5 or int(callee_address, 16) == 0: if int(callee_address, 16) >= 5 or int(callee_address, 16) == 0:
callee_account = get_callee_account( callee_account = get_callee_account(
@ -62,7 +59,6 @@ def get_call_parameters(
callee_account, callee_account,
call_data, call_data,
value, value,
call_data_type,
gas, gas,
memory_out_offset, memory_out_offset,
memory_out_size, memory_out_size,
@ -189,14 +185,12 @@ def get_call_data(
) )
] ]
call_data = ConcreteCalldata(transaction_id, calldata_from_mem) call_data = ConcreteCalldata(transaction_id, calldata_from_mem)
call_data_type = CalldataType.CONCRETE
log.debug("Calldata: " + str(call_data)) log.debug("Calldata: " + str(call_data))
except TypeError: except TypeError:
log.debug("Unsupported symbolic calldata offset") log.debug("Unsupported symbolic calldata offset")
call_data_type = CalldataType.SYMBOLIC
call_data = SymbolicCalldata("{}_internalcall".format(transaction_id)) call_data = SymbolicCalldata("{}_internalcall".format(transaction_id))
return call_data, call_data_type return call_data
def native_call( def native_call(

@ -26,8 +26,13 @@ class NodeFlags(Flags):
class Node: class Node:
"""The representation of a call graph node.""" """The representation of a call graph node."""
def __init__(
def __init__(self, contract_name: str, start_addr=0, constraints=None): self,
contract_name: str,
start_addr=0,
constraints=None,
function_name="unknown",
):
""" """
:param contract_name: :param contract_name:
@ -39,7 +44,7 @@ class Node:
self.start_addr = start_addr self.start_addr = start_addr
self.states = [] self.states = []
self.constraints = constraints self.constraints = constraints
self.function_name = "unknown" self.function_name = function_name
self.flags = NodeFlags() self.flags = NodeFlags()
# Self-assign a unique ID # Self-assign a unique ID

@ -516,7 +516,9 @@ class Instruction:
) )
else: else:
state.stack.append(pow(base.value, exponent.value, 2 ** 256)) state.stack.append(
symbol_factory.BitVecVal(pow(base.value, exponent.value, 2 ** 256), 256)
)
return [global_state] return [global_state]
@ -1678,7 +1680,7 @@ class Instruction:
environment = global_state.environment environment = global_state.environment
try: try:
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, 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:
@ -1712,7 +1714,6 @@ class Instruction:
), ),
callee_account=callee_account, callee_account=callee_account,
call_data=call_data, call_data=call_data,
call_data_type=call_data_type,
call_value=value, call_value=value,
) )
raise TransactionStartSignal(transaction, self.op_code) raise TransactionStartSignal(transaction, self.op_code)
@ -1795,7 +1796,7 @@ class Instruction:
environment = global_state.environment environment = global_state.environment
try: try:
callee_address, callee_account, call_data, value, call_data_type, gas, _, _ = get_call_parameters( callee_address, callee_account, call_data, value, gas, _, _ = get_call_parameters(
global_state, self.dynamic_loader, True global_state, self.dynamic_loader, True
) )
except ValueError as e: except ValueError as e:
@ -1818,7 +1819,6 @@ class Instruction:
caller=environment.address, caller=environment.address,
callee_account=environment.active_account, callee_account=environment.active_account,
call_data=call_data, call_data=call_data,
call_data_type=call_data_type,
call_value=value, call_value=value,
) )
raise TransactionStartSignal(transaction, self.op_code) raise TransactionStartSignal(transaction, self.op_code)
@ -1833,7 +1833,7 @@ class Instruction:
instr = global_state.get_current_instruction() instr = global_state.get_current_instruction()
try: try:
callee_address, _, _, value, _, _, memory_out_offset, memory_out_size = get_call_parameters( callee_address, _, _, value, _, 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:
@ -1899,7 +1899,7 @@ class Instruction:
environment = global_state.environment environment = global_state.environment
try: try:
callee_address, callee_account, call_data, value, call_data_type, gas, _, _ = get_call_parameters( callee_address, callee_account, call_data, value, gas, _, _ = get_call_parameters(
global_state, self.dynamic_loader global_state, self.dynamic_loader
) )
except ValueError as e: except ValueError as e:
@ -1922,7 +1922,6 @@ class Instruction:
caller=environment.sender, caller=environment.sender,
callee_account=environment.active_account, callee_account=environment.active_account,
call_data=call_data, call_data=call_data,
call_data_type=call_data_type,
call_value=environment.callvalue, call_value=environment.callvalue,
) )
raise TransactionStartSignal(transaction, self.op_code) raise TransactionStartSignal(transaction, self.op_code)
@ -1937,7 +1936,7 @@ class Instruction:
instr = global_state.get_current_instruction() instr = global_state.get_current_instruction()
try: try:
callee_address, _, _, value, _, _, memory_out_offset, memory_out_size = get_call_parameters( callee_address, _, _, value, _, memory_out_offset, memory_out_size = get_call_parameters(
global_state, self.dynamic_loader global_state, self.dynamic_loader
) )
except ValueError as e: except ValueError as e:
@ -2002,7 +2001,7 @@ class Instruction:
# TODO: implement me # TODO: implement me
instr = global_state.get_current_instruction() instr = global_state.get_current_instruction()
try: try:
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, gas, memory_out_offset, memory_out_size = get_call_parameters(
global_state, self.dynamic_loader global_state, self.dynamic_loader
) )
except ValueError as e: except ValueError as e:

@ -47,7 +47,7 @@ class Storage:
except ValueError: except ValueError:
pass pass
if self.concrete: if self.concrete:
return 0 return symbol_factory.BitVecVal(0, 256)
self._storage[item] = symbol_factory.BitVecVal(0, 256) self._storage[item] = symbol_factory.BitVecVal(0, 256)
return self._storage[item] return self._storage[item]

@ -1,4 +1,7 @@
"""This module declares classes to represent call data.""" """This module declares classes to represent call data."""
from typing import Union, Any
from mythril.laser.smt import K, Array, If, simplify, Concat, Expression, BitVec
from enum import Enum from enum import Enum
from typing import Any, Union from typing import Any, Union
@ -19,11 +22,6 @@ from mythril.laser.smt import (
) )
class CalldataType(Enum):
CONCRETE = 1
SYMBOLIC = 2
class BaseCalldata: class BaseCalldata:
"""Base calldata class This represents the calldata provided when sending a """Base calldata class This represents the calldata provided when sending a
transaction to a contract.""" transaction to a contract."""

@ -5,8 +5,7 @@ from typing import Dict
from z3 import ExprRef from z3 import ExprRef
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.calldata import BaseCalldata, CalldataType from mythril.laser.ethereum.state.calldata import BaseCalldata
from mythril.laser.smt import symbol_factory
class Environment: class Environment:
@ -22,7 +21,6 @@ class Environment:
callvalue: ExprRef, callvalue: ExprRef,
origin: ExprRef, origin: ExprRef,
code=None, code=None,
calldata_type=CalldataType.SYMBOLIC,
): ):
""" """
@ -47,7 +45,6 @@ class Environment:
self.sender = sender self.sender = sender
self.calldata = calldata self.calldata = calldata
self.calldata_type = calldata_type
self.gasprice = gasprice self.gasprice = gasprice
self.origin = origin self.origin = origin
self.callvalue = callvalue self.callvalue = callvalue
@ -72,5 +69,4 @@ class Environment:
gasprice=self.gasprice, gasprice=self.gasprice,
callvalue=self.callvalue, callvalue=self.callvalue,
origin=self.origin, origin=self.origin,
calldata_type=self.calldata_type,
) )

@ -43,8 +43,12 @@ class Memory:
:return: 32 byte word at the specified index :return: 32 byte word at the specified index
""" """
try: try:
return util.concrete_int_from_bytes( return symbol_factory.BitVecVal(
bytes([util.get_concrete_int(b) for b in self[index : index + 32]]), 0 util.concrete_int_from_bytes(
bytes([util.get_concrete_int(b) for b in self[index : index + 32]]),
0,
),
256,
) )
except: except:
result = simplify( result = simplify(

@ -6,8 +6,11 @@ from datetime import datetime, timedelta
from functools import reduce from functools import reduce
from typing import Callable, Dict, List, Tuple, Union from typing import Callable, Dict, List, Tuple, Union
from mythril.laser.ethereum.cfg import Edge, JumpType, Node, NodeFlags from mythril import alarm
from mythril.laser.ethereum.evm_exceptions import StackUnderflowException, VmException from mythril.exceptions import OutOfTimeError
from mythril.laser.ethereum.cfg import NodeFlags, Node, Edge, JumpType
from mythril.laser.ethereum.evm_exceptions import StackUnderflowException
from mythril.laser.ethereum.evm_exceptions import VmException
from mythril.laser.ethereum.instructions import Instruction from mythril.laser.ethereum.instructions import Instruction
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
@ -50,6 +53,7 @@ class LaserEVM:
create_timeout=10, create_timeout=10,
strategy=DepthFirstSearchStrategy, strategy=DepthFirstSearchStrategy,
transaction_count=2, transaction_count=2,
requires_statespace=True,
): ):
""" """
@ -67,8 +71,6 @@ class LaserEVM:
self.world_state = world_state self.world_state = world_state
self.open_states = [world_state] self.open_states = [world_state]
self.nodes = {}
self.edges = []
self.coverage = {} self.coverage = {}
self.total_states = 0 self.total_states = 0
@ -79,9 +81,14 @@ class LaserEVM:
self.max_depth = max_depth self.max_depth = max_depth
self.transaction_count = transaction_count self.transaction_count = transaction_count
self.execution_timeout = execution_timeout self.execution_timeout = execution_timeout or 0
self.create_timeout = create_timeout self.create_timeout = create_timeout
self.requires_statespace = requires_statespace
if self.requires_statespace:
self.nodes = {}
self.edges = []
self.time = None self.time = None
self.pre_hooks = defaultdict(list) self.pre_hooks = defaultdict(list)
@ -125,37 +132,46 @@ class LaserEVM:
:param contract_name: :param contract_name:
""" """
log.debug("Starting LASER execution") log.debug("Starting LASER execution")
self.time = datetime.now()
if main_address: try:
log.info("Starting message call transaction to {}".format(main_address)) alarm.start_timeout(self.execution_timeout)
self._execute_transactions(main_address) self.time = datetime.now()
elif creation_code: if main_address:
log.info("Starting contract creation transaction") log.info("Starting message call transaction to {}".format(main_address))
created_account = execute_contract_creation( self._execute_transactions(main_address)
self, creation_code, contract_name
) elif creation_code:
log.info( log.info("Starting contract creation transaction")
"Finished contract creation, found {} open states".format( created_account = execute_contract_creation(
len(self.open_states) self, creation_code, contract_name
) )
) log.info(
if len(self.open_states) == 0: "Finished contract creation, found {} open states".format(
log.warning( len(self.open_states)
"No contract was created during the execution of contract creation " )
"Increase the resources for creation execution (--max-depth or --create-timeout)"
) )
if len(self.open_states) == 0:
log.warning(
"No contract was created during the execution of contract creation "
"Increase the resources for creation execution (--max-depth or --create-timeout)"
)
self._execute_transactions(created_account.address)
self._execute_transactions(created_account.address) except OutOfTimeError:
log.warning("Timeout occurred, ending symbolic execution")
finally:
alarm.disable_timeout()
log.info("Finished symbolic execution") log.info("Finished symbolic execution")
log.info( if self.requires_statespace:
"%d nodes, %d edges, %d total states", log.info(
len(self.nodes), "%d nodes, %d edges, %d total states",
len(self.edges), len(self.nodes),
self.total_states, len(self.edges),
) self.total_states,
)
for code, coverage in self.coverage.items(): for code, coverage in self.coverage.items():
cov = ( cov = (
reduce(lambda sum_, val: sum_ + 1 if val else sum_, coverage[1]) reduce(lambda sum_, val: sum_ + 1 if val else sum_, coverage[1])
@ -176,7 +192,11 @@ class LaserEVM:
initial_coverage = self._get_covered_instructions() initial_coverage = self._get_covered_instructions()
self.time = datetime.now() self.time = datetime.now()
log.info("Starting message call transaction, iteration: {}".format(i)) log.info(
"Starting message call transaction, iteration: {}, {} initial states".format(
i, len(self.open_states)
)
)
execute_message_call(self, address) execute_message_call(self, address)
@ -209,15 +229,12 @@ class LaserEVM:
""" """
final_states = [] final_states = []
for global_state in self.strategy: for global_state in self.strategy:
if self.execution_timeout and not create: if (
if ( self.create_timeout
self.time + timedelta(seconds=self.execution_timeout) and create
<= datetime.now() and self.time + timedelta(seconds=self.create_timeout) <= datetime.now()
): ):
return final_states + [global_state] if track_gas else None return final_states + [global_state] if track_gas else None
elif self.create_timeout and create:
if self.time + timedelta(seconds=self.create_timeout) <= datetime.now():
return final_states + [global_state] if track_gas else None
try: try:
new_states, op_code = self.execute_state(global_state) new_states, op_code = self.execute_state(global_state)
@ -423,10 +440,13 @@ class LaserEVM:
old_node = state.node old_node = state.node
state.node = new_node state.node = new_node
new_node.constraints = state.mstate.constraints new_node.constraints = state.mstate.constraints
self.nodes[new_node.uid] = new_node if self.requires_statespace:
self.edges.append( self.nodes[new_node.uid] = new_node
Edge(old_node.uid, new_node.uid, edge_type=edge_type, condition=condition) self.edges.append(
) Edge(
old_node.uid, new_node.uid, edge_type=edge_type, condition=condition
)
)
if edge_type == JumpType.RETURN: if edge_type == JumpType.RETURN:
new_node.flags |= NodeFlags.CALL_RETURN new_node.flags |= NodeFlags.CALL_RETURN

@ -4,7 +4,7 @@ from typing import List, Union
from mythril.disassembler.disassembly import Disassembly from mythril.disassembler.disassembly import Disassembly
from mythril.laser.ethereum.cfg import Node, Edge, JumpType from mythril.laser.ethereum.cfg import Node, Edge, JumpType
from mythril.laser.ethereum.state.calldata import CalldataType, ConcreteCalldata from mythril.laser.ethereum.state.calldata import ConcreteCalldata
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.ethereum.transaction.transaction_models import ( from mythril.laser.ethereum.transaction.transaction_models import (
MessageCallTransaction, MessageCallTransaction,
@ -54,7 +54,6 @@ def execute_message_call(
caller=caller_address, caller=caller_address,
callee_account=open_world_state[callee_address], callee_account=open_world_state[callee_address],
call_data=ConcreteCalldata(next_transaction_id, data), call_data=ConcreteCalldata(next_transaction_id, data),
call_data_type=CalldataType.SYMBOLIC,
call_value=value, call_value=value,
) )
@ -73,10 +72,14 @@ def _setup_global_state_for_execution(laser_evm, transaction) -> None:
global_state = transaction.initial_global_state() global_state = transaction.initial_global_state()
global_state.transaction_stack.append((transaction, None)) global_state.transaction_stack.append((transaction, None))
new_node = Node(global_state.environment.active_account.contract_name) new_node = Node(
global_state.environment.active_account.contract_name,
function_name=global_state.environment.active_function_name,
)
laser_evm.nodes[new_node.uid] = new_node if laser_evm.requires_statespace:
if transaction.world_state.node: laser_evm.nodes[new_node.uid] = new_node
if transaction.world_state.node and laser_evm.requires_statespace:
laser_evm.edges.append( laser_evm.edges.append(
Edge( Edge(
transaction.world_state.node.uid, transaction.world_state.node.uid,
@ -85,6 +88,7 @@ def _setup_global_state_for_execution(laser_evm, transaction) -> None:
condition=None, condition=None,
) )
) )
global_state.node = new_node global_state.node = new_node
new_node.states.append(global_state) new_node.states.append(global_state)
laser_evm.work_list.append(global_state) laser_evm.work_list.append(global_state)

@ -6,11 +6,7 @@ import logging
from mythril.laser.smt import symbol_factory from mythril.laser.smt import symbol_factory
from mythril.disassembler.disassembly import Disassembly from mythril.disassembler.disassembly import Disassembly
from mythril.laser.ethereum.cfg import Node, Edge, JumpType from mythril.laser.ethereum.cfg import Node, Edge, JumpType
from mythril.laser.ethereum.state.calldata import ( from mythril.laser.ethereum.state.calldata import BaseCalldata, SymbolicCalldata
CalldataType,
BaseCalldata,
SymbolicCalldata,
)
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.transaction.transaction_models import ( from mythril.laser.ethereum.transaction.transaction_models import (
MessageCallTransaction, MessageCallTransaction,
@ -53,7 +49,6 @@ def execute_message_call(laser_evm, callee_address: str) -> None:
caller=symbol_factory.BitVecVal(ATTACKER_ADDRESS, 256), caller=symbol_factory.BitVecVal(ATTACKER_ADDRESS, 256),
callee_account=open_world_state[callee_address], callee_account=open_world_state[callee_address],
call_data=SymbolicCalldata(next_transaction_id), call_data=SymbolicCalldata(next_transaction_id),
call_data_type=CalldataType.SYMBOLIC,
call_value=symbol_factory.BitVecSym( call_value=symbol_factory.BitVecSym(
"call_value{}".format(next_transaction_id), 256 "call_value{}".format(next_transaction_id), 256
), ),
@ -99,7 +94,6 @@ def execute_contract_creation(
caller=symbol_factory.BitVecVal(CREATOR_ADDRESS, 256), caller=symbol_factory.BitVecVal(CREATOR_ADDRESS, 256),
callee_account=new_account, callee_account=new_account,
call_data=[], call_data=[],
call_data_type=CalldataType.SYMBOLIC,
call_value=symbol_factory.BitVecSym( call_value=symbol_factory.BitVecSym(
"call_value{}".format(next_transaction_id), 256 "call_value{}".format(next_transaction_id), 256
), ),
@ -120,18 +114,23 @@ def _setup_global_state_for_execution(laser_evm, transaction) -> None:
global_state = transaction.initial_global_state() global_state = transaction.initial_global_state()
global_state.transaction_stack.append((transaction, None)) global_state.transaction_stack.append((transaction, None))
new_node = Node(global_state.environment.active_account.contract_name) new_node = Node(
global_state.environment.active_account.contract_name,
function_name=global_state.environment.active_function_name,
)
if laser_evm.requires_statespace:
laser_evm.nodes[new_node.uid] = new_node
laser_evm.nodes[new_node.uid] = new_node
if transaction.world_state.node: if transaction.world_state.node:
laser_evm.edges.append( if laser_evm.requires_statespace:
Edge( laser_evm.edges.append(
transaction.world_state.node.uid, Edge(
new_node.uid, transaction.world_state.node.uid,
edge_type=JumpType.Transaction, new_node.uid,
condition=None, edge_type=JumpType.Transaction,
condition=None,
)
) )
)
global_state.mstate.constraints += transaction.world_state.node.constraints global_state.mstate.constraints += transaction.world_state.node.constraints
new_node.constraints = global_state.mstate.constraints new_node.constraints = global_state.mstate.constraints

@ -2,11 +2,11 @@
execution.""" execution."""
import array import array
from typing import Union
from z3 import ExprRef from z3 import ExprRef
from typing import Union
from mythril.disassembler.disassembly import Disassembly from mythril.laser.ethereum.state.environment import Environment
from mythril.laser.ethereum.state.calldata import BaseCalldata, SymbolicCalldata
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.calldata import BaseCalldata, SymbolicCalldata from mythril.laser.ethereum.state.calldata import BaseCalldata, SymbolicCalldata
from mythril.laser.ethereum.state.environment import Environment from mythril.laser.ethereum.state.environment import Environment
@ -61,7 +61,6 @@ class BaseTransaction:
gas_limit=None, gas_limit=None,
origin=None, origin=None,
code=None, code=None,
call_data_type=None,
call_value=None, call_value=None,
init_call_data=True, init_call_data=True,
): ):
@ -90,11 +89,6 @@ class BaseTransaction:
else: else:
self.call_data = call_data if isinstance(call_data, BaseCalldata) else None self.call_data = call_data if isinstance(call_data, BaseCalldata) else None
self.call_data_type = (
call_data_type
if call_data_type is not None
else symbol_factory.BitVecSym("call_data_type{}".format(identifier), 256)
)
self.call_value = ( self.call_value = (
call_value call_value
if call_value is not None if call_value is not None
@ -132,7 +126,6 @@ class MessageCallTransaction(BaseTransaction):
self.call_value, self.call_value,
self.origin, self.origin,
code=self.code or self.callee_account.code, code=self.code or self.callee_account.code,
calldata_type=self.call_data_type,
) )
return super().initial_global_state_from_environment( return super().initial_global_state_from_environment(
environment, active_function="fallback" environment, active_function="fallback"
@ -169,7 +162,6 @@ class ContractCreationTransaction(BaseTransaction):
self.call_value, self.call_value,
self.origin, self.origin,
self.code, self.code,
calldata_type=self.call_data_type,
) )
return super().initial_global_state_from_environment( return super().initial_global_state_from_environment(
environment, active_function="constructor" environment, active_function="constructor"

@ -10,7 +10,7 @@ import logging
import os import os
import platform import platform
import re import re
from configparser import ConfigParser import traceback
from pathlib import Path from pathlib import Path
from shutil import copyfile from shutil import copyfile
@ -32,7 +32,13 @@ from mythril.exceptions import CompilerError, CriticalError, NoContractFoundErro
from mythril.solidity.soliditycontract import SolidityContract, get_contracts_from_file from mythril.solidity.soliditycontract import SolidityContract, get_contracts_from_file
from mythril.support import signatures from mythril.support import signatures
from mythril.support.loader import DynLoader from mythril.support.loader import DynLoader
from mythril.support.truffle import analyze_truffle_project from mythril.exceptions import CompilerError, NoContractFoundError, CriticalError
from mythril.analysis.symbolic import SymExecWrapper
from mythril.analysis.callgraph import generate_graph
from mythril.analysis.traceexplore import get_serializable_statespace
from mythril.analysis.security import fire_lasers, retrieve_callback_issues
from mythril.analysis.report import Report
from mythril.ethereum.interface.leveldb.client import EthLevelDB
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -558,23 +564,33 @@ class Mythril(object):
""" """
all_issues = [] all_issues = []
for contract in contracts or self.contracts: for contract in contracts or self.contracts:
sym = SymExecWrapper( try:
contract, sym = SymExecWrapper(
address, contract,
strategy, address,
dynloader=DynLoader( strategy,
self.eth, dynloader=DynLoader(
storage_loading=self.onchain_storage_access, self.eth,
contract_loading=self.dynld, storage_loading=self.onchain_storage_access,
), contract_loading=self.dynld,
max_depth=max_depth, ),
execution_timeout=execution_timeout, max_depth=max_depth,
create_timeout=create_timeout, execution_timeout=execution_timeout,
transaction_count=transaction_count, create_timeout=create_timeout,
modules=modules, transaction_count=transaction_count,
) modules=modules,
compulsory_statespace=False,
issues = fire_lasers(sym, modules) )
issues = fire_lasers(sym, modules)
except KeyboardInterrupt:
log.critical("Keyboard Interrupt")
issues = retrieve_callback_issues(modules)
except Exception:
log.critical(
"Exception occurred, aborting analysis. Please report this issue to the Mythril GitHub page.\n"
+ traceback.format_exc()
)
issues = retrieve_callback_issues(modules)
if type(contract) == SolidityContract: if type(contract) == SolidityContract:
for issue in issues: for issue in issues:

@ -63,6 +63,8 @@ def analyze_truffle_project(sigs, args):
create_timeout=args.create_timeout, create_timeout=args.create_timeout,
execution_timeout=args.execution_timeout, execution_timeout=args.execution_timeout,
transaction_count=args.transaction_count, transaction_count=args.transaction_count,
modules=args.modules or [],
compulsory_statespace=False,
) )
issues = fire_lasers(sym) issues = fire_lasers(sym)

@ -10,7 +10,7 @@ eth-hash>=0.1.0
eth-keyfile>=0.5.1 eth-keyfile>=0.5.1
eth-keys>=0.2.0b3 eth-keys>=0.2.0b3
eth-rlp>=0.1.0 eth-rlp>=0.1.0
eth-tester>=0.1.0b21 eth-tester==0.1.0b32
eth-typing>=2.0.0 eth-typing>=2.0.0
eth-utils>=1.0.1 eth-utils>=1.0.1
jinja2>=2.9 jinja2>=2.9

@ -86,7 +86,7 @@ setup(
"eth-keyfile>=0.5.1", "eth-keyfile>=0.5.1",
"eth-keys>=0.2.0b3", "eth-keys>=0.2.0b3",
"eth-rlp>=0.1.0", "eth-rlp>=0.1.0",
"eth-tester>=0.1.0b21", "eth-tester==0.1.0b32",
"eth-typing>=2.0.0", "eth-typing>=2.0.0",
"coverage", "coverage",
"jinja2>=2.9", "jinja2>=2.9",

@ -75,13 +75,8 @@ def _all_info(laser):
def _test_natives(laser_info, test_list, test_name): def _test_natives(laser_info, test_list, test_name):
success = 0
for i, j in test_list: for i, j in test_list:
if (str(i) in laser_info or str(int(i, 16)) in laser_info) == j: assert (str(i) in laser_info or str(int(i, 16)) in laser_info) == j
success += 1
else:
print("Failed:", str(int(i, 16)), str(j))
assert success == len(test_list)
class NativeTests(BaseTestCase): class NativeTests(BaseTestCase):
@ -99,7 +94,6 @@ class NativeTests(BaseTestCase):
laser_info = str(_all_info(laser)) laser_info = str(_all_info(laser))
print(laser_info)
_test_natives(laser_info, SHA256_TEST, "SHA256") _test_natives(laser_info, SHA256_TEST, "SHA256")
_test_natives(laser_info, RIPEMD160_TEST, "RIPEMD160") _test_natives(laser_info, RIPEMD160_TEST, "RIPEMD160")
_test_natives(laser_info, ECRECOVER_TEST, "ECRECOVER") _test_natives(laser_info, ECRECOVER_TEST, "ECRECOVER")

Loading…
Cancel
Save