Exemple #1
0
    def _search_value(self):
        if self._arm:
            armins = self._string_to_insn(self._insbytes)
            if not self._arm64:
                if not self._armthumb:
                    # ARM instructions
                    if armins & 0x0C000000 == 0x04000000:
                        # LDR
                        thoughtval = armins & 0xFFF
                        if thoughtval != self.value:
                            raise ValueNotFoundError
                        imm12 = self._imm(12)
                        self.patch_value_expression = imm12.zero_extend(
                            self.bits - 12)
                        self.patch_bytes_expression = claripy.Concat(
                            BVV(armins >> 12, 20), imm12)
                        self._test_values = (1, 0xfff)
                    elif armins & 0x0E000000 == 0x02000000:
                        # Data processing w/ immediate
                        shiftval = (armins & 0xF00) >> 7
                        thoughtval = armins & 0xFF
                        thoughtval = ror(thoughtval, shiftval, 32)
                        if thoughtval != self.value:
                            raise ValueNotFoundError
                        shift = self._imm(4, 'shift')
                        imm8 = self._imm(8)
                        self.patch_value_expression = claripy.RotateRight(
                            imm8.zero_extend(32 - 8),
                            shift.zero_extend(32 - 4) * 2)
                        self.patch_bytes_expression = claripy.Concat(
                            BVV(armins >> 12, 20), shift, imm8)
                        self._test_values = (1, 0xff, 0xff000000)
                    elif armins & 0x0E400090 == 0x00400090:
                        # LDRH
                        thoughtval = (armins & 0xF) | ((armins & 0xF00) >> 4)
                        if thoughtval != self.value:
                            raise ValueNotFoundError
                        hinib = self._imm(4, 'hinib')
                        lonib = self._imm(4, 'lonib')
                        self.patch_value_expression = claripy.Concat(
                            hinib, lonib).zero_extend(self.bits - 8)
                        self.patch_bytes_expression = claripy.Concat(
                            BVV(armins >> 12, 20), hinib,
                            BVV((armins >> 4) & 0xF, 4), lonib)
                        self._test_values = (1, 0xff)
                    elif armins & 0x0E000000 == 0x0C000000:
                        # Coprocessor data transfer
                        # i.e. FLD/FST
                        thoughtval = armins & 0xFF
                        thoughtval *= 4
                        if thoughtval != self.value:
                            raise ValueNotFoundError
                        imm8 = self._imm(8)
                        self.patch_value_expression = imm8.zero_extend(
                            self.bits - 8) << 2
                        self.patch_bytes_expression = claripy.Concat(
                            BVV(armins >> 8, 24), imm8)
                        self._test_values = (4, 0x3fc)
                    else:
                        raise ValueNotFoundError

                else:
                    # THUMB instructions
                    # https://ece.uwaterloo.ca/~ece222/ARM/ARM7-TDMI-manual-pt3.pdf
                    if self._inslen == 2:
                        # 16 bit instructions
                        if armins & 0xF000 in (0x9000, 0xA000):
                            # SP-relative LDR/STR, also SP-addiition
                            # page 26, 28
                            # unsigned offsets only, 10 bit imm stored w/o last two bits
                            thoughtval = armins & 0xFF
                            thoughtval *= 4
                            if thoughtval != self.value:
                                raise ValueNotFoundError
                            imm8 = self._imm(8)
                            self.patch_value_expression = imm8.zero_extend(
                                self.bits - 8) << 2
                            self.patch_bytes_expression = claripy.Concat(
                                BVV(armins >> 8, 8), imm8)
                            self._test_values = (4, 0x3fc)
                        elif armins & 0xFF00 == 0xB000:
                            # Add/sub offset to SP
                            # page 30
                            # uses sign bit, 9 bit imm stored w/o last two bits
                            thoughtval = armins & 0x7F
                            thoughtval *= 4
                            if thoughtval != self.value:
                                raise ValueNotFoundError
                            imm7 = self._imm(7)
                            self.patch_value_expression = imm7.zero_extend(
                                self.bits - 7) << 2
                            self.patch_bytes_expression = claripy.Concat(
                                BVV(armins >> 7, 9), imm7)
                            self._test_values = (4, 0x1fc)
                        elif armins & 0xFC00 == 0x1C00:
                            # ADD/SUB (immediate format)
                            # page 7
                            # uses sign bit, 3 bit immediate
                            thoughtval = (armins & 0x01C0) >> 6
                            if thoughtval != self.value:
                                raise ValueNotFoundError
                            imm3 = self._imm(3)
                            self.patch_value_expression = imm3.zero_extend(
                                self.bits - 3)
                            self.patch_bytes_expression = claripy.Concat(
                                BVV(armins >> 9, 7), imm3,
                                BVV(armins & 0x3F, 6))
                            self._test_values = (1, 7)
                        elif armins & 0xE000 == 0x2000:
                            # Move/Compare/Add/Subtract immediate
                            # page 9
                            # Unsigned 8 bit immediate
                            thoughtval = armins & 0xFF
                            if thoughtval != self.value:
                                raise ValueNotFoundError
                            imm8 = self._imm(8)
                            self.patch_value_expression = imm8.zero_extend(
                                self.bits - 8)
                            self.patch_bytes_expression = claripy.Concat(
                                BVV(armins >> 8, 8), imm8)
                            self._test_values = (1, 0xff)
                        elif armins & 0xF000 == 0x6000:
                            # Register-relative LDR/STR
                            # page 22
                            # unsigned 7 bit imm stored w/o last two bits
                            thoughtval = ((armins >> 6) & 0x1F) << 2
                            if thoughtval != self.value:
                                raise ValueNotFoundError
                            imm5 = self._imm(5)
                            self.patch_value_expression = imm5.zero_extend(
                                self.bits - 5) << 2
                            self.patch_bytes_expression = claripy.Concat(
                                BVV(armins >> 11, 5), imm5,
                                BVV(armins & 0x3F, 6))
                            self._test_values = (4, 0x7c)
                        elif armins & 0xF000 == 0x7000:
                            # Register-relative LDRB/STRB
                            # page 22
                            # unsigned 5 bit imm
                            thoughtval = (armins >> 6) & 0x1F
                            if thoughtval != self.value:
                                raise ValueNotFoundError
                            imm5 = self._imm(5)
                            self.patch_value_expression = imm5.zero_extend(
                                self.bits - 5)
                            self.patch_bytes_expression = claripy.Concat(
                                BVV(armins >> 11, 5), imm5,
                                BVV(armins & 0x3F, 6))
                            self._test_values = (1, 0x1f)
                        else:
                            raise ValueNotFoundError

                    elif self._inslen == 4:
                        # 32 bit instructions
                        # http://read.pudn.com/downloads159/doc/709030/Thumb-2SupplementReferenceManual.pdf
                        if armins & 0xFE1F0000 == 0xF81F0000 or \
                           armins & 0xFE800000 == 0xF8800000:
                            # Load/Store
                            # page 66, formats 1-2
                            # imm12 with designated sign bit
                            thoughtval = armins & 0xFFF
                            if thoughtval != self.value:
                                raise ValueNotFoundError
                            imm12 = self._imm(12)
                            self.patch_value_expression = imm12.zero_extend(
                                self.bits - 12)
                            self.patch_bytes_expression = claripy.Concat(
                                BVV(armins >> 12, 20), imm12)
                            self._test_values = (1, 0xfff)
                        elif armins & 0xFE800900 == 0xF8000800:
                            # Load/Store
                            # page 66, formats 3-4
                            # imm8 with designated sign bit
                            thoughtval = armins & 0xFF
                            if thoughtval != self.value:
                                raise ValueNotFoundError
                            imm8 = self._imm(8)
                            self.patch_value_expression = imm8.zero_extend(
                                self.bits - 8)
                            self.patch_bytes_expression = claripy.Concat(
                                BVV(armins >> 8, 24), imm8)
                            self._test_values = (1, 0xff)
                        elif armins & 0xFE800900 == 0xF8000900:
                            # Load/Store
                            # page 66, formats 5-6
                            # imm8, sign extended
                            thoughtval = armins & 0x7F
                            if armins & 0x80 == 0x80:
                                thoughtval = (thoughtval ^ 0x7F) + 1
                            if thoughtval != self.value:
                                raise ValueNotFoundError
                            imm8 = self._imm(8)
                            self.patch_value_expression = imm8.sign_extend(
                                self.bits - 8)
                            self.patch_bytes_expression = claripy.Concat(
                                BVV(armins >> 8, 24), imm8)
                            self._test_values = (-0x80, 0x7f)
                        elif armins & 0xFB408000 == 0xF2000000:
                            # Add/Sub
                            # page 53, format 2
                            # 12 bit immediate split into 3 bitfields
                            thoughtval = armins & 0xFF
                            thoughtval |= (armins & 0x7000) >> 4
                            thoughtval |= (armins & 0x04000000) >> 15
                            if thoughtval != self.value:
                                raise ValueNotFoundError
                            imm8 = self._imm(8)
                            imm3 = self._imm(3)
                            imm1 = self._imm(1)
                            self.patch_value_expression = claripy.Concat(
                                imm1, imm3, imm8).zero_extend(self.bits - 12)
                            self.patch_bytes_expression = claripy.Concat(
                                BVV(armins >> 27, 5), imm1,
                                BVV((armins & 0x03FF8000) >> 15, 11), imm3,
                                BVV((armins & 0xF00) >> 8, 4), imm8)
                            self._test_values = (1, 0xfff)
                        elif armins & 0xFB408000 == 0xF2400000:
                            # Move
                            # page 53, format 3
                            # 16 bit immediate split into 4 bitfields
                            thoughtval = armins & 0xFF
                            thoughtval |= (armins & 0x7000) >> 4
                            thoughtval |= (armins & 0x04000000) >> 15
                            thoughtval |= (armins & 0xF0000) >> 4
                            if thoughtval != self.value:
                                raise ValueNotFoundError
                            imm8 = self._imm(8)
                            imm3 = self._imm(3)
                            imm1 = self._imm(1)
                            imm4 = self._imm(1)
                            self.patch_value_expression = claripy.Concat(
                                imm4, imm1, imm3,
                                imm8).zero_extend(self.bits - 12)
                            self.patch_bytes_expression = claripy.Concat(
                                BVV(armins >> 27, 5), imm1,
                                BVV((armins & 0x03F00000) >> 20, 6), imm4,
                                BVV((armins & 0x00008000) >> 15, 1), imm3,
                                BVV((armins & 0xF00) >> 8, 4), imm8)
                            self._test_values = (1, 0xffff)
                        elif armins & 0xFA008000 == 0xF0000000:
                            # Data processing, modified 12 bit imm, aka EVIL
                            # page 53
                            # wow. just. wow.
                            imm12 = armins & 0xFF
                            imm12 |= (armins & 0x7000) >> 4
                            imm12 |= (armins & 0x04000000) >> 15
                            # decoding algorithm from page 93
                            if imm12 & 0xC00 == 0:
                                if imm12 & 0x300 == 0:
                                    thoughtval = imm12
                                elif imm12 & 0x300 == 0x100:
                                    thoughtval = imm12 & 0xFF
                                    thoughtval |= thoughtval << 16
                                elif imm12 & 0x300 == 0x200:
                                    thoughtval = (imm12 & 0xFF) << 8
                                    thoughtval |= thoughtval << 16
                                elif imm12 & 0x300 == 0x300:
                                    thoughtval = imm12 & 0xFF
                                    thoughtval |= thoughtval << 8
                                    thoughtval |= thoughtval << 16
                            else:
                                thoughtval = ror(0x80 | (imm12 & 0x7F),
                                                 imm12 >> 7, 32)
                            if thoughtval != self.value:
                                raise ValueNotFoundError
                            imm12 = self._imm(12)
                            ITE = claripy.If
                            CAT = claripy.Concat
                            ROR = claripy.RotateRight
                            imm8 = imm12[7:0]
                            imm7 = imm12[6:0]
                            imm3 = imm12[10:8]
                            imm1 = imm12[11]
                            zero = BVV(0, 8)
                            bit = BVV(1, 1)
                            monster = ITE(
                                imm12[11:10] == 0,
                                ITE(
                                    imm12[9] == 0,
                                    ITE(imm12[8] == 0,
                                        imm12[7:0].zero_extend(32 - 8),
                                        CAT(zero, imm8, zero, imm8)),
                                    ITE(imm12[8] == 0,
                                        CAT(imm8, zero, imm8, zero),
                                        CAT(imm8, imm8, imm8, imm8))),
                                ROR(
                                    CAT(bit, imm7).zero_extend(32 - 8),
                                    imm12[11:7].zero_extend(32 - 5)))
                            self.patch_value_expression = monster
                            self.patch_bytes_expression = claripy.Concat(
                                BVV(armins >> 27, 5), imm1,
                                BVV((armins & 0x03FF8000) >> 15, 11), imm3,
                                BVV((armins & 0xF00) >> 8, 4), imm8)
                            self._test_values = (0xff00ff00, 0x00ff00ff,
                                                 0xffffffff, 0xff, 0xff000000)
                        else:
                            raise ValueNotFoundError
                    else:
                        raise FidgetUnsupportedError(
                            "You found a THUMB instruction longer than 32 bits??"
                        )

            else:
                self.bit_length = 64
                # aarch64 instructions
                # can't find a reference doc?????? I'm pulling these from VEX, guest_arm64_toIR.c
                if armins & 0x7f800000 in (0x28800000, 0x29800000, 0x29000000):
                    # LDP/SDP
                    # line 4791
                    # 7 bit immediate signed offset, scaled by load size (from MSB)
                    shift = 3 if armins & 0x80000000 else 2
                    simm7 = (armins & 0x3f8000) >> 15
                    simm7 = resign_int(simm7, 7)
                    simm7 <<= shift
                    if simm7 != self.value:
                        raise ValueNotFoundError
                    imm7 = self._imm(7)
                    self.patch_value_expression = imm7.sign_extend(self.bits -
                                                                   7) << shift
                    self.patch_bytes_expression = claripy.Concat(
                        BVV((armins & 0xffc00000) >> 22, 10), imm7,
                        BVV(armins & 0x7fff, 15))
                    self._test_values = (-0x40 << shift, 0x3f << shift)
                elif (armins & 0x3f800000 == 0x39000000) or \
                     (armins & 0x3f800000 == 0x39800000 and \
                          ((armins >> 30) | ((armins >> 22) & 1)) in (4, 2, 3, 0, 1)):
                    # LDR/STR, LDRS
                    # line 4639, 5008
                    # 12 bit immediate unsigned offset, scaled by load size (from 2 MSB)
                    shift = (armins & 0xc0000000) >> 30
                    offs = (armins & 0x3ffc00) >> 10
                    offs <<= shift
                    if offs != self.value:
                        raise ValueNotFoundError
                    imm12 = self._imm(12)
                    self.patch_value_expression = imm12.zero_extend(
                        self.bits - 12) << shift
                    self.patch_bytes_expression = claripy.Concat(
                        BVV((armins & 0xffc00000) >> 22, 10), imm12,
                        BVV(armins & 0x3ff, 10))
                    self._test_values = (1 << shift, 0xfff << shift)
                elif armins & 0x1f000000 == 0x11000000:
                    # ADD/SUB imm
                    # line 2403
                    # 12 bit shifted unsigned immediate
                    if not armins & 0x80000000:
                        self.bit_length = 32
                    shift = (armins >> 22) & 3
                    imm12 = (armins >> 10) & 0xfff
                    imm12 <<= 12 * shift
                    if imm12 != self.value:
                        raise ValueNotFoundError
                    shift = self._imm(1, 'shift')
                    imm12 = self._imm(12)
                    shift_full = shift.zero_extend(self.bits - 1) * 12
                    self.patch_value_expression = imm12.zero_extend(
                        self.bits - 12) << shift_full
                    self.patch_bytes_expression = claripy.Concat(
                        BVV(armins >> 24, 8), BVV(0, 1), shift, imm12,
                        BVV(armins & 0x3ff, 10))
                    self._test_values = (1, 0xfff, 0xfff000)
                elif armins & 0x3fa00000 == 0x38000000:
                    # LDUR/STUR
                    # Line 4680
                    # 9 bit signed immediate offset
                    imm9 = (armins >> 12) & 0x1ff
                    imm9 = resign_int(imm9, 9)
                    if imm9 != self.value:
                        raise ValueNotFoundError
                    imm9 = self._imm(9)
                    self.patch_value_expression = imm9.sign_extend(self.bits -
                                                                   9)
                    self.patch_bytes_expression = claripy.Concat(
                        BVV(armins >> 21, 11), imm9, BVV(armins & 0xfff, 12))
                    self._test_values = (-0x100, 0xff)

                else:
                    raise ValueNotFoundError

            if not self.sanity_check():
                raise ValueNotFoundError
        else:
            insn = self._string_to_insn(self._insbytes)
            insn = BVV(insn, self._inslen * 8)
            for word_size in (64, 32, 16, 8):
                if word_size > self.bits:
                    continue
                for bit_offset in xrange(0, insn.length - word_size + 1, 8):
                    result = insn[bit_offset + word_size - 1:bit_offset]
                    result = result.sign_extend(self.bits - word_size)
                    if claripy.is_true(result == self.value):
                        imm = self._imm(word_size)
                        self.patch_value_expression = imm.sign_extend(
                            self.bits - word_size)
                        if bit_offset + word_size >= insn.length:
                            acc = imm
                        else:
                            acc = claripy.Concat(
                                insn[insn.length - 1:bit_offset + word_size],
                                imm)
                        if bit_offset != 0:
                            acc = claripy.Concat(acc, insn[bit_offset - 1:0])

                        if self._project.arch.memory_endness == 'Iend_LE':
                            self.patch_bytes_offset = bit_offset / 8
                        else:
                            self.patch_bytes_offset = self._inslen - (
                                bit_offset + word_size) / 8

                        self.patch_bytes_size = word_size / 8
                        self.patch_bytes_expression = acc
                        self._test_values = (-(1 << word_size) >> 1,
                                             ((1 << word_size) >> 1) - 1)

                        if self.sanity_check():
                            break  # found

                    if self._project.arch.name == 'PPC64':
                        # On PPC64, the lowest two bits of immediate values can be used for other things
                        # Mask those out
                        result = (result & ~3).sign_extend(self.bits -
                                                           word_size)
                        if not claripy.is_true(result == self.value):
                            continue
                        imm = self._imm(word_size - 2)
                        self.patch_value_expression = claripy.Concat(
                            imm, BVV(0, 2)).sign_extend(self.bits - word_size)
                        if bit_offset + word_size >= insn.length:
                            acc = imm
                        else:
                            acc = claripy.Concat(
                                insn[insn.length - 1:bit_offset + word_size],
                                imm)
                        acc = claripy.Concat(acc, insn[bit_offset + 1:0])

                        if self._project.arch.memory_endness == 'Iend_LE':
                            self.patch_bytes_offset = bit_offset / 8
                        else:
                            self.patch_bytes_offset = self._inslen - (
                                bit_offset + word_size) / 8

                        self.patch_bytes_size = word_size / 8
                        self.patch_bytes_expression = acc
                        self._test_values = (-(1 << word_size) >> 1,
                                             ((1 << word_size) >> 1) - 4)
                        if self.sanity_check():
                            break  # found
                else:
                    # inner loop did not break: not found
                    continue
                # inner loop broke: found
                break
            else:
                # outer loop did not break: inner loop did not break: not found
                raise ValueNotFoundError
            # outer loop broke: inner loop broke: found
            return
Exemple #2
0
    def exec_branch(self, state):  # pylint:disable=invalid-name
        """Execute forward from a state, queuing new states if needed."""
        logger.debug("Constraints: %s", state.solver.constraints)

        def solution(variable):
            """Returns the solution. There must be one or we fail."""
            solutions = state.solver.eval(variable, 2)
            if len(solutions) > 1:
                raise MultipleSolutionsError(
                    "Multiple solutions for %s (%#x)" %
                    (variable, self.code[state.pc]))
            solution = solutions[0]
            return solution if isinstance(solution,
                                          numbers.Number) else solution.value

        self.code.pc = state.pc

        while True:
            if state.pc >= len(self.code):
                return True

            op = self.code[state.pc]
            self.code.pc += 1
            self.coverage[state.pc] += 1

            logger.debug("NEW STEP")
            logger.debug("Memory: %s", state.memory)
            logger.debug("Stack: %s", state.stack)
            logger.debug("PC: %i, %#x", state.pc, op)

            assert self.code.pc == state.pc + 1
            assert isinstance(op, numbers.Number)
            assert all(
                isinstance(i, claripy.ast.base.BV) for i in
                state.stack), "The stack musty only contains claripy BV's"

            # Trivial operations first
            if not self.code.is_valid_opcode(state.pc):
                raise utils.CodeError("Trying to execute PUSH data")
            elif op == 254:  # INVALID opcode
                raise utils.CodeError("designed INVALID opcode")
            elif op == opcode_values.JUMPDEST:
                pass
            elif op == opcode_values.ADD:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                state.stack_push(s0 + s1)
            elif op == opcode_values.SUB:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                state.stack_push(s0 - s1)
            elif op == opcode_values.MUL:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                state.stack_push(s0 * s1)
            elif op == opcode_values.DIV:
                # We need to use claripy.LShR instead of a division if possible,
                # because the solver is bad dealing with divisions, better
                # with shifts. And we need shifts to handle the solidity ABI
                # for function selection.
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                try:
                    s1 = solution(s1)  # pylint:disable=invalid-name
                except MultipleSolutionsError:
                    state.stack_push(claripy.If(s1 == 0, BVV_0, s0 / s1))
                else:
                    if s1 == 0:
                        state.stack_push(BVV_0)
                    elif s1 == 1:
                        state.stack_push(s0)
                    elif s1 & (s1 - 1) == 0:
                        exp = int(math.log(s1, 2))
                        state.stack_push(s0.LShR(exp))
                    else:
                        state.stack_push(s0 / s1)
            elif op == opcode_values.SDIV:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                try:
                    s1 = solution(s1)
                except MultipleSolutionsError:
                    state.stack_push(claripy.If(s1 == 0, BVV_0, s0.SDiv(s1)))
                else:
                    state.stack_push(BVV_0 if s1 == 0 else s0.SDiv(s1))
            elif op == opcode_values.MOD:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                try:
                    s1 = solution(s1)
                except MultipleSolutionsError:
                    state.stack_push(claripy.If(s1 == 0, BVV_0, s0 % s1))
                else:
                    state.stack_push(BVV_0 if s1 == 0 else s0 % s1)
            elif op == opcode_values.SMOD:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                try:
                    s1 = solution(s1)
                except MultipleSolutionsError:
                    state.stack_push(claripy.If(s1 == 0, BVV_0, s0.SMod(s1)))
                else:
                    state.stack_push(BVV_0 if s1 == 0 else s0.SMod(s1))
            elif op == opcode_values.ADDMOD:
                s0, s1, s2 = state.stack_pop(), state.stack_pop(
                ), state.stack_pop()
                try:
                    s2 = solution(s2)
                except MultipleSolutionsError:
                    state.stack_push(claripy.If(s2 == 0, BVV_0,
                                                (s0 + s1) % s2))
                else:
                    state.stack_push(BVV_0 if s2 == 0 else (s0 + s1) % s2)
            elif op == opcode_values.MULMOD:
                s0, s1, s2 = state.stack_pop(), state.stack_pop(
                ), state.stack_pop()
                try:
                    s2 = solution(s2)
                except MultipleSolutionsError:
                    state.stack_push(claripy.If(s2 == 0, BVV_0,
                                                (s0 * s1) % s2))
                else:
                    state.stack_push(BVV_0 if s2 == 0 else (s0 * s1) % s2)
            elif op == opcode_values.SHL:
                shift, value = state.stack_pop(), state.stack_pop()
                state.stack_push(value << shift)
            elif op == opcode_values.SHR:
                shift, value = state.stack_pop(), state.stack_pop()
                state.stack_push(value.LShR(shift))
            elif op == opcode_values.SAR:
                shift, value = state.stack_pop(), state.stack_pop()
                state.stack_push(claripy.RotateRight(value, shift))
            elif op == opcode_values.EXP:
                base, exponent = state.stack_pop(), state.stack_pop()
                base_sol = solution(base)
                if base_sol == 2:
                    state.stack_push(1 << exponent)
                else:
                    try:
                        exponent_sol = solution(exponent)
                    except MultipleSolutionsError:
                        state.stack_push(exponent)  # restore stack
                        state.stack_push(base)
                        self.add_for_fuzzing(state, exponent,
                                             EXP_EXPONENT_FUZZ)
                        return False
                    else:
                        state.stack_push(
                            claripy.BVV(base_sol**exponent_sol, 256))
            elif op == opcode_values.LT:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                state.stack_push(bool_to_bv(claripy.ULT(s0, s1)))
            elif op == opcode_values.GT:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                state.stack_push(bool_to_bv(claripy.UGT(s0, s1)))
            elif op == opcode_values.SLT:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                state.stack_push(bool_to_bv(claripy.SLT(s0, s1)))
            elif op == opcode_values.SGT:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                state.stack_push(bool_to_bv(claripy.SGT(s0, s1)))
            elif op == opcode_values.SIGNEXTEND:
                # TODO: Use Claripy's SignExt that should do exactly that.
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                # s0 is the number of bits. s1 the number we want to extend.
                s0 = solution(s0)
                if s0 <= 31:
                    sign_bit = 1 << (s0 * 8 + 7)
                    state.stack_push(
                        claripy.If(
                            s1 & sign_bit == 0,
                            s1 & (sign_bit - 1),
                            s1 | ((1 << 256) - sign_bit),
                        ))
                else:
                    state.stack_push(s1)
            elif op == opcode_values.EQ:
                s0, s1 = state.stack_pop(), state.stack_pop()
                state.stack_push(bool_to_bv(s0 == s1))
            elif op == opcode_values.ISZERO:
                state.stack_push(bool_to_bv(state.stack_pop() == BVV_0))
            elif op == opcode_values.AND:
                s0, s1 = state.stack_pop(), state.stack_pop()
                state.stack_push(s0 & s1)
            elif op == opcode_values.OR:
                s0, s1 = state.stack_pop(), state.stack_pop()
                state.stack_push(s0 | s1)
            elif op == opcode_values.XOR:
                s0, s1 = state.stack_pop(), state.stack_pop()
                state.stack_push(s0 ^ s1)
            elif op == opcode_values.NOT:
                state.stack_push(~state.stack_pop())
            elif op == opcode_values.BYTE:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                state.stack_push(
                    s1.LShR(claripy.If(s0 > 31, 32, 31 - s0) * 8) & 0xFF)

            elif op == opcode_values.PC:
                state.stack_push(bvv(state.pc))
            elif op == opcode_values.GAS:
                state.stack_push(state.env.gas)
            elif op == opcode_values.ADDRESS:
                state.stack_push(state.env.address)
            elif op == opcode_values.BALANCE:
                addr = solution(state.stack_pop())
                if addr != solution(state.env.address):
                    raise utils.InterpreterError(
                        state,
                        "Can only query balance of the current contract for now"
                    )
                state.stack_push(state.env.balance)
            elif op == opcode_values.ORIGIN:
                state.stack_push(state.env.origin)
            elif op == opcode_values.CALLER:
                state.stack_push(state.env.caller)
            elif op == opcode_values.CALLVALUE:
                state.stack_push(state.env.value)
            elif op == opcode_values.BLOCKHASH:
                block_num = state.stack_pop()
                if block_num not in state.env.block_hashes:
                    state.env.block_hashes[block_num] = claripy.BVS(
                        "blockhash[%s]" % block_num, 256)
                state.stack_push(state.env.block_hashes[block_num])
            elif op == opcode_values.TIMESTAMP:
                state.stack_push(state.env.block_timestamp)
            elif op == opcode_values.NUMBER:
                state.stack_push(state.env.block_number)
            elif op == opcode_values.COINBASE:
                state.stack_push(state.env.coinbase)
            elif op == opcode_values.DIFFICULTY:
                state.stack_push(state.env.difficulty)
            elif op == opcode_values.POP:
                state.stack_pop()
            elif op == opcode_values.JUMP:
                addr = solution(state.stack_pop())
                if addr >= len(self.code
                               ) or self.code[addr] != opcode_values.JUMPDEST:
                    raise utils.CodeError("Invalid jump (%i)" % addr)
                state.pc = addr
                self.add_branch(state)
                return False
            elif op == opcode_values.JUMPI:
                addr, condition = solution(
                    state.stack_pop()), state.stack_pop()
                state_false = state.copy()
                state.solver.add(condition != BVV_0)
                state_false.solver.add(condition == BVV_0)
                state_false.pc += 1
                self.add_branch(state_false)
                state.pc = addr
                if (state.pc >= len(self.code)
                        or self.code[state.pc] != opcode_values.JUMPDEST):
                    raise utils.CodeError("Invalid jump (%i)" % (state.pc - 1))
                self.add_branch(state)
                return False
            elif opcode_values.PUSH1 <= op <= opcode_values.PUSH32:
                pushnum = op - opcode_values.PUSH1 + 1
                raw_value = self.code.read(pushnum)
                state.pc += pushnum
                state.stack_push(
                    bvv(int.from_bytes(raw_value, byteorder="big")))
            elif opcode_values.DUP1 <= op <= opcode_values.DUP16:
                depth = op - opcode_values.DUP1 + 1
                state.stack_push(state.stack[-depth])
            elif opcode_values.SWAP1 <= op <= opcode_values.SWAP16:
                depth = op - opcode_values.SWAP1 + 1
                temp = state.stack[-depth - 1]
                state.stack[-depth - 1] = state.stack[-1]
                state.stack[-1] = temp
            elif opcode_values.LOG0 <= op <= opcode_values.LOG4:
                depth = op - opcode_values.LOG0
                mstart, msz = (state.stack_pop(), state.stack_pop())
                topics = [state.stack_pop() for x in range(depth)]
            elif op == opcode_values.SHA3:
                start, length = solution(state.stack_pop()), solution(
                    state.stack_pop())
                memory = state.memory.read(start, length)
                state.stack_push(Sha3(memory))
            elif op == opcode_values.STOP:
                return True
            elif op == opcode_values.RETURN:
                return True

            elif op == opcode_values.CALLDATALOAD:
                index = state.stack_pop()
                try:
                    index_sol = solution(index)
                except MultipleSolutionsError:
                    state.stack_push(index)  # restore the stack
                    self.add_for_fuzzing(state, index, CALLDATALOAD_INDEX_FUZZ)
                    return False
                state.stack_push(state.env.calldata.read(index_sol, 32))
            elif op == opcode_values.CALLDATASIZE:
                state.stack_push(state.env.calldata_size)
            elif op == opcode_values.CALLDATACOPY:
                old_state = state.copy()
                mstart, dstart, size = (
                    state.stack_pop(),
                    state.stack_pop(),
                    state.stack_pop(),
                )
                mstart, dstart = solution(mstart), solution(dstart)
                try:
                    size = solution(size)
                except MultipleSolutionsError:
                    self.add_for_fuzzing(old_state, size,
                                         CALLDATACOPY_SIZE_FUZZ)
                    return False
                state.memory.copy_from(state.env.calldata, mstart, dstart,
                                       size)
            elif op == opcode_values.CODESIZE:
                state.stack_push(bvv(len(self.code)))
            elif op == opcode_values.EXTCODESIZE:
                addr = state.stack_pop()
                if (addr == state.env.address).is_true():
                    state.stack_push(bvv(len(self.code)))
                else:
                    # TODO: Improve that... It's clearly not constraining enough.
                    state.stack_push(claripy.BVS("EXTCODESIZE[%s]" % addr,
                                                 256))

            elif op == opcode_values.EXTCODECOPY:
                old_state = state.copy()
                addr = state.stack_pop()
                mem_start = solution(state.stack_pop())
                code_start = solution(state.stack_pop())

                size = state.stack_pop()
                try:
                    size = solution(size)
                except MultipleSolutionsError:
                    # TODO: Fuzz.
                    # self.add_for_fuzzing(old_state, size, [])
                    # return False
                    raise
                state.memory.write(
                    mem_start,
                    size,
                    claripy.BVS("EXTCODE[%s from %s]" % (addr, code_start),
                                size * 8),
                )

            elif op == opcode_values.CODECOPY:
                mem_start, code_start, size = [
                    solution(state.stack_pop()) for _ in range(3)
                ]
                for i in range(size):
                    if code_start + i < len(state.env.code):
                        state.memory.write(
                            mem_start + i,
                            1,
                            claripy.BVV(state.env.code[code_start + i], 8),
                        )
                    else:
                        state.memory.write(mem_start + i, 1, claripy.BVV(0, 8))

            elif op == opcode_values.MLOAD:
                index = solution(state.stack_pop())
                state.stack_push(state.memory.read(index, 32))
            elif op == opcode_values.MSTORE:
                index, value = solution(state.stack_pop()), state.stack_pop()
                state.memory.write(index, 32, value)
            elif op == opcode_values.MSTORE8:
                index, value = solution(state.stack_pop()), state.stack_pop()
                state.memory.write(index, 1, value[7:0])
            elif op == opcode_values.MSIZE:
                state.stack_push(bvv(state.memory.size()))

            elif op == opcode_values.SLOAD:
                state.pc += 1
                key = state.stack_pop()
                for w_key, w_value in state.storage_written.items():
                    read_written = [w_key == key]
                    if state.solver.satisfiable(
                            extra_constraints=read_written):
                        new_state = state.copy()
                        new_state.solver.add(read_written)
                        new_state.stack_push(w_value)
                        self.add_branch(new_state)
                    state.solver.add(w_key != key)
                if state.solver.satisfiable():
                    assert key not in state.storage_written
                    if key not in state.storage_read:
                        state.storage_read[key] = claripy.BVS(
                            "storage[%s]" % key, 256)
                    state.stack_push(state.storage_read[key])
                    self.add_branch(state)
                return

            elif op == opcode_values.SSTORE:
                state.pc += 1
                key = state.stack_pop()
                value = state.stack_pop()
                for w_key, w_value in state.storage_written.items():
                    read_written = [w_key == key]
                    if state.solver.satisfiable(
                            extra_constraints=read_written):
                        new_state = state.copy()
                        new_state.solver.add(read_written)
                        new_state.storage_written[w_key] = value
                        self.add_branch(new_state)
                        state.solver.add(w_key != key)
                if state.solver.satisfiable():
                    assert key not in state.storage_written
                    state.storage_written[key] = value
                    self.add_branch(state)
                return

            elif op == opcode_values.CALL:
                state.pc += 1

                # pylint:disable=unused-variable
                gas, to_, value, meminstart, meminsz, memoutstart, memoutsz = (
                    state.stack_pop() for _ in range(7))

                # First possibility: the call fails
                # (always possible with a call stack big enough)
                state_fail = state.copy()
                state_fail.stack_push(BVV_0)
                self.add_branch(state_fail)

                # Second possibility: success.
                state.calls.append((memoutsz, memoutstart, meminsz, meminstart,
                                    value, to_, gas))

                memoutsz = solution(memoutsz)
                if memoutsz != 0:
                    # If we expect some output, let's constraint the call to
                    # be to a contract that we do control. Otherwise it could
                    # return anything...
                    state.solver.add(to_[159:0] == utils.DEFAULT_CALLER[159:0])

                    memoutstart = solution(memoutstart)
                    state.memory.write(
                        memoutstart,
                        memoutsz,
                        claripy.BVS("CALL_RETURN[%s]" % to_, memoutsz * 8),
                    )

                state.stack_push(BVV_1)
                self.add_branch(state)
                return False

            elif op == opcode_values.DELEGATECALL:
                state.pc += 1

                # pylint:disable=unused-variable
                gas, to_, meminstart, meminsz, memoutstart, memoutsz = (
                    state.stack_pop() for _ in range(6))

                # First possibility: the call fails
                # (always possible with a call stack big enough)
                state_fail = state.copy()
                state_fail.stack_push(BVV_0)
                self.add_branch(state_fail)

                # If the call is to a specific contract we don't control,
                # don't assume it could return anything, or even be successful.
                # So we say we need to be able to call an arbitrary contract.
                state.solver.add(to_[159:0] == utils.DEFAULT_CALLER[159:0])

                # Second possibility: success.
                state.calls.append(
                    (memoutsz, memoutstart, meminsz, meminstart, to_, gas))

                memoutsz = solution(memoutsz)
                if memoutsz != 0:
                    memoutstart = solution(memoutstart)
                    state.memory.write(
                        memoutstart,
                        memoutsz,
                        claripy.BVS("DELEGATECALL_RETURN[%s]" % to_,
                                    memoutsz * 8),
                    )

                state.stack_push(BVV_1)
                self.add_branch(state)
                return False

            elif op == opcode_values.RETURNDATASIZE:
                state.stack_push(claripy.BVS("RETURNDATASIZE", 256))

            elif op == opcode_values.RETURNDATACOPY:
                old_state = state.copy()
                mem_start_position = solution(state.stack_pop())
                returndata_start_position = solution(state.stack_pop())

                size = state.stack_pop()
                try:
                    size = solution(size)
                except MultipleSolutionsError:
                    self.add_for_fuzzing(old_state, size,
                                         RETURNDATACOPY_SIZE_FUZZ)
                    return False

                state.memory.write(mem_start_position, size,
                                   claripy.BVS("RETURNDATACOPY", size * 8))

            elif op == opcode_values.SELFDESTRUCT:
                state.selfdestruct_to = state.stack[-1]
                return True

            elif op == opcode_values.REVERT:
                return False

            else:
                raise utils.InterpreterError(state, "Unknown opcode %#x" % op)

            state.pc += 1