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)
def _ail_handle_Convert(self, expr): operand_expr = self._expr(expr.operand) if type(operand_expr) is Top: return Top(expr.to_bits // 8) 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) 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) converted = Expr.Convert(expr.idx, expr.from_bits, expr.to_bits, expr.is_signed, operand_expr, **expr.tags) return converted
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)
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)
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
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
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] ])
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
def _resolve_stack_argument(self, call_stmt, arg_loc): # pylint:disable=unused-argument size = arg_loc.size offset = arg_loc.stack_offset if self.project.arch.call_pushes_ret: # adjust the offset offset -= self.project.arch.bytes return Expr.Load(None, Expr.Register(None, None, self.project.arch.sp_offset, self.project.arch.bits) + Expr.Const(None, None, offset, self.project.arch.bits), size, self.project.arch.memory_endness, )
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
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
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)
def _resolve_stack_argument(self, call_stmt, arg_loc) -> Tuple[Any, Any]: # pylint:disable=unused-argument size = arg_loc.size offset = arg_loc.stack_offset if self.project.arch.call_pushes_ret: # adjust the offset offset -= self.project.arch.bytes # TODO: Support extracting values return None, Expr.Load( self._atom_idx(), Expr.Register(self._atom_idx(), None, self.project.arch.sp_offset, self.project.arch.bits) + Expr.Const(self._atom_idx(), None, offset, self.project.arch.bits), size, self.project.arch.memory_endness, )
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)
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
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
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']: if op_v in { AMD64_OpTypes['G_CC_OP_SUBB'], AMD64_OpTypes['G_CC_OP_SUBW'], AMD64_OpTypes['G_CC_OP_SUBL'], AMD64_OpTypes['G_CC_OP_SUBQ'] }: # dep_1 <=s dep_2 r = Expr.BinaryOp(ccall.idx, "CmpLE", (dep_1, dep_2), True, **ccall.tags) return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags) if cond_v == AMD64_CondTypes['CondZ']: if op_v in { AMD64_OpTypes['G_CC_OP_SUBB'], AMD64_OpTypes['G_CC_OP_SUBW'], AMD64_OpTypes['G_CC_OP_SUBL'], AMD64_OpTypes['G_CC_OP_SUBQ'] }: # dep_1 - dep_2 == 0 r = Expr.BinaryOp(ccall.idx, "CmpEQ", (dep_1, dep_2), False, **ccall.tags) return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags) elif cond_v == AMD64_CondTypes['CondL']: if op_v in { AMD64_OpTypes['G_CC_OP_SUBB'], AMD64_OpTypes['G_CC_OP_SUBW'], AMD64_OpTypes['G_CC_OP_SUBL'], AMD64_OpTypes['G_CC_OP_SUBQ'] }: # dep_1 - dep_2 <s 0 r = Expr.BinaryOp(ccall.idx, "CmpLT", (dep_1, dep_2), True, **ccall.tags) return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags) elif cond_v == AMD64_CondTypes['CondNBE']: if op_v in { AMD64_OpTypes['G_CC_OP_SUBB'], AMD64_OpTypes['G_CC_OP_SUBW'], AMD64_OpTypes['G_CC_OP_SUBL'], AMD64_OpTypes['G_CC_OP_SUBQ'] }: # dep_1 - dep_2 > 0 r = Expr.BinaryOp(ccall.idx, "CmpGT", (dep_1, dep_2), False, **ccall.tags) return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags) elif ccall.cee_name == "amd64g_calculate_rflags_c": # calculate the carry flag op = ccall.operands[0] dep_1 = ccall.operands[1] dep_2 = ccall.operands[2] ndep = ccall.operands[3] if isinstance(op, Expr.Const): op_v = op.value if op_v in { AMD64_OpTypes['G_CC_OP_ADDB'], AMD64_OpTypes['G_CC_OP_ADDW'], AMD64_OpTypes['G_CC_OP_ADDL'], AMD64_OpTypes['G_CC_OP_ADDQ'] }: # pc_actions_ADD cf = Expr.ITE( None, Expr.BinaryOp( None, "CmpLE", [ Expr.BinaryOp(None, "Add", [dep_1, dep_2], False), dep_1, ], False, ), Expr.Const(None, None, 0, ccall.bits), Expr.Const(None, None, 1, ccall.bits), **ccall.tags) return cf if op_v in { AMD64_OpTypes['G_CC_OP_SUBB'], AMD64_OpTypes['G_CC_OP_SUBW'], AMD64_OpTypes['G_CC_OP_SUBL'], AMD64_OpTypes['G_CC_OP_SUBQ'] }: # pc_actions_SUB cf = Expr.BinaryOp(None, "CmpLT", [ dep_1, dep_2, ], False) if cf.bits == ccall.bits: return cf return Expr.Convert(None, cf.bits, ccall.bits, False, cf, **ccall.tags) if op_v in { AMD64_OpTypes['G_CC_OP_DECB'], AMD64_OpTypes['G_CC_OP_DECW'], AMD64_OpTypes['G_CC_OP_DECL'], AMD64_OpTypes['G_CC_OP_DECQ'] }: # pc_actions_DEC cf = Expr.BinaryOp(None, "Shr", [ Expr.BinaryOp(None, "And", [ ndep, Expr.Const(None, None, AMD64_CondBitMasks['G_CC_MASK_C'], 64) ], False), Expr.Const(None, None, AMD64_CondBitOffsets['G_CC_SHIFT_C'], 64), ], False, **ccall.tags) return cf return None
def _ail_handle_Convert(self, expr: Expr.Convert) -> PropValue: o_value = self._expr(expr.operand) if o_value is None or self.state.is_top(o_value.value): new_value = self.state.top(expr.to_bits) else: if expr.from_bits < expr.to_bits: if expr.is_signed: new_value = claripy.SignExt(expr.to_bits - expr.from_bits, o_value.value) else: new_value = claripy.ZeroExt(expr.to_bits - expr.from_bits, o_value.value) elif expr.from_bits > expr.to_bits: new_value = claripy.Extract(expr.to_bits - 1, 0, o_value.value) else: new_value = o_value.value o_expr = o_value.one_expr o_defat = o_value.one_defat if o_expr is not None: # easy cases if type(o_expr) is Expr.Convert: if expr.from_bits == o_expr.to_bits and expr.to_bits == o_expr.from_bits: # eliminate the redundant Convert new_expr = o_expr.operand else: new_expr = Expr.Convert(expr.idx, o_expr.from_bits, expr.to_bits, expr.is_signed, o_expr.operand) elif type(o_expr) is Expr.Const: # do the conversion right away value = o_expr.value mask = (2 ** expr.to_bits) - 1 value &= mask new_expr = Expr.Const(expr.idx, o_expr.variable, value, expr.to_bits) else: new_expr = Expr.Convert(expr.idx, expr.from_bits, expr.to_bits, expr.is_signed, o_expr, **expr.tags) if isinstance(new_expr, Expr.Convert) and not new_expr.is_signed \ and new_expr.to_bits > new_expr.from_bits and new_expr.from_bits % self.arch.byte_width == 0: # special handling for zero-extension: it simplifies the code if we explicitly model zeros new_size = new_expr.from_bits // self.arch.byte_width offset_and_details = { 0: Detail(new_size, new_expr.operand, o_defat), new_size: Detail( new_expr.size - new_size, Expr.Const(expr.idx, None, 0, new_expr.to_bits - new_expr.from_bits), self._codeloc()), } else: offset_and_details = {0: Detail(expr.size, new_expr, self._codeloc())} return PropValue(new_value, offset_and_details=offset_and_details) elif o_value.offset_and_details: # hard cases... we will keep certain labels and eliminate other labels start_offset = 0 end_offset = expr.to_bits // self.arch.byte_width # end_offset is exclusive offset_and_details = {} max_offset = max(o_value.offset_and_details.keys()) for offset_, detail_ in o_value.offset_and_details.items(): if offset_ < start_offset < offset_ + detail_.size: # we start here off = 0 siz = min(end_offset, offset_ + detail_.size) - start_offset expr_ = PropValue.extract_ail_expression( (start_offset - offset_) * self.arch.byte_width, siz * self.arch.byte_width, detail_.expr ) offset_and_details[off] = Detail(siz, expr_, detail_.def_at) elif offset_ >= start_offset and offset_ + detail_.size <= end_offset: # we include the whole thing off = offset_ - start_offset siz = detail_.size if off == max_offset and off + siz < end_offset: # extend the expr expr_ = PropValue.extend_ail_expression( (end_offset - (off + siz)) * self.arch.byte_width, detail_.expr ) siz = end_offset - off else: expr_ = detail_.expr offset_and_details[off] = Detail(siz, expr_, detail_.def_at) elif offset_ < end_offset <= offset_ + detail_.size: # we include all the way until end_offset if offset_ < start_offset: off = 0 siz = end_offset - start_offset else: off = offset_ - start_offset siz = end_offset - offset_ expr_ = PropValue.extract_ail_expression(0, siz * self.arch.byte_width, detail_.expr) offset_and_details[off] = Detail(siz, expr_, detail_.def_at) return PropValue( new_value, offset_and_details=offset_and_details ) else: # it's empty... no expression is available for whatever reason return PropValue.from_value_and_details(new_value, expr.size, expr, self._codeloc())