Example #1
0
    def _ail_handle_Sub(self, expr):

        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        x_0, c_0, x_1, c_1 = None, None, None, None
        if isinstance(operand_1, Expr.BinaryOp) \
            and isinstance(operand_1.operands[1], Expr.Const) \
                and operand_1.op == 'Mul':
            if isinstance(operand_1.operands[0], Expr.BinaryOp) \
                and isinstance(operand_1.operands[0].operands[1], Expr.Const) \
                    and operand_1.operands[0].op in ['Div', 'DivMod']:
                x_0 = operand_1.operands[0].operands[0]
                x_1 = operand_0
                c_0 = operand_1.operands[1]
                c_1 = operand_1.operands[0].operands[1]
            elif isinstance(operand_1.operands[0], Expr.Convert) \
                and isinstance(operand_1.operands[0].operand, Expr.BinaryOp) \
                    and operand_1.operands[0].operand.op in ['Div', 'DivMod']:
                x_0 = operand_1.operands[0].operand.operands[0]
                x_1 = operand_0
                c_0 = operand_1.operands[1]
                c_1 = operand_1.operands[0].operand.operands[1]

            if x_0 is not None and x_1 is not None and x_0 == x_1 and c_0.value == c_1.value:
                return Expr.BinaryOp(expr.idx, 'Mod', [x_0, c_0], expr.signed,
                                     **expr.tags)
        if (operand_0, operand_1) != (expr.operands[0], expr.operands[1]):
            return Expr.BinaryOp(expr.idx, 'Sub', [operand_0, operand_1],
                                 expr.signed, **expr.tags)
        return expr
Example #2
0
    def _ail_handle_Convert(self, expr: Expr.Convert):
        operand_expr = self._expr(expr.operand)
        # import ipdb; ipdb.set_trace()

        if type(operand_expr) is Expr.Convert:
            if expr.from_bits == operand_expr.to_bits and expr.to_bits == operand_expr.from_bits:
                # eliminate the redundant Convert
                return operand_expr.operand
            else:
                return Expr.Convert(expr.idx, operand_expr.from_bits,
                                    expr.to_bits, expr.is_signed,
                                    operand_expr.operand, **expr.tags)
        elif type(operand_expr) is Expr.Const:
            # do the conversion right away
            value = operand_expr.value
            mask = (2**expr.to_bits) - 1
            value &= mask
            return Expr.Const(expr.idx, operand_expr.variable, value,
                              expr.to_bits, **expr.tags)
        elif type(operand_expr) is Expr.BinaryOp \
            and operand_expr.op in {'Mul', 'Shl', 'Div', 'DivMod', 'Add', 'Sub'}:
            if isinstance(operand_expr.operands[1], Expr.Const):
                if isinstance(operand_expr.operands[0], Expr.Register) and \
                        expr.from_bits == operand_expr.operands[0].bits:
                    converted = Expr.Convert(expr.idx, expr.from_bits,
                                             expr.to_bits, expr.is_signed,
                                             operand_expr.operands[0])
                    return Expr.BinaryOp(operand_expr.idx, operand_expr.op,
                                         [converted, operand_expr.operands[1]],
                                         operand_expr.signed, **expr.tags)
                # TODO: the below optimization was unsound
                # Conv(32->64, (Conv(64->32, r14<8>) + 0x1<32>)) became Add(r14<8>, 0x1<32>)
                # ideally it should become Conv(32->64, Conv(64->32, r14<8> + 0x1<64>))
                # and then the double convert can be pretty-printed away
                #elif isinstance(operand_expr.operands[0], Expr.Convert) and \
                #        expr.from_bits == operand_expr.operands[0].to_bits and \
                #        expr.to_bits == operand_expr.operands[0].from_bits:
                #    return Expr.BinaryOp(operand_expr.idx, operand_expr.op,
                #                         [operand_expr.operands[0].operand, operand_expr.operands[1]],
                #                         operand_expr.signed,
                #                         **operand_expr.tags)
            elif isinstance(operand_expr.operands[0], Expr.Convert) \
                    and isinstance(operand_expr.operands[1], Expr.Convert) \
                    and operand_expr.operands[0].from_bits == operand_expr.operands[1].from_bits:
                if operand_expr.operands[0].to_bits == operand_expr.operands[1].to_bits \
                        and expr.from_bits == operand_expr.operands[0].to_bits \
                        and expr.to_bits == operand_expr.operands[1].from_bits:
                    return Expr.BinaryOp(operand_expr.idx, operand_expr.op, [
                        operand_expr.operands[0].operand,
                        operand_expr.operands[1].operand
                    ], expr.is_signed, **operand_expr.tags)

        converted = Expr.Convert(expr.idx, expr.from_bits, expr.to_bits,
                                 expr.is_signed, operand_expr, **expr.tags)
        return converted
Example #3
0
    def _ail_handle_Convert(self, expr):
        if expr.from_bits == 128 and expr.to_bits == 64:
            operand_expr = self._expr(expr.operand)
            if isinstance(operand_expr, Expr.BinaryOp) \
                    and operand_expr.op == 'Mul' \
                    and isinstance(operand_expr.operands[1], Expr.Const) \
                    and isinstance(operand_expr.operands[0], Expr.BinaryOp):
                if operand_expr.operands[0].op in {'Shr', 'DivMod'} \
                        and isinstance(operand_expr.operands[0].operands[1], Expr.Const):
                    if operand_expr.operands[0].op == 'Shr':
                        Y = operand_expr.operands[0].operands[1].value
                    else:
                        Y = int(
                            math.log2(
                                operand_expr.operands[0].operands[1].value))
                    C = operand_expr.operands[1].value
                    divisor = self._check_divisor(pow(2, 64 + Y), C)
                    if divisor:
                        X = operand_expr.operands[0].operands[0]
                        new_const = Expr.Const(expr.idx, None, divisor, 64)
                        return Expr.BinaryOp(expr.idx, 'DivMod',
                                             [X, new_const], expr.signed,
                                             **expr.tags)

        if expr.from_bits == 64 and expr.to_bits == 32 \
                and isinstance(expr.operand, Expr.BinaryOp) and expr.operand.op == "Shr" \
                and isinstance(expr.operand.operands[1], Expr.Const) and expr.operand.operands[1].value == expr.to_bits:
            inner = expr.operand.operands[0]
            if isinstance(inner, Expr.BinaryOp) and inner.op == "Mull":
                operand_0, operand_1 = inner.operands

                if isinstance(operand_1, Expr.Const) and not isinstance(
                        operand_0, Expr.Const):
                    # swap them
                    operand_0, operand_1 = operand_1, operand_0

                if isinstance(operand_0, Expr.Const) and not isinstance(
                        operand_1, Expr.Const) and operand_0.bits == 32:
                    bits = operand_0.bits
                    C = operand_0.value
                    X = operand_1
                    V = bits
                    ndigits = 5 if V == 32 else 6
                    divisor = self._check_divisor(pow(2, V), C, ndigits)
                    if divisor is not None and X:
                        new_const = Expr.Const(None, None, divisor, V)
                        new_expr = Expr.BinaryOp(inner.idx, 'Div',
                                                 [X, new_const], inner.signed,
                                                 **inner.tags)
                        return new_expr

        return super()._ail_handle_Convert(expr)
Example #4
0
    def _ail_handle_Convert(self, expr):
        operand_expr = self._expr(expr.operand)
        # import ipdb; ipdb.set_trace()

        if type(operand_expr) is Expr.Convert:
            if expr.from_bits == operand_expr.to_bits and expr.to_bits == operand_expr.from_bits:
                # eliminate the redundant Convert
                return operand_expr.operand
            else:
                return Expr.Convert(expr.idx, operand_expr.from_bits,
                                    expr.to_bits, expr.is_signed,
                                    operand_expr.operand, **expr.tags)
        elif type(operand_expr) is Expr.Const:
            # do the conversion right away
            value = operand_expr.value
            mask = (2**expr.to_bits) - 1
            value &= mask
            return Expr.Const(expr.idx, operand_expr.variable, value,
                              expr.to_bits, **expr.tags)
        elif type(operand_expr) is Expr.BinaryOp \
            and operand_expr.op in {'Mul', 'Shl', 'Div', 'DivMod', 'Add', 'Sub'}:
            if isinstance(operand_expr.operands[1], Expr.Const):
                if isinstance(operand_expr.operands[0], Expr.Register) and \
                        expr.from_bits == operand_expr.operands[0].bits:
                    converted = Expr.Convert(expr.idx, expr.from_bits,
                                             expr.to_bits, expr.is_signed,
                                             operand_expr.operands[0])
                    return Expr.BinaryOp(operand_expr.idx, operand_expr.op,
                                         [converted, operand_expr.operands[1]],
                                         **expr.tags)
                elif isinstance(operand_expr.operands[0], Expr.Convert) and \
                        expr.from_bits == operand_expr.operands[0].to_bits and \
                        expr.to_bits == operand_expr.operands[0].from_bits:
                    return Expr.BinaryOp(operand_expr.idx, operand_expr.op, [
                        operand_expr.operands[0].operand,
                        operand_expr.operands[1]
                    ], **operand_expr.tags)
            elif isinstance(operand_expr.operands[0], Expr.Convert) \
                    and isinstance(operand_expr.operands[1], Expr.Convert) \
                    and operand_expr.operands[0].from_bits == operand_expr.operands[1].from_bits:
                if operand_expr.operands[0].to_bits == operand_expr.operands[1].to_bits \
                        and expr.from_bits == operand_expr.operands[0].to_bits \
                        and expr.to_bits == operand_expr.operands[1].from_bits:
                    return Expr.BinaryOp(operand_expr.idx, operand_expr.op, [
                        operand_expr.operands[0].operand,
                        operand_expr.operands[1].operand
                    ], **operand_expr.tags)

        converted = Expr.Convert(expr.idx, expr.from_bits, expr.to_bits,
                                 expr.is_signed, operand_expr, **expr.tags)
        return converted
Example #5
0
    def _ail_handle_Shl(self, expr):

        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        if isinstance(operand_1, Expr.Const):
            new_operand = Expr.Const(operand_1.idx, None, 2**operand_1.value,
                                     operand_0.bits)
            return Expr.BinaryOp(expr.idx, 'Mul', [operand_0, new_operand],
                                 expr.signed, **expr.tags)

        if (operand_0, operand_1) != (expr.operands[0], expr.operands[1]):
            return Expr.BinaryOp(expr.idx, 'Shl', [operand_0, operand_1],
                                 expr.signed, **expr.tags)
        return expr
Example #6
0
 def _test_concatenation(pv: PropValue):
     if pv.offset_and_details is not None and len(pv.offset_and_details) == 2 and 0 in pv.offset_and_details:
         lo_value = pv.offset_and_details[0]
         hi_offset = next(iter(k for k in pv.offset_and_details if k != 0))
         hi_value = pv.offset_and_details[hi_offset]
         if lo_value.def_at == hi_value.def_at:
             # it's the same value! we can apply concatenation here
             if isinstance(hi_value.expr, Expr.Const) and hi_value.expr.value == 0:
                 # it's probably an up-cast
                 mappings = {
                     # (lo_value.size, hi_value.size): (from_bits, to_bits)
                     (1, 1): (8, 16),  # char to short
                     (1, 3): (8, 32),  # char to int
                     (1, 7): (8, 64),  # char to int64
                     (2, 2): (16, 32),  # short to int
                     (2, 6): (16, 64),  # short to int64
                     (4, 4): (32, 64),  # int to int64
                 }
                 key = (lo_value.size, hi_value.size)
                 if key in mappings:
                     from_bits, to_bits = mappings[key]
                     result_expr = Expr.Convert(None, from_bits, to_bits, False, lo_value.expr)
                     return True, result_expr
             result_expr = Expr.BinaryOp(None, "Concat", [hi_value.expr, lo_value.expr], False)
             return True, result_expr
     return False, None
Example #7
0
    def _ail_handle_And(self, expr: Expr.BinaryOp):

        o0_value = self._expr(expr.operands[0])
        o1_value = self._expr(expr.operands[1])

        value = self.state.top(expr.bits)
        if o0_value is None or o1_value is None:
            new_expr = expr
        else:
            o0_expr = o0_value.one_expr
            o1_expr = o1_value.one_expr

            # Special logic for stack pointer alignment
            sp_offset = self.extract_offset_to_sp(o0_value.value)
            if sp_offset is not None and type(o1_expr) is Expr.Const and is_alignment_mask(o1_expr.value):
                value = o0_value.value
                new_expr = o0_expr
            elif isinstance(o0_expr, Expr.StackBaseOffset) and type(o1_expr) is Expr.Const \
                    and is_alignment_mask(o1_expr.value):
                value = o0_value.value
                new_expr = o0_expr
            else:
                value = self.state.top(expr.bits)
                new_expr = Expr.BinaryOp(expr.idx,
                                         'And',
                                         [o0_expr if o0_expr is not None else expr.operands[0],
                                          o1_expr if o1_expr is not None else expr.operands[1],],
                                         expr.signed,
                                         **expr.tags)
        return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
Example #8
0
    def _ail_handle_Convert(self, expr):
        if expr.from_bits == 128 and expr.to_bits == 64:
            operand_expr = self._expr(expr.operand)
            if isinstance(operand_expr, Expr.BinaryOp) \
                    and operand_expr.op == 'Mul' \
                    and isinstance(operand_expr.operands[1], Expr.Const) \
                    and isinstance(operand_expr.operands[0], Expr.BinaryOp):
                if operand_expr.operands[0].op in {'Shr', 'DivMod'} \
                        and isinstance(operand_expr.operands[0].operands[1], Expr.Const):
                    if operand_expr.operands[0].op == 'Shr':
                        Y = operand_expr.operands[0].operands[1].value
                    else:
                        Y = int(
                            math.log2(
                                operand_expr.operands[0].operands[1].value))
                    C = operand_expr.operands[1].value
                    divisor = self._check_divisor(pow(2, 64 + Y), C)
                    if divisor:
                        X = operand_expr.operands[0].operands[0]
                        new_const = Expr.Const(expr.idx, None, divisor, 64)
                        return Expr.BinaryOp(expr.idx, 'DivMod',
                                             [X, new_const], expr.signed,
                                             **expr.tags)

        return super()._ail_handle_Convert(expr)
Example #9
0
    def _ail_handle_Sub(self, expr: Expr.BinaryOp) -> PropValue:
        o0_value = self._expr(expr.operands[0])
        o1_value = self._expr(expr.operands[1])

        if o0_value is None or o1_value is None:
            new_expr = expr
            value = self.state.top(expr.bits)
        else:
            if o0_value.value.concrete and o1_value.value.concrete:
                value = o0_value.value - o1_value.value
            else:
                value = self.state.top(expr.bits)

            o0_expr = o0_value.one_expr
            o1_expr = o1_value.one_expr
            if isinstance(o0_expr, Expr.BasePointerOffset) and isinstance(o1_expr, Expr.Const):
                new_expr = o0_value.one_expr.copy()
                new_expr.offset -= o1_expr.value
            else:
                new_expr = Expr.BinaryOp(expr.idx,
                                         'Sub',
                                         [o0_expr if o0_expr is not None else expr.operands[0],
                                          o1_expr if o1_expr is not None else expr.operands[1],],
                                         expr.signed,
                                         **expr.tags)
        return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
Example #10
0
    def _ail_handle_Cmp(self, expr: Expr.BinaryOp) -> PropValue:
        operand_0_value = self._expr(expr.operands[0])
        operand_1_value = self._expr(expr.operands[1])

        if operand_0_value is not None and operand_1_value is not None:
            operand_0_oneexpr = operand_0_value.one_expr
            operand_1_oneexpr = operand_1_value.one_expr
            if operand_0_oneexpr is expr.operands[
                    0] and operand_1_oneexpr is expr.operands[1]:
                # nothing changed
                return PropValue.from_value_and_details(
                    self.state.top(expr.bits), expr.size, expr,
                    self._codeloc())
            else:
                operand_0 = operand_0_oneexpr if operand_0_oneexpr is not None else expr.operands[
                    0]
                operand_1 = operand_1_oneexpr if operand_1_oneexpr is not None else expr.operands[
                    1]

            new_expr = Expr.BinaryOp(expr.idx, expr.op, [operand_0, operand_1],
                                     expr.signed, **expr.tags)
        else:
            new_expr = expr

        return PropValue.from_value_and_details(self.state.top(expr.bits),
                                                expr.size, new_expr,
                                                self._codeloc())
Example #11
0
    def _ail_handle_Mul(self, expr):
        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        if (operand_0, operand_1) != (expr.operands[0], expr.operands[1]):
            return Expr.BinaryOp(expr.idx, 'Mul', [operand_0, operand_1],
                                 **expr.tags)
        return expr
Example #12
0
    def _ail_handle_Xor(self, expr):
        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        if type(operand_0) is Top or type(operand_1) is Top:
            return Top(operand_0.size)

        return Expr.BinaryOp(expr.idx, 'Xor', [ operand_0, operand_1 ], expr.signed, **expr.tags)
Example #13
0
    def _ail_handle_Div(self, expr):

        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        if isinstance(operand_1, Expr.Const) \
            and isinstance(operand_0, Expr.BinaryOp) \
            and operand_0.op in {'Div', 'DivMod'} \
            and isinstance(operand_0.operands[1], Expr.Const):

            new_const_value = operand_1.value * operand_0.operands[1].value
            new_const = Expr.Const(operand_1.idx, None, new_const_value, operand_1.bits)
            return Expr.BinaryOp(expr.idx, 'Div', [operand_0.operands[0], new_const], expr.signed, **expr.tags)

        if (operand_0, operand_1) != (expr.operands[0], expr.operands[1]):
            return Expr.BinaryOp(expr.idx, 'Div', [operand_0, operand_1], expr.signed, **expr.tags)
        return expr
Example #14
0
    def _ail_handle_CmpNE(self, expr):
        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        if type(operand_0) is Top or type(operand_1) is Top:
            return Top(1)

        return Expr.BinaryOp(expr.idx, 'CmpNE', [operand_0, operand_1],
                             expr.signed)
Example #15
0
    def _ail_handle_And(self, expr):
        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        # Special logic for SP alignment
        if type(operand_0) is Expr.StackBaseOffset and \
                type(operand_1) is Expr.Const and is_alignment_mask(operand_1.value):
            return operand_0

        return Expr.BinaryOp(expr.idx, 'And', [operand_0, operand_1])
Example #16
0
    def _ail_handle_Mul(self, expr):

        operand_0, operand_1 = expr.operands

        if isinstance(operand_1, Expr.Const) \
            and isinstance(operand_0, Expr.BinaryOp) \
                and isinstance(operand_0.operands[1], Expr.Const) \
                    and operand_0.op in {'DivMod', 'Shr'}:
            if operand_0.op == 'DivMod':
                Y = int(math.log2(operand_0.operands[1].value))
            else:
                Y = operand_0.operands[1].value
            C = operand_1.value
            X = operand_0.operands[0]
            # there is a convert outside this expr
            V = 64
            if isinstance(X, Expr.Convert):
                V = X.from_bits - X.to_bits
            ndigits = 5 if V == 32 else 6
            if self._check_divisor(pow(2, V + Y), C, ndigits) and X:
                divisor = self._check_divisor(pow(2, Y + V), C, ndigits)
                new_const = Expr.Const(expr.idx, None, divisor, 64)
                return Expr.BinaryOp(expr.idx, 'DivMod', [X, new_const],
                                     expr.signed, **expr.tags)
        if isinstance(operand_1, Expr.Const) \
            and isinstance(operand_0, Expr.Convert) \
                and isinstance(operand_0.operand, Expr.BinaryOp) \
                    and isinstance(operand_0.operand.operands[1], Expr.Const) \
                and operand_0.operand.op in {'DivMod', 'Shr'}:
            if operand_0.operand.op == 'DivMod':
                Y = int(math.log2(operand_0.operand.operands[1].value))
            else:
                Y = operand_0.operand.operands[1].value
            C = operand_1.value
            X = operand_0.operand.operands[0]
            V = operand_0.from_bits - operand_0.to_bits
            ndigits = 5 if V == 32 else 6
            if self._check_divisor(pow(2, V + Y), C, ndigits) and X:
                divisor = self._check_divisor(pow(2, Y + V), C, ndigits)
                new_const = Expr.Const(expr.idx, None, divisor, 64)
                return Expr.BinaryOp(expr.idx, 'DivMod', [X, new_const],
                                     expr.signed, **expr.tags)
        return super()._ail_handle_Mul(expr)
Example #17
0
    def _ail_handle_Shr(self, expr: Expr.BinaryOp):
        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        if self.state.is_top(operand_0):
            return self.state.top(expr.bits)
        elif self.state.is_top(operand_1):
            return self.state.top(expr.bits)

        return Expr.BinaryOp(expr.idx, 'Shr', [ operand_0, operand_1 ], expr.signed, **expr.tags)
Example #18
0
    def _ail_handle_Mul(self, expr):

        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        if Expr.Const in [type(operand_0), type(operand_1)]:
            if Expr.BinaryOp in [type(operand_0), type(operand_1)]:
                const_, x0 = (operand_0, operand_1) if isinstance(
                    operand_0, Expr.Const) else (operand_1, operand_0)
                if x0.op == 'Mul' and Expr.Const in [
                        type(x0.operands[0]),
                        type(x0.operands[1])
                ]:
                    const_x0, x = (x0.operands[0],
                                   x0.operands[1]) if isinstance(
                                       x0.operands[0],
                                       Expr.Const) else (x0.operands[1],
                                                         x0.operands[0])
                    new_const = Expr.Const(const_.idx, None,
                                           const_.value * const_x0.value,
                                           const_.bits)
                    new_expr = Expr.BinaryOp(expr.idx, 'Mul', [x, new_const],
                                             expr.signed, **expr.tags)
                    return new_expr
            elif isinstance(operand_0, Expr.Convert) \
                and isinstance(operand_0.operand, Expr.BinaryOp) \
                    and operand_0.operand.op == 'Mul' \
                    and isinstance(operand_0.operand.operands[1], Expr.Const):
                x = operand_0.operand.operands[0]
                new_const = Expr.Const(
                    operand_1.idx, None,
                    operand_1.value * operand_0.operand.operands[1].value,
                    operand_1.bits)
                new_expr = Expr.BinaryOp(expr.idx, 'Mul', [x, new_const],
                                         expr.signed, **expr.tags)
                return new_expr

        if (operand_0, operand_1) != (expr.operands[0], expr.operands[1]):
            return Expr.BinaryOp(expr.idx, 'Mul', [operand_0, operand_1],
                                 expr.signed, **expr.tags)
        return expr
Example #19
0
    def _ail_handle_Sub(self, expr):
        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        if isinstance(operand_0, Expr.Const) and isinstance(operand_1, Expr.Const):
            return Expr.Const(expr.idx, None, operand_0.value - operand_1.value, expr.bits)
        elif isinstance(operand_0, Expr.BasePointerOffset) and isinstance(operand_1, Expr.Const):
            r = operand_0.copy()
            r.offset -= operand_1.value
            return r
        return Expr.BinaryOp(expr.idx, 'Sub', [ operand_0 if operand_0 is not None else expr.operands[0],
                                                operand_1 if operand_1 is not None else expr.operands[1]
                                                ])
Example #20
0
    def _ail_handle_Cmp(self, expr: Expr.BinaryOp):
        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        if self.state.is_top(operand_0):
            operand_0 = expr.operands[0]
        if self.state.is_top(operand_1):
            operand_1 = expr.operands[1]

        if operand_0 is expr.operands[0] and operand_1 is expr.operands[1]:
            # nothing changed
            return expr

        return Expr.BinaryOp(expr.idx, expr.op, [operand_0, operand_1], expr.signed, **expr.tags)
Example #21
0
    def _rewrite(self, ccall: Expr.VEXCCallExpression) -> Optional[Expr.Expression]:
        if ccall.cee_name == "amd64g_calculate_condition":
            cond = ccall.operands[0]
            op = ccall.operands[1]
            dep_1 = ccall.operands[2]
            dep_2 = ccall.operands[3]
            if isinstance(cond, Expr.Const) and isinstance(op, Expr.Const):
                cond_v = cond.value
                op_v = op.value
                if cond_v == AMD64_CondTypes['CondLE'] and op_v == AMD64_OpTypes['G_CC_OP_SUBL']:
                    # dep_1 <=s dep_2
                    return Expr.BinaryOp(ccall.idx, "CmpLE",
                                         (dep_1, dep_2),
                                         True,
                                         **ccall.tags)
                if cond_v == AMD64_CondTypes['CondLE'] and op_v == AMD64_OpTypes['G_CC_OP_SUBB']:
                    # dep_1 <=s dep_2
                    return Expr.BinaryOp(ccall.idx, "CmpLE",
                                         (dep_1, dep_2),
                                         True,
                                         **ccall.tags)

        return None
Example #22
0
    def _ail_handle_Concat(self, expr):
        o0_value = self._expr(expr.operands[0])
        o1_value = self._expr(expr.operands[1])

        value = self.state.top(expr.bits)
        if o0_value is None or o1_value is None:
            new_expr = expr
        else:
            o0_expr = o0_value.one_expr
            o1_expr = o1_value.one_expr
            new_expr = Expr.BinaryOp(expr.idx, 'Concat', [
                o0_expr if o0_expr is not None else expr.operands[0],
                o1_expr if o1_expr is not None else expr.operands[1],
            ], expr.signed, **expr.tags)
        return PropValue.from_value_and_details(value, expr.size, new_expr,
                                                self._codeloc())
Example #23
0
    def _ail_handle_Mull(self, expr):
        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        if self.state.is_top(operand_0):
            return self.state.top(expr.bits)
        elif self.state.is_top(operand_1):
            return self.state.top(expr.bits)

        return Expr.BinaryOp(expr.idx,
                             'Mull', [
                                 operand_0,
                                 operand_1,
                             ],
                             expr.signed,
                             bits=expr.bits,
                             **expr.tags)
Example #24
0
    def _ail_handle_Add(self, expr):
        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        if type(operand_0) is Top or type(operand_1) is Top:
            return Top(operand_0.size)

        if isinstance(operand_0, Expr.Const) and isinstance(operand_1, Expr.Const):
            return Expr.Const(expr.idx, None, operand_0.value + operand_1.value, expr.bits)
        elif isinstance(operand_0, Expr.BasePointerOffset) and isinstance(operand_1, Expr.Const):
            r = operand_0.copy()
            r.offset += operand_1.value
            return r
        return Expr.BinaryOp(expr.idx, 'Add', [operand_0 if operand_0 is not None else expr.operands[0],
                                               operand_1 if operand_1 is not None else expr.operands[1]
                                               ],
                             expr.signed)
Example #25
0
    def _ail_handle_And(self, expr: Expr.BinaryOp):

        self.state: 'PropagatorAILState'

        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        if self.state.is_top(operand_0):
            return self.state.top(expr.bits)
        elif self.state.is_top(operand_1):
            return self.state.top(expr.bits)

        # Special logic for stack pointer alignment
        sp_offset = self.extract_offset_to_sp(operand_0)
        if sp_offset is not None and type(operand_1) is Expr.Const and is_alignment_mask(operand_1.value):
            return operand_0

        return Expr.BinaryOp(expr.idx, 'And', [ operand_0, operand_1 ], expr.signed, **expr.tags)
Example #26
0
    def _ail_handle_Add(self, expr: Expr.BinaryOp):
        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        if self.state.is_top(operand_0):
            return self.state.top(expr.bits)
        elif self.state.is_top(operand_1):
            return self.state.top(expr.bits)

        if isinstance(operand_0, Expr.Const) and isinstance(operand_1, Expr.Const):
            return Expr.Const(expr.idx, None, operand_0.value + operand_1.value, expr.bits)
        elif isinstance(operand_0, Expr.BasePointerOffset) and isinstance(operand_1, Expr.Const):
            r = operand_0.copy()
            r.offset += operand_1.value
            return r

        return Expr.BinaryOp(expr.idx, 'Add', [operand_0 if operand_0 is not None else expr.operands[0],
                                               operand_1 if operand_1 is not None else expr.operands[1]
                                               ],
                             expr.signed,
                             **expr.tags)
Example #27
0
    def _ail_handle_Shr(self, expr):

        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        X = None
        divisor = None

        if isinstance(operand_1, Expr.Const) \
            and isinstance(operand_0, Expr.BinaryOp) \
                and operand_0.op == 'DivMod' \
                    and isinstance(operand_0.operands[1], Expr.Const):
            divisor = operand_0.operands[1].value * pow(2, operand_1.value)
            X = operand_0.operands[0]
        if isinstance(operand_1, Expr.Const) \
            and isinstance(operand_0, Expr.Convert) \
                and isinstance(operand_0.operand, Expr.BinaryOp) \
                    and operand_0.operand.op == 'DivMod' \
                and isinstance(operand_0.operand.operands[1], Expr.Const):
            divisor = operand_0.operand.operands[1].value * pow(
                2, operand_1.value)
            X = operand_0.operand.operands[0]
        if isinstance(operand_1, Expr.Const) \
                and isinstance(operand_0, Expr.Convert) \
                and operand_0.from_bits == 128 \
                and operand_0.to_bits == 64:
            if isinstance(operand_0.operand, Expr.BinaryOp)\
                    and operand_0.operand.op == 'Mul':
                if isinstance(operand_0.operand.operands[1], Expr.Const):
                    C = operand_0.operand.operands[1].value
                    Y = operand_1.value
                    divisor = self._check_divisor(pow(2, 64 + Y), C)
                    X = operand_0.operand.operands[0]
                elif isinstance(operand_0.operand.operands[0], Expr.BinaryOp) \
                        and operand_0.operand.operands[0].op in {'Shr', 'DivMod'}:
                    C = operand_0.operand.operands[1].value
                    Z = operand_1.value
                    if operand_0.operand.operands[0].op == 'Shr':
                        Y = operand_0.operand.operands[0].operands[1].value
                    else:
                        Y = int(
                            math.log2(operand_0.operand.operands[0].
                                      operands[1].value))
                    divisor = self._check_divisor(pow(2, 64 + Z + Y), C)
                    X = operand_0.operand.operands[0].operands[0]
        if isinstance(operand_1, Expr.Const) \
                and isinstance(operand_0, Expr.BinaryOp) \
                and operand_0.op == 'Add':
            add_0, add_1 = operand_0.operands
            Z = operand_1.value
            if add_0.has_atom(add_1) or add_1.has_atom(add_0):
                xC = add_1 if add_0.has_atom(add_1) else add_0
                x_xC = add_0 if add_0.has_atom(add_1) else add_1
                if isinstance(xC,
                              Expr.Convert) and (xC.from_bits > xC.to_bits):
                    Y = xC.from_bits - xC.to_bits
                    if isinstance(xC.operand,
                                  Expr.BinaryOp) and xC.operand.op == 'Mul':
                        xC_ = xC.operand
                        if isinstance(xC_.operands[1], Expr.Const):
                            C = xC_.operands[1].value
                            X = xC_.operands[0]
                            if isinstance(x_xC,
                                          Expr.BinaryOp) and x_xC.op == 'Shr':
                                V_, V = x_xC.operands
                                if isinstance(V, Expr.Const):
                                    V = V.value
                                    if isinstance(
                                            V_,
                                            Expr.BinaryOp) and V_.op == 'Sub':
                                        if V_.operands[0] == X and V_.operands[
                                                1] == xC:
                                            divisor = self._check_divisor(
                                                pow(2, Y + V + Z),
                                                C * (pow(2, V) - 1) +
                                                pow(2, Y))
                # unsigned int here
                if isinstance(xC, Expr.BinaryOp) and xC.op == 'Mul':
                    if isinstance(xC.operands[1], Expr.Const) \
                        and isinstance(xC.operands[0], Expr.Convert):
                        C = xC.operands[1].value
                        X = xC.operands[0]
                        Y = X.from_bits - X.to_bits
                        if isinstance(x_xC,
                                      Expr.BinaryOp) and x_xC.op == 'Shr':
                            V_, V = x_xC.operands
                            if isinstance(V, Expr.Const):
                                V = V.value
                                if isinstance(
                                        V_, Expr.BinaryOp) and V_.op == 'Sub':
                                    if V_.operands[1] == xC:
                                        divisor = self._check_divisor(
                                            pow(2, Y + V + Z),
                                            C * (pow(2, V) - 1) + pow(2, Y))
                elif isinstance(xC, Expr.BinaryOp) and xC.op == 'Shr':
                    if isinstance(xC.operands[1], Expr.Const) \
                        and isinstance(xC.operands[0], Expr.BinaryOp) \
                            and xC.operands[0].op == 'Mul' \
                                and isinstance(xC.operands[0].operands[1], Expr.Const):
                        if isinstance(x_xC, Expr.BinaryOp) \
                            and isinstance(x_xC.operands[1], Expr.Const) \
                                and isinstance(x_xC.operands[0], Expr.BinaryOp) \
                                    and x_xC.op == 'Shr' and x_xC.operands[0].op == 'Sub':
                            X = xC.operands[0].operands[0]
                            C = xC.operands[0].operands[1].value
                            Y = xC.operands[1].value
                            V = x_xC.operands[1].value
                            if X == x_xC.operands[0].operands[0]:
                                divisor = self._check_divisor(
                                    pow(2, Y + V + Z),
                                    C * (pow(2, V) - 1) + pow(2, Y))

        # unsigned int
        if isinstance(operand_1, Expr.Const) \
            and isinstance(operand_0, Expr.BinaryOp) \
                and operand_0.op == 'Mul' \
                    and isinstance(operand_0.operands[1], Expr.Const):
            if isinstance(operand_0.operands[0], Expr.Convert):
                V = operand_0.operands[0].from_bits - operand_0.operands[
                    0].to_bits
                C = operand_0.operands[1].value
                Z = operand_1.value
                X = operand_0.operands[0]
                divisor = self._check_divisor(pow(2, V + Z), C)
            elif isinstance(operand_0.operands[0], Expr.BinaryOp) \
                and isinstance(operand_0.operands[0].operands[1], Expr.Const) \
                    and operand_0.operands[0].op in {'Shr', 'DivMod'}:
                X = operand_0.operands[0].operands[0]
                V = 0
                ndigits = 6
                if isinstance(X, Expr.Convert):
                    V = X.from_bits - X.to_bits
                if V == 32:
                    ndigits = 5
                C = operand_0.operands[1].value
                Y = operand_0.operands[0].operands[1].value
                if operand_0.operands[0].op == 'DivMod':
                    Y = int(math.log2(operand_0.operands[0].operands[1].value))
                Z = operand_1.value
                divisor = self._check_divisor(pow(2, Y + Z + V), C, ndigits)
            else:
                X = operand_0.operands[0]
                Y = operand_1.value
                C = operand_0.operands[1].value
                divisor = self._check_divisor(pow(2, Y), C)

        if divisor and X:
            new_const = Expr.Const(expr.idx, None, divisor, 64)
            return Expr.BinaryOp(expr.idx, 'DivMod', [X, new_const],
                                 expr.signed, **expr.tags)

        if isinstance(operand_1, Expr.Const):
            if isinstance(operand_0, Expr.Register):
                new_operand = Expr.Const(operand_1.idx, None,
                                         2**operand_1.value, operand_1.bits)
                return Expr.BinaryOp(expr.idx, 'DivMod',
                                     [operand_0, new_operand], expr.signed)
            elif isinstance(operand_0, Expr.BinaryOp) \
                and operand_0.op == 'Shr' \
                    and isinstance(operand_0.operands[1], Expr.Const):
                new_const = Expr.Const(
                    operand_1.idx, None,
                    operand_0.operands[1].value + operand_1.value,
                    operand_1.bits)
                return Expr.BinaryOp(expr.idx, 'Shr',
                                     [operand_0.operands[0], new_const],
                                     expr.signed, **expr.tags)

        if (operand_0, operand_1) != (expr.operands[0], expr.operands[1]):
            return Expr.BinaryOp(expr.idx, 'Shr', [operand_0, operand_1],
                                 expr.signed)
        return expr
Example #28
0
    def _ail_handle_Xor(self, expr):
        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        return Expr.BinaryOp(expr.idx, 'Xor', [operand_0, operand_1])
Example #29
0
    def _ail_handle_CmpNE(self, expr):
        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        return Expr.BinaryOp(expr.idx, 'CmpNE', [operand_0, operand_1],
                             expr.signed)
Example #30
0
    def _ail_handle_Sub(self, expr):

        operand_0 = self._expr(expr.operands[0])
        operand_1 = self._expr(expr.operands[1])

        # x + x = 2*x
        if type(operand_0) in [Expr.Convert, Expr.Register]:
            if isinstance(operand_1, (Expr.Convert, Expr.Register)):
                if operand_0 == operand_1:
                    count = Expr.Const(expr.idx, None, 0, 8)
                    new_expr = Expr.BinaryOp(expr.idx, 'Mul',
                                             [operand_1, count], expr.signed,
                                             **expr.tags)
                    return new_expr

        # 2*x - x = x
        if Expr.BinaryOp in [type(operand_0), type(operand_1)]:
            if isinstance(operand_1, Expr.BinaryOp) and operand_1.op == 'Mul' and \
                (not isinstance(operand_0, Expr.BinaryOp) or \
                    (isinstance(operand_0, Expr.BinaryOp) and operand_0.op != 'Mul')):

                x0 = operand_0
                x1_index = 0 if isinstance(operand_1.operands[1],
                                           Expr.Const) else 1
                x1 = operand_1.operands[x1_index]
                const_x1 = operand_1.operands[1 - x1_index]
                if x0 == x1:
                    new_const = Expr.Const(const_x1.idx, None,
                                           const_x1.value - 1, const_x1.bits)
                    new_expr = Expr.BinaryOp(expr.idx, 'Mul', [x0, new_const],
                                             expr.signed, **expr.tags)
                    return new_expr
            elif isinstance(operand_0, Expr.BinaryOp) and operand_0.op == 'Mul' and \
                (not isinstance(operand_1, Expr.BinaryOp) or \
                    (isinstance(operand_1, Expr.BinaryOp) and operand_1.op != 'Mul')):

                x1 = operand_1
                x0_index = 0 if isinstance(operand_0.operands[1],
                                           Expr.Const) else 1
                x0 = operand_0.operands[x0_index]
                const_x0 = operand_0.operands[1 - x0_index]
                if x0 == x1:
                    new_const = Expr.Const(const_x0.idx, None,
                                           const_x0.value - 1, const_x0.bits)
                    new_expr = Expr.BinaryOp(expr.idx, 'Mul', [x1, new_const],
                                             expr.signed, **expr.tags)
                    return new_expr
            # 3*x - 2*x = x
            elif isinstance(operand_0, Expr.BinaryOp) and isinstance(operand_1, Expr.BinaryOp) and \
                operand_0.op == 'Mul' and operand_1.op == 'Mul':
                if Expr.Const in [type(operand_0.operands[0]), type(operand_0.operands[1])] \
                    and Expr.Const in [type(operand_1.operands[0]), type(operand_1.operands[1])]:
                    x0_index = 0 if isinstance(operand_0.operands[1],
                                               Expr.Const) else 1
                    x0 = operand_0.operands[x0_index]
                    const_x0 = operand_0.operands[1 - x0_index]

                    x1_index = 0 if isinstance(operand_1.operands[1],
                                               Expr.Const) else 1
                    x1 = operand_1.operands[x1_index]
                    const_x1 = operand_1.operands[1 - x1_index]
                    if x0 == x1:
                        new_const = Expr.Const(const_x1.idx, None,
                                               const_x0.value - const_x1.value,
                                               const_x1.bits)
                        new_expr = Expr.BinaryOp(expr.idx, 'Mul',
                                                 [x0, new_const], expr.signed,
                                                 **expr.tags)
                        return new_expr

        if (operand_0, operand_1) != (expr.operands[0], expr.operands[1]):
            return Expr.BinaryOp(expr.idx, 'Sub', [operand_0, operand_1],
                                 expr.signed, **expr.tags)
        return expr