Esempio n. 1
0
def ether_leak(op, stack, trace, debug):

    global s

    # CALL leaks
    if op == 'CALL' and len(
            stack) >= 7 and stack[-2]['type'] == 'constant' and stack[-3]['type'] == 'constant':
        MyGlobals.s.push()
        # CALL sent address coincides with our address
        MyGlobals.s.add(
            stack[-2]['z3'] == BitVecVal(int(get_params('my_address', ''), 16), 256))
        # amount of Ether sent is > 0
        MyGlobals.s.add(stack[-3]['z3'] > 0)
        try:
            if MyGlobals.s.check() == sat:

                # Search condition found but keep expanding the search tree to make sure that the execution ends normally,
                # i.e. with STOP/RETURN/SUICIDE
                return True, False

        except Exception as e:
            print("Exception: " + str(e))

        MyGlobals.s.pop()

    # SUICIDE leaks
    if op == 'SUICIDE' and len(stack) >= 1 and stack[-1]['type'] == 'constant':

        MyGlobals.s.push()
        # SUICIDE send address coincides with our address
        MyGlobals.s.add(
            stack[-1]['z3'] == BitVecVal(int(get_params('my_address', ''), 16), 256))

        try:
            if MyGlobals.s.check() == sat:

                # Once SUICIDE is executed, then no need to look for the final STOP or RETURN
                # because SUICIDE is already a stopping instruction
                global stop_search
                MyGlobals.stop_search = True

                return True, True

        except Exception as e:
            print("Exception: " + str(e))

        MyGlobals.s.pop()

    return False, False
Esempio n. 2
0
def execute( code, stack, pos, storage, mmemory, data, trace, calldepth, debug, read_from_blockchain  ):
    op = code[pos]['o']
    halt = False
    executed = True
    step = code[pos]['id']

    if op not in allops:
        print('Unknown operation %s at pos %x' % (op,pos) )
        return pos,True

    # check if stack has enough elements
    if allops[op][1] > len(stack): 
        if debug: print('Not enough entries in the stack to execute the operation %8s  at step %x: required %d, provided %d' % (op,code[pos]['id'], allops[op][1], len(stack)) )
        return pos, True
    start_stack_size = len(stack)
    final_stack_size = len(stack) - allops[op][1] + allops[op][2]

    # get arguments from the stack
    # the cases of DUP and SWAP are different, so avoid those
    args = []
    if op.find('SWAP') < 0 and op.find('DUP') < 0 and op not in ['JUMPI']:
        for i in range( allops[op][1] ): args.append( stack.pop() )
    

    # all unary
    if op in ['ISZERO','NOT']: 
        stack.append( unary ( args[0] ,step, op ) )
        
    # all binary except SIGNEXTEND
    elif op in ['ADD','MUL','SUB','DIV','SDIV','MOD','SMOD','EXP','AND','OR','XOR', 'LT','GT','SLT','SGT','EQ']:
        stack.append( binary (  args[0] , args[1] , step , op ) )

    # all ternary
    elif op in ['ADDMOD','MULMOD']:
        stack.append( ternary( args[0], args[1], args[2], step, op ) )

    elif op == 'SIGNEXTEND':

        if not is_fixed(args[0]) or not is_fixed(args[1]): 
            stack.append( {'type':'undefined','step':step} )

        else:

            o = get_value(args[1])
            t = 256 - 8*( get_value(args[0]) + 1 )
            tbit = (o >> t ) & 1
            n = 0
            for i in range(256):
                n ^= (tbit if i<= t else ((o>>i)&1)) << i
            stack.append( {'type':'undefined','step':step, 'z3':BitVecVal( n, 256 ) } )


    elif op == 'SHA3':


        addr  = simplify(args[0]['z3'])
        offset= simplify(args[1]['z3'])

        exact_address = addr.as_long() if is_bv_value(addr) else -1
        exact_offset  = offset.as_long() if is_bv_value(offset) else -1

        res = {'type':'undefined','step':step}

        if exact_address >= 0 and exact_offset >= 0:
            if (exact_offset % 32) == 0 :     # for now, can deal only with offsets divisible by 32


                val = ''
                all_good = True
                for i in range(exact_offset/32):
                    if (exact_address + i*32) not in mmemory or not is_fixed(mmemory[exact_address+i*32]): 
                        all_good = False
                        break
                    val += '%064x' % get_value(mmemory[exact_address + i*32])

                if all_good:

                    k = keccak_256()
                    k.update(val.encode('utf-8'))
                    digest = k.hexdigest()
                    res = {'type':'constant','step':step, 'z3':BitVecVal(int(digest,16), 256) }

        if MyGlobals.symbolic_sha and is_undefined(res):
            res = {'type':'constant','step':step, 'z3': BitVec('sha-'+str(step)+'-'+str(calldepth),256) }

        stack.append( res )



    elif op.find('PUSH') >= 0: stack.append( {'type':'constant','step':step, 'z3':BitVecVal(int(code[pos]['input'],16), 256)} )
    elif op.find('DUP' ) >= 0: stack.append( copy.deepcopy( stack[-int(op[3:]) ] ) )


    elif op.find('SWAP') >= 0:
        tmp1 = stack[-1]
        tmp2 = stack[-int(op[4:])-1 ]
        stack[-1] = tmp2
        stack[-int(op[4:]) -1] = tmp1


    # assign symbolic variable to some of the parameters (such as CALLVALUE, TIMESTAMP,  etc)
    # only if they are selected to get one
    # otherwise, below, they will get fixed value (BitVecVal) as specified
    elif op in MyGlobals.symbolic_vars:
        stack.append( {'type':'constant','step':step, 'z3': BitVec(op+'-'+str(calldepth),256) } ) 




    elif op == 'NUMBER':        stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('block_number',''),16), 256)} )
    elif op == 'GASLIMIT':      stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('gas_limit',''),16), 256)} )
    elif op == 'TIMESTAMP':     stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('time_stamp',''),16), 256)} )
    elif op == 'CALLVALUE':     stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('call_value',''),16), 256)} )
    elif op == 'ADDRESS':       stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('contract_address',''), 16), 256)} )
    elif op == 'ORIGIN':        stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('contract_address',''), 16), 256)} )
    elif op == 'GASPRICE':      stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('gas_price',''), 16), 256) } )
    elif op == 'COINBASE':      stack.append( {'type':'constant','step':step, 'z3': BitVecVal(0,256)} )
    elif op == 'DIFFICULTY':    stack.append( {'type':'constant','step':step, 'z3': BitVecVal(0,256)} )
    elif op == 'CALLER':        stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('my_address',''), 16), 256) } )
    elif op == 'GAS':           stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('gas',''),16), 256) } )
    elif op == 'MSIZE':         stack.append( {'type':'constant','step':step, 'z3': BitVecVal(len(mmemory), 256) } )
    elif op == 'BLOCKHASH':     stack.append( {'type':'constant','step':step, 'z3': BitVecVal(0x123,256)} ) # does not use the argument which specifies the blocknumber
    elif op == 'BALANCE':       stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('contract_balance',''), 10), 256)} )        # always assume that it is the balance of the current contract
    elif op == 'POP':           pass
    elif op.find('LOG') >= 0:   pass
    elif op == 'CODECOPY':      pass

    elif op == 'JUMPDEST':      
        if not is_good_jump(code, pos, debug): 
            return pos, True

    elif op in ['STOP','RETURN','REVERT', 'INVALID', 'SUICIDE']:    halt = True

    elif op in ['CALLDATALOAD']:

        addr = args[0]

        if is_fixed( addr ):

            addr = get_value(addr)

            # If symmbolic variable does not exist, then create it  
            if ('data-'+str(calldepth)+'-' + str(addr)) not in data:
                data['data-'+str(calldepth)+'-' + str(addr)] = BitVec('input'+str(calldepth)+'['+str(addr)+']', 256)

            stack.append( {'type':'constant','step':step, 'z3':data['data-'+str(calldepth)+'-' + str(addr)] } )

        elif is_undefined(addr):

            if debug:
                print ('\033[95m[-] In CALLDATALOAD the input address cannot be determined at step %x: \033[0m' % code[pos]['id'] )
                print( addr )
            return pos, True

        #
        # if the address is not fixed (symbolic expression) then assume we are dealing with dynamic array
        # and input[ address ] is the length of the array
        else:

            stack.append( args[0] )

            return pos, False




    elif op in ['CALLDATASIZE']:

        return pos, False



    elif op == 'CALL':

        if is_fixed(args[5]) and is_fixed(args[6]):
            addr  = get_value( args[5] )
            value = get_value( args[6] )


            if value < 10000:
                for i in range(value/32):
                    mmemory[addr + 32 * i] = { 'type':'undefined','step':step }

        stack.append( {'type':'constant','step':step, 'z3':BitVec('call_at_step_'+str(step), 256) & 0x1} )     # assume the result of call can be any (True or False)


    elif op == 'CALLDATACOPY': 

        memaddr = args[0]  
        datapos = args[1]
        length  = args[2]

        if not is_fixed(memaddr) or not is_fixed( datapos ) or not is_fixed( length ):
            if debug: 
                print('\033[95m[-] In CALLDATACOPY the memory address or datapos or length cannot be determined \033[0m' )
                print(memaddr)
                print(datapos)
                print(length)
            return pos, True

        memaddr = get_value ( memaddr )
        datapos = get_value ( datapos )
        length  = get_value ( length  )


        if length % 32 != 0:
            if debug:
                print('\033[95m[-] In CALLDATACOPY the length of array (%d) is not multiple of 32 \033[0m' % length )
            return pos, True

        for i in range( length / 32 ):
            data[ datapos + 32 * i ] = BitVec('input'+str(calldepth)+'['+str(datapos + 32 * i )+']',256)
            store_in_memory( mmemory, memaddr + 32 * i , {'type':'constant','step':step,'z3':data[ datapos + 32 * i ]} )

        # Truncate the storing only to 32 byte values


    elif op == 'CALLCODE':          stack.append( {'type':'constant','step':step, 'z3':BitVecVal(0,256)} )
    elif op == 'DELEGATECALL':      stack.append( {'type':'constant','step':step, 'z3':BitVecVal(0,256)} )
    elif op == 'EXTCODESIZE':       stack.append( {'type':'constant','step':step, 'z3':BitVecVal(0,256)} )
    elif op == 'CREATE': stack.append( {'type':'constant','step':step, 'z3':BitVecVal(0,256)} )

    elif op == 'MLOAD':
        addr = args[0]


        if is_undefined(addr):
            if debug:print('\033[95m[-] The MLOAD address on %x  cannot be determined\033[0m' % code[pos]['id'] )
            return pos, True

        addr = simplify(addr['z3'])

        if is_bv_value(addr):

            exact_address = addr.as_long()
            if exact_address in mmemory: res = copy.deepcopy(mmemory[exact_address])
            else: 
                res = {'type':'constant','step':step, 'z3': BitVecVal(0, 256) }
            stack.append( res )

        else:
            if debug:print('\033[95m[-] The MLOAD address on %x  cannot be determined\033[0m' % code[pos]['id'] )
            return pos, True


    elif op == 'MSTORE':


        addr = args[0]
        if is_undefined(addr) or not is_bv_value( simplify(addr['z3']) ) :
            if debug:print('\033[95m[-] The MSTORE the write address on %x  cannot be determined\033[0m' % code[pos]['id'] )
            return pos, True

        t = copy.deepcopy( args[1] )
        addr = get_value(addr)

        store_in_memory( mmemory, addr, t )


    elif op in ['MSTORE8']:
        addr = args[0]
        value= args[1]

        if not is_fixed(addr) :
            if debug:print('\033[95m[-] The MSTORE8 the write address on %x  cannot be determined\033[0m' % code[pos]['id'] )
            return pos, True
        if not is_fixed(value) :
            if debug:print('\033[95m[-] The MSTORE8 value is undefined \033[0m' % code[pos]['id'] )
            return pos, True

        ea = get_value(addr)
        ev = get_value(value) % 256

        if (ea/32)*32 not in mmemory: 
            mmemory[(ea/32)*32] = {'type':'constant','step':step, 'z3':BitVecVal(ev << (31- (ea%32)), 256) }
        elif is_fixed( mmemory[(ea/32)*32]['z3'] ):
            v = get_value( mmemory[(ea/32)*32]['z3'] )
            v = (v & (~BitVecVal(0xff,256) << (31- (ea%32)))) ^ (ev << (31- (ea%32)))
            mmemory[(ea/32)*32]['z3'] = v


    elif op == 'SLOAD':


        addr = args[0]

        if is_undefined(addr):
            if debug:print('\033[95m[-] The SLOAD address on %x  cannot be determined\033[0m' % code[pos]['id'] )
            return pos, True

        addr = simplify(addr['z3'])

        if is_bv_value(addr):

            exact_address = addr.as_long()
            if exact_address in storage:
                total_values = len(storage[exact_address])
                if total_values == 0:
                    print('In SLOAD the list at address %x has no elements ' % exact_address)
                    exit(0)
                    return pos, True
                else:
                    res = copy.deepcopy(storage[exact_address][0])
            else:
                if MyGlobals.web3 is not None and read_from_blockchain:
                    value = MyGlobals.web3.eth.getStorageAt( get_params('contract_address',''), exact_address )
                else:
                    value = '0'

                t = {'type':'constant','step':step, 'z3': BitVecVal(int(value,16), 256) }

                storage[exact_address] = [ t ]
                res = copy.deepcopy(t)

            stack.append( res )

        else:
            if MyGlobals.symbolic_load:
                stack.append({'type':'constant','step':step, 'z3': BitVec('sload-'+str(step)+'-'+str(calldepth),256) } )
            else:
                if debug:print('\033[95m[-] The SLOAD address on %x  cannot be determined\033[0m' % code[pos]['id'] )
                return pos, True



    elif op == 'SSTORE':


        addr = args[0]
        if is_undefined(addr):
            if debug:print('\033[95m[-] The SSTORE address on %x  cannot be determined\033[0m' % code[pos]['id'] )
            return pos, True

        t = copy.deepcopy( args[1] )

        if is_bv_value( simplify(addr['z3']) ):
            va = get_value( addr )
            storage[va] = [t];

        else:
            if MyGlobals.symbolic_load:
                pass
            else:
                if debug:
                    print ('\033[95m[-] In SSTORE the write address cannot be determined at step %x: \033[0m' % code[pos]['id'] )
                    print( addr )
                return pos, True
            
    elif op == 'JUMP':

        addr = args[0]

        if not is_fixed( addr ):
            if debug: print('\033[95m[-] In JUMP the address cannot be determined \033[0m'  )
            return pos, True
        
        jump_dest = get_value( addr )
        if( jump_dest <= 0):
            if debug: print('\033[95m[-] The JUMP destination is not a valid address : %x\033[0m'  % jump_dest )
            return pos, True
        
        new_position= find_pos(code, jump_dest )

        if( new_position < 0):
            if debug: print('\033[95m[-] The code has no such JUMP destination: %s at line %x\033[0m' % (hex(jump_dest), code[pos]['id']) )
            return pos, True

        if not is_good_jump(code, new_position, debug): 
            return pos, True


        return new_position, False


    elif op == 'JUMPI': return pos , False

    elif op == 'BYTE':
        byte_no = args[0]
        word    = args[1]
        if is_undefined(word) or is_undefined(byte_no): 
            res = {'type':'undefined','step':step}
        else:                                           
            res = {'type':'constant','step':step, 'z3': (word['z3'] >> (8*(31-byte_no['z3'])) ) & 0xff }

        stack.append( res )

    else:
        executed = False




    if executed and final_stack_size != len(stack):
        print('Incorrect final stack size after executing %s at step %x' % (op,step))
        print(len(stack))
        print(final_stack_size)
        exit(2)

    return pos + 1, halt
Esempio n. 3
0
	def execute(self, code, stack, pos, storage, mmemory, data, trace, calldepth, function_hash, actual_key, search_enhance, debug, read_from_blockchain  ):

		# Stop the search once it exceeds timeout
		time_now = datetime.datetime.now()
		if MyGlobals.ONE_HB_TIMEOUT < int((time_now - MyGlobals.Time_checkpoint).total_seconds()):
			MyGlobals.stop_search = True
			return pos , True

		if debug: print_stack(stack)

		op = code[pos]['o']
		halt = False
		executed = True
		step = code[pos]['id']

		# for statistics
		if (not search_enhance) and op in ['CALL', 'CODESIZE', 'CODECOPY', 'EXTCODESIZE', 'EXTCODECOPY', 'RETURNDATASIZE', 'RETURNDATACOPY', 'DIFFICULTY', 'GAS', 'CREATE', 'CALLCODE', 'DELEGATECALL', 'STATICCALL', 'LOG0', 'LOG1', 'LOG2', 'LOG3', 'LOG4']:
			if op in MyGlobals.notimplemented_ins:
				MyGlobals.notimplemented_ins[op]+=1
			else:
				MyGlobals.notimplemented_ins[op]=1

		if (not search_enhance):
			if op in ['CALL', 'SSTORE', 'SLOAD', 'MSTORE8', 'MLOAD', 'JUMP', 'JUMPI']:
				if op+'_all' in MyGlobals.notimplemented_ins:
					MyGlobals.notimplemented_ins[op+'_all']+=1
				else:
					MyGlobals.notimplemented_ins[op+'_all']=1

			if 'total' in MyGlobals.notimplemented_ins:
				MyGlobals.notimplemented_ins['total']+=1
			else:
				MyGlobals.notimplemented_ins['total']=1		
					

		key = 0
		if actual_key in [1, 4]: key = 1
		if actual_key in [2, 3]: key = 2

		if op not in allops:
			print('Unknown operation %s at pos %x' % (op,pos) )
			return pos,True

		# check if stack has enough elements
		if allops[op][1] > len(stack): 
			if debug: print('Not enough entries in the stack to execute the operation %8s  at step %x: required %d, provided %d' % (op,code[pos]['id'], allops[op][1], len(stack)) )
			return pos, True
		start_stack_size = len(stack)
		final_stack_size = len(stack) - allops[op][1] + allops[op][2]

		# get arguments from the stack
		# the cases of DUP and SWAP are different, so avoid those
		args = []
		if op.find('SWAP') < 0 and op.find('DUP') < 0 and op not in ['JUMPI']:
			for i in range( allops[op][1] ): args.append( stack.pop() )
		

		# all unary
		if op in ['ISZERO','NOT']: 
			stack.append( self._unary ( args[0] ,step, op ) )
			
		# all binary except SIGNEXTEND
		elif op in ['ADD','MUL','SUB','DIV','SDIV','MOD','SMOD','EXP','AND','OR','XOR', 'LT','GT','SLT','SGT','EQ']:
			stack.append( self._binary (  args[0] , args[1] , step , op ) )

		# all ternary
		elif op in ['ADDMOD','MULMOD']:
			stack.append( self._ternary( args[0], args[1], args[2], step, op ) )

		elif op == 'SIGNEXTEND':

			if not self.is_fixed(args[0]) or not self.is_fixed(args[1]): 
				stack.append( {'type':'undefined','step':step} )

			else:

				o = self.get_value(args[1])
				t = 256 - 8*( self.get_value(args[0]) + 1 )
				tbit = (o >> t ) & 1
				n = 0
				for i in range(256):
					n ^= (tbit if i<= t else ((o>>i)&1)) << i
				stack.append( {'type':'undefined','step':step, 'z3':BitVecVal( n, 256 ) } )


		elif op == 'SHA3':


			addr  = simplify(args[0]['z3'])
			offset= simplify(args[1]['z3'])

			exact_address = addr.as_long() if is_bv_value(addr) else -1
			exact_offset  = offset.as_long() if is_bv_value(offset) else -1
			# for statistics
			if exact_address==-1:
				if (not search_enhance):
					if 'sha3_addr' in MyGlobals.notimplemented_ins:
						MyGlobals.notimplemented_ins['sha3_addr']+=1
					else:
						MyGlobals.notimplemented_ins['sha3_addr']=1

			if exact_offset==-1:
				if 'sha3_offset' in MyGlobals.notimplemented_ins:
					MyGlobals.notimplemented_ins['sha3_offset']+=1
				else:
					MyGlobals.notimplemented_ins['sha3_offset']=1		


			res = {'type':'undefined','step':step}

			changed_offset = exact_address
		
			if (exact_offset - exact_address)//32 >= 2 : changed_offset = exact_offset//2
		
			if exact_address >= 0 and exact_offset >= 0:
		
				if (exact_offset % 32) == 0 :     # for now, can deal only with offsets divisible by 32
					val = ''
					all_good = True
					sha3val = 0
					for i in range(exact_offset//32):
						if (exact_address + i*32) not in mmemory or not self.is_fixed(mmemory[exact_address+i*32]): 
							all_good = False
							break
						val += '%064x' % self.get_value(mmemory[exact_address + i*32])

					if all_good:

						k = keccak_256()
						# print('hereee', val, '\n')
						# k.update(val.decode('hex'))
						k.update((codecs.decode(val, 'hex')))
						digest = k.hexdigest()
						res = {'type':'constant','step':step, 'z3':BitVecVal(int(digest,16), 256) }
						sha3val = int(digest,16)
						

					else: 
						# for statistics
						if (not search_enhance):
							if exact_address==-1:
								if 'sha3_addr' in MyGlobals.notimplemented_ins:
									MyGlobals.notimplemented_ins['sha3_mem']+=1
								else:
									MyGlobals.notimplemented_ins['sha3_mem']=1

						if search_enhance and is_bv_value(simplify(mmemory[changed_offset]['z3'])):
							temp_key = remove0x(hex(mmemory[changed_offset]['z3'].as_long()).rstrip('L'))
							if not 'SHA3'+'-'+str(step)+'-'+function_hash in MyGlobals.sha3vardata:
								MyGlobals.sha3vardata['SHA3'+'-'+str(step)+'-'+function_hash] = []
								MyGlobals.sha3vardata['SHA3'+'-'+str(step)+'-'+function_hash].append(temp_key)	
							
							else:
								if not temp_key in MyGlobals.sha3vardata['SHA3'+'-'+str(step)+'-'+function_hash]:
									MyGlobals.sha3vardata['SHA3'+'-'+str(step)+'-'+function_hash].append(temp_key)


						stack.append(args[1])
						stack.append(args[0])
						return pos, False    
			
			if search_enhance and is_bv_value(simplify(mmemory[changed_offset]['z3'])):
				temp_key = remove0x(hex(mmemory[changed_offset]['z3'].as_long()).rstrip('L'))
				if not sha3val in MyGlobals.sha3vardata:
					MyGlobals.sha3vardata[sha3val] = []
					MyGlobals.sha3vardata[sha3val].append(temp_key)

				else:
					if not temp_key in MyGlobals.sha3vardata[sha3val]:
						MyGlobals.sha3vardata[sha3val].append(temp_key)
			


			stack.append( res )



		elif op.find('PUSH') >= 0: stack.append( {'type':'constant','step':step, 'z3':BitVecVal(int(code[pos]['input'],16), 256)} )
		elif op.find('DUP' ) >= 0: stack.append( copy.deepcopy( stack[-int(op[3:]) ] ) )


		elif op.find('SWAP') >= 0:
			tmp1 = stack[-1]
			tmp2 = stack[-int(op[4:])-1 ]
			stack[-1] = tmp2
			stack[-int(op[4:]) -1] = tmp1


		# assign symbolic variable to some of the parameters (such as CALLVALUE, TIMESTAMP,  etc)
		# only if they are selected to get one
		# otherwise, below, they will get fixed value (BitVecVal) as specified
		elif op in MyGlobals.symbolic_vars:
			stack.append( {'type':'constant','step':step, 'z3': BitVec(op+'-'+str(calldepth)+'-'+function_hash,256) } ) 

		elif op == 'NUMBER':        stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('block_number',''),16), 256)} )
		elif op == 'GASLIMIT':      stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('gas_limit',''),16), 256)} )
		elif op == 'TIMESTAMP':     stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('time_stamp',''),16), 256)} )
		elif op == 'CALLVALUE':     stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('call_value',''),16), 256)} )
		elif op == 'ADDRESS':       stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('contract_address',''), 16), 256)} )
		elif op == 'ORIGIN':        stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('contract_address',''), 16), 256)} )
		elif op == 'GASPRICE':      stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('gas_price',''), 16), 256) } )
		elif op == 'COINBASE':      stack.append( {'type':'constant','step':step, 'z3': BitVecVal(0,256)} )
		elif op == 'DIFFICULTY':    stack.append( {'type':'constant','step':step, 'z3': BitVecVal(0,256)} )
		elif op == 'CALLER':        stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('my_address',''), 16), 256) } )
		elif op == 'GAS':           stack.append( {'type':'constant','step':step, 'z3': BitVecVal(int(get_params('gas',''),16), 256) } )
		elif op == 'MSIZE':         stack.append( {'type':'constant','step':step, 'z3': BitVecVal(len(mmemory), 256) } )
		elif op == 'BLOCKHASH':     stack.append( {'type':'constant','step':step, 'z3': BitVecVal(0x123,256)} ) # does not use the argument which specifies the blocknumber
		elif op == 'BALANCE':       stack.append( {'type':'constant','step':step, 'z3': BitVecVal(10**25, 256)} )        # always assume that it is the balance of the current contract
		elif op == 'POP':           pass
		elif op.find('LOG') >= 0:   pass
		elif op == 'CODECOPY':      pass

		elif op == 'JUMPDEST':      
			return pos+1, False

		elif op in ['STOP','RETURN','REVERT', 'INVALID']: 	halt = True

		elif op in 'SUICIDE':
			if search_enhance:
				if not function_hash in MyGlobals.funcvardata:
					MyGlobals.funcvardata[function_hash] = {}
					MyGlobals.funcvardata[function_hash]['bal'] = []
					MyGlobals.funcvardata[function_hash]['bal'].append('W')
					
				else:
					if not 'bal' in MyGlobals.funcvardata[function_hash]:
						MyGlobals.funcvardata[function_hash]['bal'] = []
						MyGlobals.funcvardata[function_hash]['bal'].append('W')

					else:
						if not 'W' in MyGlobals.funcvardata[function_hash]['bal']:
							MyGlobals.funcvardata[function_hash]['bal'].append('W')
			halt = True

		elif op in ['CALLDATALOAD']:

			addr = args[0]

			if self.is_fixed( addr ):
				addr = self.get_value(addr)

				if addr == 0:
					# If fallback function append 0 to the stack
					if function_hash in ['11111111', '22222222']:
						stack.append( {'type':'constant','step':step, 'z3':BitVecVal(0, 256) } )   
					
					else:         
						stack.append( {'type':'constant','step':step, 'z3':BitVecVal(int(function_hash.ljust(64, '0'), 16), 256) } )

			# If symmbolic variable does not exist, then create it  
				else:

					if ('data-'+str(key)+'-' + str(addr)+'-'+function_hash) not in data:
						data['data-'+str(key)+'-' + str(addr) +'-'+function_hash] = BitVec('input'+str(key)+'['+str(addr)+']' +'-'+function_hash, 256)

					stack.append( {'type':'constant','step':step, 'z3':data['data-'+str(key)+'-' + str(addr)+'-'+function_hash] } )

			elif self.is_undefined(addr):
				# for statistics
				if (not search_enhance):
					if 'cdl_addr' in MyGlobals.notimplemented_ins:
						MyGlobals.notimplemented_ins['cdl_addr']+=1
					else:
						MyGlobals.notimplemented_ins['cdl_addr']=1

				if debug:
					print ('\033[95m[-] In CALLDATALOAD the input address cannot be determined at step %x: \033[0m' % code[pos]['id'] )
					print( addr )
				return pos, True

			#
			# if the address is not fixed (symbolic expression) then assume we are dealing with dynamic array
			# and input[ address ] is the length of the array
			else:

				stack.append( args[0] )

				return pos, False

		elif op in ['CALLDATASIZE']:
			return pos, False

		elif op == 'CALL':

			if self.is_fixed(args[5]) and self.is_fixed(args[6]):
				addr  = self.get_value( args[5] )
				value = self.get_value( args[6] )


				if value < 10000:
					for i in range(value//32):
						mmemory[addr + 32 * i] = { 'type':'undefined','step':step }


				exact_address = addr
				#Adding the accessed global variables to funcvardata 
				if search_enhance:
					if not function_hash in MyGlobals.funcvardata:
						MyGlobals.funcvardata[function_hash] = {}
						MyGlobals.funcvardata[function_hash]['bal'] = []
						MyGlobals.funcvardata[function_hash]['bal'].append('W')
						
					else:
						if not 'bal' in MyGlobals.funcvardata[function_hash]:
							MyGlobals.funcvardata[function_hash]['bal'] = []
							MyGlobals.funcvardata[function_hash]['bal'].append('W')

						else:
							if not 'W' in MyGlobals.funcvardata[function_hash]['bal']:
								MyGlobals.funcvardata[function_hash]['bal'].append('W')

			stack.append( {'type':'constant','step':step, 'z3':BitVec('call_at_step_'+str(step), 256) & 0x1} )     # assume the result of call can be any (True or False)

		elif op == 'CALLDATACOPY': 
			memaddr = args[0]  
			datapos = args[1]
			length  = args[2]

			if not self.is_fixed(memaddr) or not self.is_fixed( datapos ) or not self.is_fixed( length ):
				if debug: 
					print('\033[95m[-] In CALLDATACOPY the memory address or datapos or length cannot be determined \033[0m' )
					print(memaddr)
					print(datapos)
					print(length)
				return pos, True

			memaddr = self.get_value ( memaddr )
			datapos = self.get_value ( datapos )
			length  = self.get_value ( length  )


			if length % 32 != 0:
				if debug:
					print('\033[95m[-] In CALLDATACOPY the length of array (%d) is not multiple of 32 \033[0m' % length )
				return pos, True

			for i in range( length // 32 ):

				data[ datapos + 32 * i ] = BitVec('input'+str(key)+'['+str(datapos + 32 * i )+']' +'-'+function_hash,256)
				self.store_in_memory( mmemory, memaddr + 32 * i , {'type':'constant','step':step,'z3':data[ datapos + 32 * i ]} )

			# Truncated the storing only to 32 byte values

		elif op == 'CODESIZE':
			# for statistics
			if (not search_enhance):
				if 'codesize' in MyGlobals.notimplemented_ins:
					MyGlobals.notimplemented_ins['codesize']+=1
				else:
					MyGlobals.notimplemented_ins['codesize']=1
				
		elif op == 'CALLCODE':          stack.append( {'type':'constant','step':step, 'z3':BitVecVal(0,256)} )
		elif op == 'DELEGATECALL':      stack.append( {'type':'constant','step':step, 'z3':BitVecVal(0,256)} )
		elif op == 'EXTCODESIZE':       stack.append( {'type':'constant','step':step, 'z3':BitVecVal(0,256)} )
		elif op == 'CREATE': stack.append( {'type':'constant','step':step, 'z3':BitVecVal(0,256)} )

		elif op == 'MLOAD':
			addr = args[0]


			if self.is_undefined(addr):

				if debug:print('\033[95m[-] The MLOAD address on %x  cannot be determined\033[0m' % code[pos]['id'] )
				return pos, True

			addr = simplify(addr['z3'])

			if is_bv_value(addr):
				exact_address = addr.as_long()
				if exact_address in mmemory: res = copy.deepcopy(mmemory[exact_address])
				else: 
					res = {'type':'constant','step':step, 'z3': BitVecVal(0, 256) }
				stack.append( res )

			else:
				# for statistics
				if (not search_enhance):
					if 'mload_mem' in MyGlobals.notimplemented_ins:
						MyGlobals.notimplemented_ins['mload_mem']+=1
					else:
						MyGlobals.notimplemented_ins['mload_mem']=1
						
				if debug:print('\033[95m[-] The MLOAD address on %x  cannot be determined\033[0m' % code[pos]['id'] )
				return pos, True


		elif op == 'MSTORE':


			addr = args[0]
			if self.is_undefined(addr) or not is_bv_value( simplify(addr['z3']) ) :
				# for statistics
				if (not search_enhance):
					if 'mstore_mem' in MyGlobals.notimplemented_ins:
						MyGlobals.notimplemented_ins['mstore_mem']+=1
					else:
						MyGlobals.notimplemented_ins['mstore_mem']=1
				if debug:print('\033[95m[-] The MSTORE the write address on %x  cannot be determined\033[0m' % code[pos]['id'] )
				return pos, True

			t = copy.deepcopy( args[1] )
			addr = self.get_value(addr)

			self.store_in_memory( mmemory, addr, t )


		elif op in ['MSTORE8']:
			addr = args[0]
			value= args[1]

			if not self.is_fixed(addr) :
				# for statistics
				if (not search_enhance):
					if 'mstore8_mem' in MyGlobals.notimplemented_ins:
						MyGlobals.notimplemented_ins['mstore8_mem']+=1
					else:
						MyGlobals.notimplemented_ins['mstore8_mem']=1

				if debug:print('\033[95m[-] The MSTORE8 the write address on %x  cannot be determined\033[0m' % code[pos]['id'] )
				return pos, True
			if not self.is_fixed(value) :
				if debug:print('\033[95m[-] The MSTORE8 value is undefined \033[0m' % code[pos]['id'] )
				return pos, True

			ea = self.get_value(addr)
			ev = self.get_value(value) % 256

			if (ea//32)*32 not in mmemory: 
				mmemory[(ea//32)*32] = {'type':'constant','step':step, 'z3':BitVecVal(ev << (31- (ea%32)), 256) }
			elif self.is_fixed( mmemory[(ea//32)*32]['z3'] ):
				v = self.get_value( mmemory[(ea//32)*32]['z3'] )
				v = (v & (~BitVecVal(0xff,256) << (31- (ea%32)))) ^ (ev << (31- (ea%32)))
				mmemory[(ea//32)*32]['z3'] = v


		elif op == 'SLOAD':
			addr = args[0]

			if self.is_undefined(addr):
				if debug:print('\033[95m[-] The SLOAD address on %x  cannot be determined\033[0m' % code[pos]['id'] )
				# for statistics
				if (not search_enhance):
					if 'sload_mem' in MyGlobals.notimplemented_ins:
						MyGlobals.notimplemented_ins['sload_mem']+=1
					else:
						MyGlobals.notimplemented_ins['sload_mem']=1

				return pos, True

			addr = simplify(addr['z3'])

			# Optimizing search by technique similar to taint analysis

			if search_enhance:
				if is_bv_value(addr):
					exact_address = addr.as_long()
					#Adding the accessed global variables to funcvardata 

					if not function_hash in MyGlobals.funcvardata:
						MyGlobals.funcvardata[function_hash] = {}
						MyGlobals.funcvardata[function_hash][hex(exact_address).lstrip('0x').rstrip('L')] = []
						MyGlobals.funcvardata[function_hash][hex(exact_address).lstrip('0x').rstrip('L')].append('R')
						
					else:
						if not hex(exact_address).lstrip('0x').rstrip('L') in MyGlobals.funcvardata[function_hash]:
							MyGlobals.funcvardata[function_hash][hex(exact_address).lstrip('0x').rstrip('L')] = []
							MyGlobals.funcvardata[function_hash][hex(exact_address).lstrip('0x').rstrip('L')].append('R')

						else:
							if not 'R' in MyGlobals.funcvardata[function_hash][hex(exact_address).lstrip('0x').rstrip('L')]:
								MyGlobals.funcvardata[function_hash][hex(exact_address).lstrip('0x').rstrip('L')].append('R')

					if exact_address in MyGlobals.sha3vardata:
						for each in MyGlobals.sha3vardata[exact_address]:
							if not each in  MyGlobals.funcvardata[function_hash]:
								MyGlobals.funcvardata[function_hash][each] = []
								MyGlobals.funcvardata[function_hash][each].append('R')
							else:
								if not 'R' in MyGlobals.funcvardata[function_hash][each]:
									MyGlobals.funcvardata[function_hash][each].append('R')    

				else:
					for key, value in MyGlobals.sha3vardata.items():
						if str(key) in str(addr):
							for each in MyGlobals.sha3vardata[key]:
								if not function_hash in MyGlobals.funcvardata:
									MyGlobals.funcvardata[function_hash] = {}
									MyGlobals.funcvardata[function_hash][each] = []
									MyGlobals.funcvardata[function_hash][each].append('R')
									
								else:
									if not each in  MyGlobals.funcvardata[function_hash]:
										MyGlobals.funcvardata[function_hash][each] = []
										MyGlobals.funcvardata[function_hash][each].append('R')
									else:
										if not 'R' in MyGlobals.funcvardata[function_hash][each]:
											MyGlobals.funcvardata[function_hash][each].append('R')  



			if is_bv_value(addr):
				exact_address = addr.as_long()           
	 
				if exact_address in storage:
					total_values = len(storage[exact_address])
					if total_values == 0:
						print('In SLOAD the list at address %x has no elements ' % exact_address)
						exit(0)
						return pos, True
					else:
						res = copy.deepcopy(storage[exact_address][0])
				else:
					if search_enhance and MyGlobals.set_storage_symbolic:
						stack.append({'type':'constant','step':step, 'z3': BitVec('SLOAD'+'-'+str(step)+'-'+function_hash, 256) })
						return pos+1, False

					value = get_storage_value ( get_params('contract_address',''), exact_address, read_from_blockchain )
					t = {'type':'constant','step':step, 'z3': BitVecVal(int.from_bytes(value, byteorder='big'), 256) }

					storage[exact_address] = [ t ]
					res = copy.deepcopy(t)

				stack.append( res )

			else:
				if search_enhance:
					stack.append({'type':'constant','step':step, 'z3': BitVec('SLOAD'+'-'+str(step)+'-'+function_hash, 256) })
					return pos+1, False

				if debug:print('\033[95m[-] The SLOAD address on %x  cannot be determined\033[0m' % code[pos]['id'] )
				return pos, True

		elif op == 'SSTORE':

			addr = args[0]
			if self.is_undefined(addr):
				if debug:print('\033[95m[-] The SSTORE address on %x  cannot be determined\033[0m' % code[pos]['id'] )
				# for statistics
				if (not search_enhance):
					if 'sstore_addr' in MyGlobals.notimplemented_ins:
						MyGlobals.notimplemented_ins['sstore_addr']+=1
					else:
						MyGlobals.notimplemented_ins['sstore_addr']=1			
				return pos, True

			t = copy.deepcopy( args[1] )

			if search_enhance:

				if is_bv_value(simplify(addr['z3'])):
					exact_address = self.get_value(addr)

					if not function_hash in MyGlobals.funcvardata:
						MyGlobals.funcvardata[function_hash] = {}
						MyGlobals.funcvardata[function_hash][hex(exact_address).lstrip('0x').rstrip('L')] = []
						MyGlobals.funcvardata[function_hash][hex(exact_address).lstrip('0x').rstrip('L')].append('W')
						
					else:
						if not hex(exact_address).lstrip('0x').rstrip('L') in MyGlobals.funcvardata[function_hash]:
							MyGlobals.funcvardata[function_hash][hex(exact_address).lstrip('0x').rstrip('L')] = []
							MyGlobals.funcvardata[function_hash][hex(exact_address).lstrip('0x').rstrip('L')].append('W')

						else:
							if not 'W' in MyGlobals.funcvardata[function_hash][hex(exact_address).lstrip('0x').rstrip('L')]:
								MyGlobals.funcvardata[function_hash][hex(exact_address).lstrip('0x').rstrip('L')].append('W')


					if exact_address in MyGlobals.sha3vardata:
						for each in MyGlobals.sha3vardata[exact_address]:
							if not each in  MyGlobals.funcvardata[function_hash]:
								MyGlobals.funcvardata[function_hash][each] = []
								MyGlobals.funcvardata[function_hash][each].append('W')
							else:
								if not 'W' in MyGlobals.funcvardata[function_hash][each]:
									MyGlobals.funcvardata[function_hash][each].append('W')    

				else:
					se_addr = simplify(addr['z3'])
					for key, value in MyGlobals.sha3vardata.items():

						if str(key) in str(se_addr):

							for each in MyGlobals.sha3vardata[key]:
								if not function_hash in MyGlobals.funcvardata:
									MyGlobals.funcvardata[function_hash] = {}
									MyGlobals.funcvardata[function_hash][each] = []
									MyGlobals.funcvardata[function_hash][each].append('W')
									
								else:
									if not each in  MyGlobals.funcvardata[function_hash]:
										MyGlobals.funcvardata[function_hash][each] = []
										MyGlobals.funcvardata[function_hash][each].append('W')
									else:
										if not 'W' in MyGlobals.funcvardata[function_hash][each]:
											MyGlobals.funcvardata[function_hash][each].append('W') 			
								
			
			if is_bv_value( simplify(addr['z3']) ):
				va = self.get_value( addr )
				storage[va] = [t];
				exact_address = va

			else:
				if search_enhance:
					return pos+1, False
				if debug:
					print ('\033[95m[-] In SSTORE the write address cannot be determined at step %x: \033[0m' % code[pos]['id'] )
					print( addr )
				return pos, True
				
		elif op == 'JUMP':

			addr = args[0]

			if not self.is_fixed( addr ):
				# for statistics
				if (not search_enhance):
					if 'jump_addr' in MyGlobals.notimplemented_ins:
						MyGlobals.notimplemented_ins['jump_addr']+=1
					else:
						MyGlobals.notimplemented_ins['jump_addr']=1

				if debug: print('\033[95m[-] In JUMP the address cannot be determined \033[0m'  )
				return pos, True
		
			jump_dest = self.get_value( addr )
			if( jump_dest <= 0):
				if debug: print('\033[95m[-] The JUMP destination is not a valid address : %x\033[0m'  % jump_dest )
				return pos, True
		
			new_position= find_pos(code, jump_dest )

			if( new_position < 0):

				if debug: print('\033[95m[-] The code has no such JUMP destination: %s at line %x\033[0m' % (hex(jump_dest), code[pos]['id']) )
				return pos, True

			return new_position, False


		elif op == 'JUMPI': return pos , False

		elif op == 'BYTE':
			byte_no = args[0]
			word    = args[1]
			if self.is_undefined(word) or self.is_undefined(byte_no): 
				res = {'type':'undefined','step':step}
			else:                                           
				res = {'type':'constant','step':step, 'z3': (word['z3'] >> (8*(31-byte_no['z3'])) ) & 0xff }

			stack.append( res )

		else:
			executed = False




		if executed and final_stack_size != len(stack):
			print('Incorrect final stack size after executing %s at step %x' % (op,step))
			print(len(stack))
			print(final_stack_size)
			exit(2)

		return pos + 1, halt