def _translate_bsh(self, oprnd1, oprnd2, oprnd3):
        """Return a formula representation of a BSH instruction.
        """
        assert oprnd1.size and oprnd2.size and oprnd3.size
        assert oprnd1.size == oprnd2.size

        op1_var = self._translate_src_oprnd(oprnd1)
        op2_var = self._translate_src_oprnd(oprnd2)
        op3_var, op3_var_constrs = self._translate_dst_oprnd(oprnd3)

        if oprnd3.size > oprnd1.size:
            op1_var_zx = smtfunction.zero_extend(op1_var, oprnd3.size)
            op2_var_zx = smtfunction.zero_extend(op2_var, oprnd3.size)
            op2_var_neg_sx = smtfunction.sign_extend(-op2_var, oprnd3.size)

            shr = smtfunction.extract(op1_var_zx >> op2_var_neg_sx, 0,
                                      op3_var.size)
            shl = smtfunction.extract(op1_var_zx << op2_var_zx, 0,
                                      op3_var.size)
        elif oprnd3.size < oprnd1.size:
            shr = smtfunction.extract(op1_var >> -op2_var, 0, op3_var.size)
            shl = smtfunction.extract(op1_var << op2_var, 0, op3_var.size)
        else:
            shr = op1_var >> -op2_var
            shl = op1_var << op2_var

        result = smtfunction.ite(oprnd3.size, op2_var >= 0, shl, shr)

        return [op3_var == result] + op3_var_constrs
    def _translate_bsh(self, oprnd1, oprnd2, oprnd3):
        """Return a formula representation of a BSH instruction.
        """
        assert oprnd1.size and oprnd2.size and oprnd3.size
        assert oprnd1.size == oprnd2.size

        op1_var = self._translate_src_oprnd(oprnd1)
        op2_var = self._translate_src_oprnd(oprnd2)
        op3_var, op3_var_constrs = self._translate_dst_oprnd(oprnd3)

        if oprnd3.size > oprnd1.size:
            op1_var_zx = smtfunction.zero_extend(op1_var, oprnd3.size)
            op2_var_zx = smtfunction.zero_extend(op2_var, oprnd3.size)
            op2_var_neg_sx = smtfunction.sign_extend(-op2_var, oprnd3.size)

            shr = smtfunction.extract(op1_var_zx >> op2_var_neg_sx, 0, op3_var.size)
            shl = smtfunction.extract(op1_var_zx << op2_var_zx, 0, op3_var.size)
        elif oprnd3.size < oprnd1.size:
            shr = smtfunction.extract(op1_var >> -op2_var, 0, op3_var.size)
            shl = smtfunction.extract(op1_var << op2_var, 0, op3_var.size)
        else:
            shr = op1_var >> -op2_var
            shl = op1_var << op2_var

        result = smtfunction.ite(oprnd3.size, op2_var >= 0, shl, shr)

        return [op3_var == result] + op3_var_constrs
    def test_extract(self):
        x = BitVec(32, "x")
        x0 = extract(x, 0, 8)
        x1 = extract(x, 8, 8)
        x2 = extract(x, 16, 8)
        x3 = extract(x, 24, 8)

        self.assertEqual(x0.value, "((_ extract 7 0) x)")
        self.assertEqual(x1.value, "((_ extract 15 8) x)")
        self.assertEqual(x2.value, "((_ extract 23 16) x)")
        self.assertEqual(x3.value, "((_ extract 31 24) x)")
    def test_extract(self):
        x = BitVec(32, "x")
        x0 = extract(x, 0, 8)
        x1 = extract(x, 8, 8)
        x2 = extract(x, 16, 8)
        x3 = extract(x, 24, 8)

        self.assertEqual(x0.value, "((_ extract 7 0) x)")
        self.assertEqual(x1.value, "((_ extract 15 8) x)")
        self.assertEqual(x2.value, "((_ extract 23 16) x)")
        self.assertEqual(x3.value, "((_ extract 31 24) x)")
    def _translate_dst_register_oprnd(self, operand):
        """Translate destination register operand to SMT expr.
        """
        reg_info = self._arch_alias_mapper.get(operand.name, None)

        parent_reg_constrs = []

        if reg_info:
            var_base_name, offset = reg_info

            var_name_old = self._get_var_name(var_base_name, fresh=False)
            var_name_new = self._get_var_name(var_base_name, fresh=True)
            var_size = self._arch_regs_size[var_base_name]

            ret_val_old = self.make_bitvec(var_size, var_name_old)
            ret_val_new = self.make_bitvec(var_size, var_name_new)

            ret_val = smtfunction.extract(ret_val_new, offset, operand.size)

            if 0 < offset < var_size - 1:
                lower_expr_1 = smtfunction.extract(ret_val_new, 0, offset)
                lower_expr_2 = smtfunction.extract(ret_val_old, 0, offset)

                parent_reg_constrs += [lower_expr_1 == lower_expr_2]

                upper_expr_1 = smtfunction.extract(
                    ret_val_new, offset + operand.size,
                    var_size - offset - operand.size)
                upper_expr_2 = smtfunction.extract(
                    ret_val_old, offset + operand.size,
                    var_size - offset - operand.size)

                parent_reg_constrs += [upper_expr_1 == upper_expr_2]
            elif offset == 0:
                upper_expr_1 = smtfunction.extract(
                    ret_val_new, offset + operand.size,
                    var_size - offset - operand.size)
                upper_expr_2 = smtfunction.extract(
                    ret_val_old, offset + operand.size,
                    var_size - offset - operand.size)

                parent_reg_constrs += [upper_expr_1 == upper_expr_2]
            elif offset == var_size - 1:
                lower_expr_1 = smtfunction.extract(ret_val_new, 0, offset)
                lower_expr_2 = smtfunction.extract(ret_val_old, 0, offset)

                parent_reg_constrs += [lower_expr_1 == lower_expr_2]
        else:
            var_name_new = self._get_var_name(operand.name, fresh=True)

            ret_val = self.make_bitvec(operand.size, var_name_new)

        return ret_val, parent_reg_constrs
    def _get_constrs_arithmetic_load(self, gadget):
        """Generate constraints for the ArithmeticLoad gadget: dst_reg <- dst_reg OP mem[src_reg + offset]
        """
        op = self._arithmetic_ops[gadget.operation]
        dst = self.analyzer.get_register_expr(gadget.destination[0].name,
                                              mode="post")
        size = gadget.destination[0].size

        if isinstance(gadget.sources[1], ReilRegisterOperand):
            base_addr = self.analyzer.get_register_expr(gadget.sources[1].name,
                                                        mode="pre")
            offset = gadget.sources[2].immediate

            addr = base_addr + offset
        else:
            addr = gadget.sources[2].immediate

        src1 = self.analyzer.get_register_expr(gadget.sources[0].name,
                                               mode="pre")
        src2 = self.analyzer.get_memory_expr(addr, size / 8)

        result = op(src1, src2)

        constrs = []

        for i in reversed(xrange(0, size, 8)):
            bytes_exprs_1 = smtfunction.extract(result, i, 8)
            bytes_exprs_2 = smtfunction.extract(dst, i, 8)

            constrs += [bytes_exprs_1 != bytes_exprs_2]

        # Check all non-modified registers don't change.
        constrs_mod = []

        for name in self._arch_info.registers_gp_base:
            if name not in [r.name for r in gadget.modified_registers]:
                var_initial = self.analyzer.get_register_expr(name, mode="pre")
                var_final = self.analyzer.get_register_expr(name, mode="post")

                constrs_mod += [var_initial != var_final]

        if constrs_mod:
            constrs_mod = [
                reduce(lambda c, acc: acc | c, constrs_mod[1:], constrs_mod[0])
            ]

        return constrs + constrs_mod
    def _get_constrs_arithmetic_load(self, gadget):
        """Generate constraints for the ArithmeticLoad gadgets: dst_reg <- dst_reg OP mem[src_reg + offset]
        """
        op = self._arithmetic_ops[gadget.operation]
        dst = self.analyzer.get_register_expr(gadget.destination[0].name, mode="post")
        size = gadget.destination[0].size

        if isinstance(gadget.sources[1], ReilRegisterOperand):
            base_addr = self.analyzer.get_register_expr(gadget.sources[1].name, mode="pre")
            offset = gadget.sources[2].immediate

            addr = base_addr + offset
        else:
            addr = gadget.sources[2].immediate

        src1 = self.analyzer.get_register_expr(gadget.sources[0].name, mode="pre")
        src2 = self.analyzer.get_memory_expr(addr, size // 8)

        result = op(src1, src2)

        constrs = []

        for i in reversed(range(0, size, 8)):
            bytes_exprs_1 = smtfunction.extract(result, i, 8)
            bytes_exprs_2 = smtfunction.extract(dst, i, 8)

            constrs += [bytes_exprs_1 != bytes_exprs_2]

        # Check all non-modified registers don't change.
        constrs_mod = []

        for name in self._arch_info.registers_gp_base:
            if name not in [r.name for r in gadget.modified_registers]:
                var_initial = self.analyzer.get_register_expr(name, mode="pre")
                var_final = self.analyzer.get_register_expr(name, mode="post")

                constrs_mod += [var_initial != var_final]

        if constrs_mod:
            constrs_mod = [reduce(lambda c, acc: acc | c, constrs_mod[1:], constrs_mod[0])]

        return constrs + constrs_mod
    def _translate_dst_register_oprnd(self, operand):
        """Translate destination register operand to SMT expr.
        """
        reg_info = self._arch_alias_mapper.get(operand.name, None)

        parent_reg_constrs = []

        if reg_info:
            var_base_name, offset = reg_info

            var_name_old = self._get_var_name(var_base_name, fresh=False)
            var_name_new = self._get_var_name(var_base_name, fresh=True)
            var_size = self._arch_regs_size[var_base_name]

            ret_val_old = self.make_bitvec(var_size, var_name_old)
            ret_val_new = self.make_bitvec(var_size, var_name_new)

            ret_val = smtfunction.extract(ret_val_new, offset, operand.size)

            if 0 < offset < var_size - 1:
                lower_expr_1 = smtfunction.extract(ret_val_new, 0, offset)
                lower_expr_2 = smtfunction.extract(ret_val_old, 0, offset)

                parent_reg_constrs += [lower_expr_1 == lower_expr_2]

                upper_expr_1 = smtfunction.extract(ret_val_new, offset + operand.size, var_size - offset - operand.size)
                upper_expr_2 = smtfunction.extract(ret_val_old, offset + operand.size, var_size - offset - operand.size)

                parent_reg_constrs += [upper_expr_1 == upper_expr_2]
            elif offset == 0:
                upper_expr_1 = smtfunction.extract(ret_val_new, offset + operand.size, var_size - offset - operand.size)
                upper_expr_2 = smtfunction.extract(ret_val_old, offset + operand.size, var_size - offset - operand.size)

                parent_reg_constrs += [upper_expr_1 == upper_expr_2]
            elif offset == var_size-1:
                lower_expr_1 = smtfunction.extract(ret_val_new, 0, offset)
                lower_expr_2 = smtfunction.extract(ret_val_old, 0, offset)

                parent_reg_constrs += [lower_expr_1 == lower_expr_2]
        else:
            var_name_new = self._get_var_name(operand.name, fresh=True)

            ret_val = self.make_bitvec(operand.size, var_name_new)

        return ret_val, parent_reg_constrs
    def _translate_ldm(self, oprnd1, oprnd2, oprnd3):
        """Return a formula representation of a LDM instruction.
        """
        assert oprnd1.size and oprnd3.size
        assert oprnd1.size == self._address_size

        op1_var = self._translate_src_oprnd(oprnd1)
        op3_var, op3_var_constrs = self._translate_dst_oprnd(oprnd3)

        exprs = []

        for i in reversed(range(0, oprnd3.size, 8)):
            exprs += [self._mem_curr[op1_var + i // 8] == smtfunction.extract(op3_var, i, 8)]

        return exprs + op3_var_constrs
    def _translate_str(self, oprnd1, oprnd2, oprnd3):
        """Return a formula representation of a STR instruction.
        """
        assert oprnd1.size and oprnd3.size

        op1_var = self._translate_src_oprnd(oprnd1)
        op3_var, op3_var_constrs = self._translate_dst_oprnd(oprnd3)

        if oprnd3.size > oprnd1.size:
            result = smtfunction.zero_extend(op1_var, op3_var.size)
        elif oprnd3.size < oprnd1.size:
            result = smtfunction.extract(op1_var, 0, op3_var.size)
        else:
            result = op1_var

        return [op3_var == result] + op3_var_constrs
    def _translate_str(self, oprnd1, oprnd2, oprnd3):
        """Return a formula representation of a STR instruction.
        """
        assert oprnd1.size and oprnd3.size

        op1_var = self._translate_src_oprnd(oprnd1)
        op3_var, op3_var_constrs = self._translate_dst_oprnd(oprnd3)

        if oprnd3.size > oprnd1.size:
            result = smtfunction.zero_extend(op1_var, op3_var.size)
        elif oprnd3.size < oprnd1.size:
            result = smtfunction.extract(op1_var, 0, op3_var.size)
        else:
            result = op1_var

        return [op3_var == result] + op3_var_constrs
    def _translate_ldm(self, oprnd1, oprnd2, oprnd3):
        """Return a formula representation of a LDM instruction.
        """
        assert oprnd1.size and oprnd3.size
        assert oprnd1.size == self._address_size

        op1_var = self._translate_src_oprnd(oprnd1)
        op3_var, op3_var_constrs = self._translate_dst_oprnd(oprnd3)

        exprs = []

        for i in reversed(xrange(0, oprnd3.size, 8)):
            exprs += [
                self._mem_curr[op1_var + i / 8] == smtfunction.extract(
                    op3_var, i, 8)
            ]

        return exprs + op3_var_constrs
    def _translate_src_register_oprnd(self, operand):
        """Translate source register operand to SMT expr.
        """
        reg_info = self._arch_alias_mapper.get(operand.name, None)

        if reg_info:
            var_base_name, offset = reg_info

            var_size = self._arch_regs_size[var_base_name]
        else:
            var_base_name = operand.name
            var_size = operand.size

        var_name = self._get_var_name(var_base_name)
        ret_val = self.make_bitvec(var_size, var_name)

        if reg_info:
            ret_val = smtfunction.extract(ret_val, offset, operand.size)

        return ret_val
    def get_register_expr(self, register_name, mode="post"):
        """Return a smt bit vector that represents an architectural (native)
        register.
        """
        reg_info = self._arch_info.alias_mapper.get(register_name, None)

        if reg_info:
            var_base_name, offset = reg_info
        else:
            var_base_name = register_name

        var_name = self._get_var_name(var_base_name, mode)
        var_size = self._arch_info.registers_size[var_base_name]

        ret_val = self._translator.make_bitvec(var_size, var_name)

        if reg_info:
            ret_val = smtfunction.extract(ret_val, offset, self._arch_info.registers_size[register_name])

        return ret_val
    def _translate_src_register_oprnd(self, operand):
        """Translate source register operand to SMT expr.
        """
        reg_info = self._arch_alias_mapper.get(operand.name, None)

        if reg_info:
            var_base_name, offset = reg_info

            var_size = self._arch_regs_size[var_base_name]
        else:
            var_base_name = operand.name
            var_size = operand.size

        var_name = self._get_var_name(var_base_name)
        ret_val = self.make_bitvec(var_size, var_name)

        if reg_info:
            ret_val = smtfunction.extract(ret_val, offset, operand.size)

        return ret_val
Exemple #16
0
    def _get_constrs_store_memory(self, gadget):
        """Generate constraints for the StoreMemory gadgets: mem[dst_reg + offset] <- src_reg
        """
        if isinstance(gadget.destination[0], ReilRegisterOperand):
            base_addr = self.analyzer.get_register_expr(
                gadget.destination[0].name, mode="pre")
            offset = gadget.destination[1].immediate

            addr = base_addr + offset
        else:
            addr = gadget.destination[1].immediate

        src = self.analyzer.get_register_expr(gadget.sources[0].name,
                                              mode="pre")
        size = gadget.sources[0].size

        constrs = []

        for i in reversed(range(0, size, 8)):
            bytes_exprs_1 = self.analyzer.get_memory_expr(
                addr + i // 8, 8 // 8)
            bytes_exprs_2 = smtfunction.extract(src, i, 8)

            constrs += [bytes_exprs_1 != bytes_exprs_2]

        # Check all non-modified registers don't change.
        constrs_mod = []

        for name in self._arch_info.registers_gp_base:
            if name not in [r.name for r in gadget.modified_registers]:
                var_initial = self.analyzer.get_register_expr(name, mode="pre")
                var_final = self.analyzer.get_register_expr(name, mode="post")

                constrs_mod += [var_initial != var_final]

        if constrs_mod:
            constrs_mod = [
                reduce(lambda c, acc: acc | c, constrs_mod[1:], constrs_mod[0])
            ]

        return constrs + constrs_mod
    def _translate_smul(self, oprnd1, oprnd2, oprnd3):
        """Return a formula representation of an MUL instruction.
        """
        assert oprnd1.size and oprnd2.size and oprnd3.size
        assert oprnd1.size == oprnd2.size

        op1_var = self._translate_src_oprnd(oprnd1)
        op2_var = self._translate_src_oprnd(oprnd2)
        op3_var, op3_var_constrs = self._translate_dst_oprnd(oprnd3)

        if oprnd3.size > oprnd1.size:
            op1_var_sx = smtfunction.sign_extend(op1_var, oprnd3.size)
            op2_var_sx = smtfunction.sign_extend(op2_var, oprnd3.size)

            result = op1_var_sx * op2_var_sx
        elif oprnd3.size < oprnd1.size:
            result = smtfunction.extract(op1_var * op2_var, 0, oprnd3.size)
        else:
            result = op1_var * op2_var

        return [op3_var == result] + op3_var_constrs
    def _translate_stm(self, oprnd1, oprnd2, oprnd3):
        """Return a formula representation of a STM instruction.
        """
        assert oprnd1.size and oprnd3.size
        assert oprnd3.size == self._address_size

        op1_var = self._translate_src_oprnd(oprnd1)
        op3_var = self._translate_src_oprnd(oprnd3)

        for i in range(0, oprnd1.size, 8):
            self._mem_curr[op3_var + i//8] = smtfunction.extract(op1_var, i, 8)

        # Memory versioning.
        self._mem_instance += 1

        mem_old = self._mem_curr
        mem_new = self.make_array(self._address_size, "MEM_{}".format(self._mem_instance))

        self._mem_curr = mem_new

        return [mem_new == mem_old]
Exemple #19
0
    def get_register_expr(self, register_name, mode="post"):
        """Return a smt bit vector that represents an architectural (native)
        register.
        """
        reg_info = self._arch_info.alias_mapper.get(register_name, None)

        if reg_info:
            var_base_name, offset = reg_info
        else:
            var_base_name = register_name

        var_name = self._get_var_name(var_base_name, mode)
        var_size = self._arch_info.registers_size[var_base_name]

        ret_val = self._translator.make_bitvec(var_size, var_name)

        if reg_info:
            ret_val = smtfunction.extract(
                ret_val, offset, self._arch_info.registers_size[register_name])

        return ret_val
    def _translate_mod(self, oprnd1, oprnd2, oprnd3):
        """Return a formula representation of an MOD instruction.
        """
        assert oprnd1.size and oprnd2.size and oprnd3.size
        assert oprnd1.size == oprnd2.size

        op1_var = self._translate_src_oprnd(oprnd1)
        op2_var = self._translate_src_oprnd(oprnd2)
        op3_var, op3_var_constrs = self._translate_dst_oprnd(oprnd3)

        if oprnd3.size > oprnd1.size:
            op1_var_zx = smtfunction.zero_extend(op1_var, oprnd3.size)
            op2_var_zx = smtfunction.zero_extend(op2_var, oprnd3.size)

            result = op1_var_zx.umod(op2_var_zx)
        elif oprnd3.size < oprnd1.size:
            result = smtfunction.extract(op1_var.umod(op2_var), 0, oprnd3.size)
        else:
            result = op1_var.umod(op2_var)

        return [op3_var == result] + op3_var_constrs
    def _translate_div(self, oprnd1, oprnd2, oprnd3):
        """Return a formula representation of an DIV instruction.
        """
        assert oprnd1.size and oprnd2.size and oprnd3.size
        assert oprnd1.size == oprnd2.size

        op1_var = self._translate_src_oprnd(oprnd1)
        op2_var = self._translate_src_oprnd(oprnd2)
        op3_var, op3_var_constrs = self._translate_dst_oprnd(oprnd3)

        if oprnd3.size > oprnd1.size:
            op1_var_zx = smtfunction.zero_extend(op1_var, oprnd3.size)
            op2_var_zx = smtfunction.zero_extend(op2_var, oprnd3.size)

            result = op1_var_zx.udiv(op2_var_zx)
        elif oprnd3.size < oprnd1.size:
            result = smtfunction.extract(op1_var.udiv(op2_var), 0, oprnd3.size)
        else:
            result = op1_var.udiv(op2_var)

        return [op3_var == result] + op3_var_constrs
    def _translate_smod(self, oprnd1, oprnd2, oprnd3):
        """Return a formula representation of an MOD instruction.
        """
        assert oprnd1.size and oprnd2.size and oprnd3.size
        assert oprnd1.size == oprnd2.size

        op1_var = self._translate_src_oprnd(oprnd1)
        op2_var = self._translate_src_oprnd(oprnd2)
        op3_var, op3_var_constrs = self._translate_dst_oprnd(oprnd3)

        if oprnd3.size > oprnd1.size:
            op1_var_sx = smtfunction.sign_extend(op1_var, oprnd3.size)
            op2_var_sx = smtfunction.sign_extend(op2_var, oprnd3.size)

            result = op1_var_sx % op2_var_sx
        elif oprnd3.size < oprnd1.size:
            result = smtfunction.extract(op1_var % op2_var, 0, oprnd3.size)
        else:
            result = op1_var % op2_var

        return [op3_var == result] + op3_var_constrs
    def _translate_stm(self, oprnd1, oprnd2, oprnd3):
        """Return a formula representation of a STM instruction.
        """
        assert oprnd1.size and oprnd3.size
        assert oprnd3.size == self._address_size

        op1_var = self._translate_src_oprnd(oprnd1)
        op3_var = self._translate_src_oprnd(oprnd3)

        for i in xrange(0, oprnd1.size, 8):
            self._mem_curr[op3_var + i / 8] = smtfunction.extract(
                op1_var, i, 8)

        # Memory versioning.
        self._mem_instance += 1

        mem_old = self._mem_curr
        mem_new = self.make_array(self._address_size,
                                  "MEM_{}".format(self._mem_instance))

        self._mem_curr = mem_new

        return [mem_new == mem_old]
    def _get_constrs_store_memory(self, gadget):
        """Generate constraints for the StoreMemory gadgets: mem[dst_reg + offset] <- src_reg
        """
        if isinstance(gadget.destination[0], ReilRegisterOperand):
            base_addr = self.analyzer.get_register_expr(gadget.destination[0].name, mode="pre")
            offset = gadget.destination[1].immediate

            addr = base_addr + offset
        else:
            addr = gadget.destination[1].immediate

        src = self.analyzer.get_register_expr(gadget.sources[0].name, mode="pre")
        size = gadget.sources[0].size

        constrs = []

        for i in reversed(range(0, size, 8)):
            bytes_exprs_1 = self.analyzer.get_memory_expr(addr + i // 8, 8 // 8)
            bytes_exprs_2 = smtfunction.extract(src, i, 8)

            constrs += [bytes_exprs_1 != bytes_exprs_2]

        # Check all non-modified registers don't change.
        constrs_mod = []

        for name in self._arch_info.registers_gp_base:
            if name not in [r.name for r in gadget.modified_registers]:
                var_initial = self.analyzer.get_register_expr(name, mode="pre")
                var_final = self.analyzer.get_register_expr(name, mode="post")

                constrs_mod += [var_initial != var_final]

        if constrs_mod:
            constrs_mod = [reduce(lambda c, acc: acc | c, constrs_mod[1:], constrs_mod[0])]

        return constrs + constrs_mod