Esempio n. 1
0
    def CALLDATALOAD(self, gstate, index):
        logging.debug('CALLDATA index:' + str(index))
        if gstate.environment.calldata is None:
            raise SVMRuntimeError('CALLDATA is not set')
        index_concrete = svm_utils.is_bv_concrete(index)
        if gstate.environment.calldata_type == CalldataType.UNDEFINED:
            data_bytes = []
            # for i in range(32):
                # label = 'calldata_{}_{}'.format(wstate.gen, i + svm_utils.get_concrete_int(index))
                # data_bytes.append(z3.BitVec(label, 8))
            # data = z3.Concat(data_bytes)
            if index_concrete:
                data = self.svm.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.CALLDATA,
                                                            gstate.wstate.gen,
                                                            index=svm_utils.get_concrete_int(index))
                gstate.mstate.stack.append(data)
            else:
                data = self.svm.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.CALLDATA,
                                                            gstate.wstate.gen,
                                                            unique=True)
                gstate.mstate.stack.append(data)

        elif gstate.environment.calldata_type == CalldataType.DEFINED:
            assert gstate.environment.calldata.sort().name() == 'bv', 'CALLDATA sort mismatch'
            index = svm_utils.get_concrete_int(z3.simplify(index))
            calldatasize = gstate.environment.calldata.size()
            assert index < calldatasize
            calldata_start = calldatasize-index*8
            calldata_stop = max(0, calldata_start - 256)
            calldata = z3.Extract(calldata_start-1, calldata_stop, gstate.environment.calldata)
            calldata = svm_utils.zpad_bv_left(calldata, 256)
            gstate.mstate.stack.append(calldata)
        else:
            raise SVMRuntimeError('Unknown calldata type')
Esempio n. 2
0
    def CREATE(self, gstate, balance, offset, length):
        new_gstates = []

        active_address = gstate.environment.active_address
        active_account = gstate.wstate.address_to_account[active_address]

        if gstate.wstate.gen != 0:
            raise SVMRuntimeError('Dynamic contract creation is not supported')

        offset = svm_utils.get_concrete_int(offset)
        length = svm_utils.get_concrete_int(length)
        create_contract_bytes = []
        concrete_prefix_bytes = []
        concrete_prefix_stop = False
        for index in range(0, length):
            memory_byte = gstate.mstate.memory_dict[index+offset]
            memory_byte = svm_utils.get_concrete_int(memory_byte) if svm_utils.is_bv_concrete(memory_byte) else memory_byte
            create_contract_bytes.append(memory_byte)
            concrete_prefix_stop = concrete_prefix_stop or not isinstance(memory_byte, int)
            if not concrete_prefix_stop: concrete_prefix_bytes.append(memory_byte)
        found_swarmhashes = asm.find_swarmhashes(bytes(concrete_prefix_bytes))
        if not len(found_swarmhashes):
            raise SVMRuntimeError('CREATE found no swarmhashes in bytecode')
        create_contract = self.svm.swarm_hash_tuple_to_contract[tuple(found_swarmhashes)]
        create_address = utils.get_next_contract_address()
        create_account = Account(create_address, create_contract, balance=balance)
        logging.debug(f'CREATE created contract {create_account.contract.name}')
        create_enviroment = Environment(active_address=create_address,
                                        sender=z3.BitVecVal(active_account.address, 256),
                                        calldata=[],
                                        gasprice=gstate.environment.gasprice,
                                        callvalue=balance,
                                        origin=gstate.environment.origin,
                                        calldata_type=CalldataType.UNDEFINED,
                                        disassembly=create_account.contract.creation_disassembly,
                                        runtime_bytecode_bytes=create_contract_bytes,
                                        timestamp=gstate.environment.timestamp)
        child_wstate = copy(gstate.wstate)
        child_wstate.address_to_account[create_address] = create_account
        create_gstate = GlobalState(child_wstate, create_enviroment)
        create_gstate.has_storage_changed = True
        intermediate_gstates = self.execute_gstate(create_gstate)
        if len(intermediate_gstates) == 0:
            raise SVMRuntimeError('CREATE has no feasible blocks')
        for new_gstate in intermediate_gstates:
            new_gstate.mstate = deepcopy(gstate.mstate)
            new_gstate.mstate.stack.append(z3.BitVecVal(create_address, 256))
            new_gstate.pc_addr_to_depth = copy(gstate.pc_addr_to_depth)
            new_gstate.mstate.pc += 1
            new_gstate.halt = False
            new_gstate.environment = gstate.environment
            new_gstates.extend(self.execute_gstate(new_gstate))
        logging.debug(f'returning FROM CREATE contract {create_account.contract.name}')
        gstate.halt = True
        return new_gstates
Esempio n. 3
0
 def JUMP(self, gstate, jump_addr):
     if not svm_utils.is_bv_concrete(jump_addr):
         if svm_utils.check_wstate_reachable(gstate.wstate, 100):
             logging.warning('JUMP to invalid address')
         return
     # if gstate.pc_addr_to_depth.setdefault((gstate.mstate.pc, jump_addr), 0) < self.svm.max_jump_depth:
     jump_addr = svm_utils.get_concrete_int(jump_addr)
     instr_idx = svm_utils.get_instruction_index(gstate.environment.disassembly.instruction_list, jump_addr)
     if instr_idx is None:
         raise SVMRuntimeError('JUMP to invalid address')
     dest_opcode = gstate.environment.disassembly.instruction_list[instr_idx]['opcode']
     if dest_opcode != 'JUMPDEST':
         raise SVMRuntimeError('JUMP to invalid address')
     gstate.mstate.pc = instr_idx
     return self.execute_gstate(gstate)
Esempio n. 4
0
 def CALLDATACOPY(self, gstate, dest_offset, offset, length):
     length_concrete = svm_utils.is_bv_concrete(length)
     if not length_concrete:
         logging.warning('Symbolic calldata size')
         length = z3.BitVecVal(64, 256)
     if gstate.environment.calldata_type == CalldataType.UNDEFINED:
         length = svm_utils.get_concrete_int(length)
         if svm_utils.is_bv_concrete(offset):
             offset = svm_utils.get_concrete_int(offset)
             for i in range(length):
                 data_word = self.svm.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.CALLDATA,
                                                                      gstate.wstate.gen,
                                                                      index=offset+(i//32))
                 slot = i % 32
                 data_bytes = svm_utils.split_bv_into_bytes(data_word)
                 data = data_bytes[slot]
                 gstate.mstate.memory = z3.Store(gstate.mstate.memory, dest_offset+i, data)
         else:
             for i in range(length):
                 data = self.svm.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.CALLDATA,
                                                                 gstate.wstate.gen,
                                                                 unique=True,
                                                                 bv_size=8)
                 gstate.mstate.memory = z3.Store(gstate.mstate.memory, dest_offset+i, data)
     elif gstate.environment.calldata_type == CalldataType.DEFINED:
         length = svm_utils.get_concrete_int(length)
         offset_concrete = svm_utils.is_bv_concrete(offset)
         calldata_bytes = svm_utils.split_bv_into_bytes(gstate.environment.calldata)
         offset_concrete = svm_utils.is_bv_concrete(offset)
         for i in range(length):
             gstate.mstate.memory = z3.Store(gstate.mstate.memory, dest_offset+i, calldata_bytes[offset_concrete+i])
     else:
         raise SVMRuntimeError('Unknown calldata type')
Esempio n. 5
0
 def SIGNEXTEND(self, gstate, a, b):
     if svm_utils.is_bv_concrete(a) and svm_utils.is_bv_concrete(b):
         a = svm_utils.get_concrete_int(a)
         b = svm_utils.get_concrete_int(b)
         if a <= 31:
             testbit = a * 8 + 7
             if b & (1 << testbit):
                 gstate.mstate.stack.append(b | (TT256 - (1 << testbit)))
             else:
                 gstate.mstate.stack.append(b & ((1 << testbit) - 1))
         else:
             gstate.mstate.stack.append(b)
     else:
         raise SVMRuntimeError('SIGNEXTEND error')
Esempio n. 6
0
    def CALLDATASIZE(self, gstate):
        active_address = gstate.environment.active_address
        active_account = gstate.wstate.address_to_account[active_address]

        if gstate.environment.calldata_type == CalldataType.UNDEFINED:
            gstate.mstate.stack.append(self.svm.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.CALLDATASIZE,
                                                                                gstate.wstate.gen,
                                                                                acc=active_account.id))
        elif gstate.environment.calldata_type == CalldataType.DEFINED:
            if gstate.environment.calldata is not None:
                gstate.mstate.stack.append(z3.BitVecVal(gstate.environment.calldata.size() // 8, 256))
            else:
                gstate.mstate.stack.append(z3.BitVecVal(0, 256))
        else:
            raise SVMRuntimeError('Unknown calldata type')
Esempio n. 7
0
    def evaluate(self, gstate):
        stack_len_start = len(gstate.mstate.stack)
        self.pre_evaluate(gstate)
        if gstate.halt:
            return

        instr = gstate.environment.disassembly.instruction_list[gstate.mstate.pc]
        instr_address = instr['address']


        op = instr['opcode']
        match = re.match(r'^(PUSH|DUP|LOG|SWAP)\d{1,2}', op)
        op = match.group(1) if match else op
        eval_func = getattr(self, op, None)
        if eval_func is None:
            raise SVMRuntimeError(f'op evaluator not found: {op}')

        active_account = gstate.wstate.address_to_account[gstate.environment.active_address]
        current_func = '?'  if gstate.wstate.trace is None else gstate.wstate.trace
        arg = instr.get('argument', '')
        arg = (arg[0:10] + '..') if len(arg) > 12 else arg.ljust(12)
        logging.debug(f'{BColors.BLUE}{BColors.BOLD}OP{BColors.ENDC} '
                      f'{op.ljust(12)}\t'
                      f'{arg},\t'
                      f'addr={instr_address},\t'
                      f'pc={gstate.mstate.pc},\t'
                      f'contract={active_account.contract.name}\t'
                      f'func={current_func}\t'
                      f'sender={gstate.environment.sender}')
        arglist = inspect.getargspec(eval_func).args
        try:
            stack_args = [gstate.mstate.stack.pop() for arg in arglist[2:]]
            res = eval_func(gstate, *stack_args)
            gstate.mstate.pc += 1
            stack_len_stop = len(gstate.mstate.stack)
            self.op_to_stack_len[op] = (stack_len_stop - stack_len_start)
            return res
        except Exception as e:
            s = z3.Solver()
            s.add(gstate.wstate.constraints)
            if s.check() == z3.sat:
                raise e
Esempio n. 8
0
 def DELEGATECALL(self, gstate, gas, to, meminstart, meminsize, outmemstart, memoutsize):
     value = 0
     raise SVMRuntimeError('DELEGATECALL not implemented')
Esempio n. 9
0
 def CALLCODE(self, gstate, gas, to, value, meminstart, meminsize, outmemstart, memoutsize):
     raise SVMRuntimeError('CALLCODE not implemented')
Esempio n. 10
0
    def JUMPI(self, gstate, jump_addr, condition):
        new_gstates = []

        active_address = gstate.environment.active_address
        active_account = gstate.wstate.address_to_account[active_address]
        mstate = gstate.mstate

        jump_addr = svm_utils.get_concrete_int(jump_addr)
        function_entry = False

        gstate.jump_count += 1
        if (gstate.jump_count % 3 == 0 and
                gstate.jump_count > 20 and
                not svm_utils.check_wstate_reachable(gstate.wstate, 100)):
            gstate.halt = True
            return

        if gstate.pc_addr_to_depth.setdefault((gstate.mstate.pc, jump_addr), 0) >= 3:
            gstate.halt = True
            return
        increase_depth = True
        current_contract = active_account.contract
        line = solidity_utils.offset_to_line(current_contract.src_code, mstate.pc, current_contract.src_map)
        src_code = current_contract.src_code.split('\n')[line].strip()
        concrete_cond = False
        if 'assert' in src_code:
            increase_depth = False
        if type(condition) == bool:
            increase_depth = False
        else:
            simplified_cond = z3.simplify(condition)
            if z3.is_true(simplified_cond) or z3.is_false(simplified_cond):
                concrete_cond = True
                increase_depth = False
        if increase_depth:
            gstate.pc_addr_to_depth[(mstate.pc, jump_addr)] = gstate.pc_addr_to_depth[(mstate.pc, jump_addr)] + 1

        instr_idx = svm_utils.get_instruction_index(gstate.environment.disassembly.instruction_list, jump_addr)
        if instr_idx is None:
            raise SVMRuntimeError('JUMP to invalid address')
        dest_opcode = gstate.environment.disassembly.instruction_list[instr_idx]['opcode']
        if dest_opcode != 'JUMPDEST':
            raise SVMRuntimeError('JUMP to invalid address')

        condition = z3.BoolVal(condition) if isinstance(condition, bool) else condition
        condition = (condition == 0) if isinstance(condition, z3.BitVecRef) else condition
        assert isinstance(condition ,z3.BoolRef), 'Invalid condition types!'

        if not z3.is_false(z3.simplify(condition)):
            true_gstate = copy(gstate)
            true_gstate.mstate.pc = instr_idx
            true_gstate.wstate.constraints.append(condition)
            if true_gstate.wstate.trace is None:
                jump_func_name, jump_func_hash = gstate.environment.extract_func_name_hash(gstate.mstate.pc)
                if jump_func_name:
                    jump_trace = make_trace(active_account, jump_func_name)
                    logging.debug('Entering function %s', jump_trace)
                    true_gstate.wstate.trace = jump_trace
            new_gstates.extend(self.execute_gstate(true_gstate))

        negated_condition = z3.Not(condition)

        if not z3.is_false(z3.simplify(negated_condition)):
            false_gstate = copy(gstate)
            false_gstate.mstate.pc += 1
            false_gstate.wstate.constraints.append(negated_condition)
            new_gstates.extend(self.execute_gstate(false_gstate))

        gstate.halt = True
        return new_gstates
Esempio n. 11
0
 def EXTCODECOPY(self, gstate, start, s2, size):
     raise SVMRuntimeError('not implemented')