@ -18,13 +18,11 @@ from mythril.laser.smt import (
ULT ,
UGT ,
BitVec ,
is_true ,
is_false ,
URem ,
SRem ,
If ,
Bool ,
Or ,
Not ,
LShR ,
)
@ -41,7 +39,6 @@ from mythril.laser.ethereum.evm_exceptions import (
OutOfGasException ,
)
from mythril . laser . ethereum . gas import OPCODE_GAS
from mythril . laser . ethereum . keccak import KeccakFunctionManager
from mythril . laser . ethereum . state . global_state import GlobalState
from mythril . laser . ethereum . transaction import (
MessageCallTransaction ,
@ -56,8 +53,6 @@ log = logging.getLogger(__name__)
TT256 = 2 * * 256
TT256M1 = 2 * * 256 - 1
keccak_function_manager = KeccakFunctionManager ( )
class StateTransition ( object ) :
""" Decorator that handles global state copy and original return.
@ -193,7 +188,6 @@ class Instruction:
if not post
else getattr ( self , op + " _ " + " post " , None )
)
if instruction_mutator is None :
raise NotImplementedError
@ -417,6 +411,7 @@ class Instruction:
* helper . pop_bitvec ( global_state . mstate )
)
)
return [ global_state ]
@StateTransition ( )
@ -552,11 +547,15 @@ class Instruction:
state . stack . append (
global_state . new_bitvec (
" ( " + str ( simplify ( base ) ) + " )**( " + str ( simplify ( exponent ) ) + " ) " ,
" invhash( "
+ str ( hash ( simplify ( base ) ) )
+ " )**invhash( "
+ str ( hash ( simplify ( exponent ) ) )
+ " ) " ,
256 ,
base . annotations + exponent . annotations ,
)
)
) # Hash is used because str(symbol) takes a long time to be converted to a string
else :
state . stack . append (
@ -774,13 +773,8 @@ class Instruction:
if size > 0 :
try :
state . mem_extend ( mstart , size )
except TypeError :
log . debug (
" Memory allocation error: mstart = "
+ str ( mstart )
+ " , size = "
+ str ( size )
)
except TypeError as e :
log . debug ( " Memory allocation error: {} " . format ( e ) )
state . mem_extend ( mstart , 1 )
state . memory [ mstart ] = global_state . new_bitvec (
" calldata_ "
@ -893,7 +887,6 @@ class Instruction:
: param global_state :
: return :
"""
global keccak_function_manager
state = global_state . mstate
op0 , op1 = state . stack . pop ( ) , state . stack . pop ( )
@ -936,7 +929,7 @@ class Instruction:
for b in state . memory [ index : index + length ] :
if isinstance ( b , BitVec ) :
annotations . append ( b . annotations )
annotations + = b . annotations
argument_str = str ( state . memory [ index ] ) . replace ( " " , " _ " )
result = symbol_factory . BitVecFuncSym (
@ -948,7 +941,6 @@ class Instruction:
)
log . debug ( " Created BitVecFunc hash. " )
keccak_function_manager . add_keccak ( result , state . memory [ index ] )
else :
keccak = utils . sha3 ( data . value . to_bytes ( length , byteorder = " big " ) )
result = symbol_factory . BitVecFuncVal (
@ -1318,21 +1310,19 @@ class Instruction:
state = global_state . mstate
op0 = state . stack . pop ( )
log . debug ( " MLOAD[ " + str ( op0 ) + " ] " )
try :
offset = util . get_concrete_int ( op0 )
except TypeError :
log . debug ( " Can ' t MLOAD from symbolic index " )
data = global_state . new_bitvec ( " mem[ " + str ( simplify ( op0 ) ) + " ] " , 256 )
data = global_state . new_bitvec (
" mem[invhash( " + str ( hash ( simplify ( op0 ) ) ) + " )] " , 256
)
state . stack . append ( data )
return [ global_state ]
state . mem_extend ( offset , 32 )
data = state . memory . get_word_at ( offset )
log . debug ( " Load from memory[ " + str ( offset ) + " ]: " + str ( data ) )
state . stack . append ( data )
return [ global_state ]
@ -1355,9 +1345,7 @@ class Instruction:
try :
state . mem_extend ( mstart , 32 )
except Exception :
log . debug ( " Error extending memory, mstart = " + str ( mstart ) + " , size = 32 " )
log . debug ( " MSTORE to mem[ " + str ( mstart ) + " ]: " + str ( value ) )
log . debug ( " Error extending memory " )
state . memory . write_word_at ( mstart , value )
@ -1387,7 +1375,6 @@ class Instruction:
) # type: Union[int, BitVec]
except TypeError : # BitVec
value_to_write = Extract ( 7 , 0 , value )
log . debug ( " MSTORE8 to mem[ " + str ( offset ) + " ]: " + str ( value_to_write ) )
state . memory [ offset ] = value_to_write
@ -1400,86 +1387,13 @@ class Instruction:
: param global_state :
: return :
"""
global keccak_function_manager
state = global_state . mstate
index = state . stack . pop ( )
log . debug ( " Storage access at index " + str ( index ) )
try :
index = util . get_concrete_int ( index )
return self . _sload_helper ( global_state , index )
except TypeError :
if not keccak_function_manager . is_keccak ( index ) :
return self . _sload_helper ( global_state , str ( index ) )
storage_keys = global_state . environment . active_account . storage . keys ( )
keccak_keys = list ( filter ( keccak_function_manager . is_keccak , storage_keys ) )
results = [ ] # type: List[GlobalState]
constraints = [ ]
for keccak_key in keccak_keys :
key_argument = keccak_function_manager . get_argument ( keccak_key )
index_argument = keccak_function_manager . get_argument ( index )
constraints . append ( ( keccak_key , key_argument == index_argument ) )
for ( keccak_key , constraint ) in constraints :
if constraint in state . constraints :
results + = self . _sload_helper (
global_state , keccak_key , [ constraint ]
)
if len ( results ) > 0 :
return results
for ( keccak_key , constraint ) in constraints :
results + = self . _sload_helper (
copy ( global_state ) , keccak_key , [ constraint ]
)
if len ( results ) > 0 :
return results
return self . _sload_helper ( global_state , str ( index ) )
@staticmethod
def _sload_helper (
global_state : GlobalState , index : Union [ str , int ] , constraints = None
) :
"""
: param global_state :
: param index :
: param constraints :
: return :
"""
try :
data = global_state . environment . active_account . storage [ index ]
except KeyError :
data = global_state . new_bitvec ( " storage_ " + str ( index ) , 256 )
global_state . environment . active_account . storage [ index ] = data
if constraints is not None :
global_state . mstate . constraints + = constraints
global_state . mstate . stack . append ( data )
state . stack . append ( global_state . environment . active_account . storage [ index ] )
return [ global_state ]
@staticmethod
def _get_constraints ( keccak_keys , this_key , argument ) :
"""
: param keccak_keys :
: param this_key :
: param argument :
"""
global keccak_function_manager
for keccak_key in keccak_keys :
if keccak_key == this_key :
continue
keccak_argument = keccak_function_manager . get_argument ( keccak_key )
yield keccak_argument != argument
@StateTransition ( )
def sstore_ ( self , global_state : GlobalState ) - > List [ GlobalState ] :
"""
@ -1487,90 +1401,10 @@ class Instruction:
: param global_state :
: return :
"""
global keccak_function_manager
state = global_state . mstate
index , value = state . stack . pop ( ) , state . stack . pop ( )
log . debug ( " Write to storage[ " + str ( index ) + " ] " )
try :
index = util . get_concrete_int ( index )
return self . _sstore_helper ( global_state , index , value )
except TypeError :
is_keccak = keccak_function_manager . is_keccak ( index )
if not is_keccak :
return self . _sstore_helper ( global_state , str ( index ) , value )
storage_keys = global_state . environment . active_account . storage . keys ( )
keccak_keys = filter ( keccak_function_manager . is_keccak , storage_keys )
results = [ ] # type: List[GlobalState]
new = symbol_factory . Bool ( False )
for keccak_key in keccak_keys :
key_argument = keccak_function_manager . get_argument (
keccak_key
) # type: Expression
index_argument = keccak_function_manager . get_argument (
index
) # type: Expression
condition = key_argument == index_argument
condition = (
condition
if type ( condition ) == bool
else is_true ( simplify ( cast ( Bool , condition ) ) )
)
if condition :
return self . _sstore_helper (
copy ( global_state ) ,
keccak_key ,
value ,
key_argument == index_argument ,
)
results + = self . _sstore_helper (
copy ( global_state ) ,
keccak_key ,
value ,
key_argument == index_argument ,
)
new = Or ( new , cast ( Bool , key_argument != index_argument ) )
if len ( results ) > 0 :
results + = self . _sstore_helper (
copy ( global_state ) , str ( index ) , value , new
)
return results
return self . _sstore_helper ( global_state , str ( index ) , value )
@staticmethod
def _sstore_helper ( global_state , index , value , constraint = None ) :
"""
: param global_state :
: param index :
: param value :
: param constraint :
: return :
"""
try :
global_state . environment . active_account = deepcopy (
global_state . environment . active_account
)
global_state . accounts [
global_state . environment . active_account . address . value
] = global_state . environment . active_account
global_state . environment . active_account . storage [ index ] = (
value if not isinstance ( value , Expression ) else simplify ( value )
)
except KeyError :
log . debug ( " Error writing to storage: Invalid index " )
if constraint is not None :
global_state . mstate . constraints . append ( constraint )
global_state . environment . active_account . storage [ index ] = value
return [ global_state ]
@StateTransition ( increment_pc = False , enable_gas = False )