def __identify(app, in_name): # TODO: identify number of independant inputs NL = app.nl().vector() M = app.matrix() nbits_in = M.ncols() nbits_out = M.nlines() if nbits_in != nbits_out: raise ValueError("do not yet support application with a different\ number of input and output bits!") mba = MBA(nbits_in) var_in = mba.var(in_name) if NL != Vector(len(NL)): return _identify_nonaffine(app, var_in) C = EX.ExprCst(mba.from_vec(app.cst()).to_cst(), nbits_out) if M == Matrix(nbits_out, nbits_in): # This is just a constant return C ret = EX.ExprBV(var_in) matrix_empty = 0 # Find empty columns in the matrix. for j in range(nbits_in): is_zero = reduce(operator.and_, (M.at(i, j) == imm(0) for i in range(nbits_out)), True) if is_zero: matrix_empty |= 1 << j matrix_and_mask = (~matrix_empty) % (2**nbits_out) if matrix_empty != 0: ret = EX.ExprAnd(ret, EX.ExprCst(matrix_and_mask, nbits_out)) if mba.from_vec(M * var_in.vec) ^ (var_in & matrix_empty) == var_in: # This is a XOR return EX.ExprXor(ret, C) raise ValueError("unable to identify an expression")
def test_unary(self): self.exprEqual(EX.ExprNot(self.x4_expr), ~self.x4) self.exprEqual(EX.ExprBroadcast(EX.ExprCst(1, 4), 0, 4), self.mba4.from_cst(0xf)) self.exprEqual(EX.ExprBroadcast(EX.ExprCst(1, 4), 1, 4), self.mba4.from_cst(0))
def visit_Ror(self, e): n = e.Y if not isinstance(n, EX.ExprCst): raise ValueError("only ror with a known constant is supported") n = n.n arg = self.visit(e.X) if n == 0: return arg nbits = arg.nbits return EX.ExprXor(EX.ExprShl(arg, EX.ExprCst(nbits - n, nbits)), EX.ExprLShr(arg, EX.ExprCst(n, nbits)))
def test_cond(self): e = EX.ExprCond(EX.ExprCmpEq(self.ex, EX.ExprCst(10, 8)), self.ex, self.ey) M,cfunc = self.get_c_func(e, self.args) for i in range(256): vref = 0xff if i != 10 else 10 self.assertEqual(cfunc(i, 0xff), vref) self.engine.remove_module(M) e = EX.ExprCond(EX.ExprCmpGte(self.ex, EX.ExprCst(10, 8), is_signed=True), self.ex, self.ey) M,cfunc = self.get_c_func(e, self.args) for i in range(-128,128): vref = i if i >= 10 else 0xff self.assertEqual(cfunc(i, 0xff), vref) self.engine.remove_module(M)
def test_cmp(self): e = EX.ExprCond(EX.ExprCmpEq(self.x8_expr, EX.ExprCst(10, 8)), self.y8_expr, self.z8_expr) e = EX.eval_expr(e) for i in range(256): eref = self.z8 if i != 10 else self.y8 self.assertEqual(e.eval({self.x8: i}), eref.vec)
def test_logical(self): ops = ((EX.ExprLShr, operator.rshift), (EX.ExprShl, operator.lshift), (EX.ExprRol, lambda x, n: x.rol(n)), (EX.ExprRor, lambda x, n: x.ror(n))) for op in ops: for s in range(5): self.exprEqual(op[0](self.x4_expr, EX.ExprCst(s, 4)), op[1](self.x4, s))
def test_binaryops(self): ops = ( (EX.ExprAdd, operator.add), (EX.ExprSub, operator.sub), (EX.ExprMul, operator.mul), ) args_expr = (self.x4_expr, self.y4_expr, self.z4_expr) args = (self.x4, self.y4, self.z4) for op in ops: self.exprEqual(reduce(op[0], args_expr), reduce(op[1], args)) E0 = EX.ExprAdd(self.x8_expr, self.x8_expr) self.exprEqual(EX.ExprAdd(E0, E0), self.x8 << 2) for i in range(1, 16): self.exprEqual(EX.ExprDiv(self.x4_expr, EX.ExprCst(i, 4)), self.x4.udiv(i))
def test_rotate_binop(self): E0 = EX.ExprRor(EX.ExprAdd(self.x4_expr, self.y4_expr), EX.ExprCst(1, 4)) self.exprEqual(E0, (self.x4 + self.y4).ror(1)) E0 = EX.ExprRor(EX.ExprSub(self.x4_expr, self.y4_expr), EX.ExprCst(1, 4)) self.exprEqual(E0, (self.x4 - self.y4).ror(1)) E0 = EX.ExprRor(EX.ExprMul(self.x4_expr, self.y4_expr), EX.ExprCst(1, 4)) self.exprEqual(E0, (self.x4 * self.y4).ror(1)) E0 = EX.ExprRol(EX.ExprAdd(self.x4_expr, self.y4_expr), EX.ExprCst(1, 4)) self.exprEqual(E0, (self.x4 + self.y4).rol(1)) E0 = EX.ExprRol(EX.ExprSub(self.x4_expr, self.y4_expr), EX.ExprCst(1, 4)) self.exprEqual(E0, (self.x4 - self.y4).rol(1)) E0 = EX.ExprRol(EX.ExprMul(self.x4_expr, self.y4_expr), EX.ExprCst(1, 4)) self.exprEqual(E0, (self.x4 * self.y4).rol(1))
def tritonast2arybo(e, use_exprs=True, use_esf=False, context=None): ''' Convert a subset of Triton's AST into Arybo's representation Args: e: Triton AST use_esf: use ESFs when creating the final expression context: dictionnary that associates Triton expression ID to arybo expressions Returns: An :class:`arybo.lib.MBAVariable` object ''' children_ = e.getChilds() children = (tritonast2arybo(c, use_exprs, use_esf, context) for c in children_) reversed_children = (tritonast2arybo(c, use_exprs, use_esf, context) for c in reversed(children_)) Ty = e.getKind() if Ty == TAstN.ZX: n = next(children) v = next(children) n += v.nbits if n == v.nbits: return v return v.zext(n) if Ty == TAstN.SX: n = next(children) v = next(children) n += v.nbits if n == v.nbits: return v return v.sext(n) if Ty == TAstN.DECIMAL: return e.getValue() if Ty == TAstN.BV: cst = next(children) nbits = next(children) if use_exprs: return EX.ExprCst(cst, nbits) else: return _get_mba(nbits, use_esf).from_cst(cst) if Ty == TAstN.EXTRACT: last = next(children) first = next(children) v = next(children) return v[first:last + 1] if Ty == TAstN.CONCAT: if use_exprs: return EX.ExprConcat(*list(reversed_children)) else: return flatten(reversed_children) if Ty == TAstN.VARIABLE: name = e.getValue() ret = _get_mba(e.getBitvectorSize(), use_esf).var(name) if use_exprs: ret = EX.ExprBV(ret) return ret if Ty == TAstN.REFERENCE: if context is None: raise ValueError( "reference node without context can't be resolved") id_ = e.getValue() ret = context.get(id_, None) if ret is None: raise ValueError("expression id %d not found in context" % id_) return ret if Ty == TAstN.LET: # Alias # djo: "c'est pas utilise osef" raise ValueError("unsupported LET operation") # Logical/arithmetic shifts shifts = { TAstN.BVLSHR: operator.rshift, TAstN.BVSHL: operator.lshift, } shift = shifts.get(Ty, None) if not shift is None: v = next(children) n = next(children) return shift(v, n) # We need to separate rotate shifts from the others because the triton API # is different for this one... (no comment) rshifts = { TAstN.BVROL: lambda x, n: x.rol(n), TAstN.BVROR: lambda x, n: x.ror(n) } rshift = rshifts.get(Ty, None) if not rshift is None: # Notice the order here compared to above... n = next(children) v = next(children) return rshift(v, n) # Unary op unops = { TAstN.BVNOT: lambda x: ~x, TAstN.LNOT: lambda x: ~x, TAstN.BVNEG: operator.neg } unop = unops.get(Ty, None) if unop != None: return unop(next(children)) binops = { TAstN.BVADD: operator.add, TAstN.BVSUB: operator.sub, TAstN.BVAND: operator.and_, TAstN.BVOR: operator.or_, TAstN.BVXOR: operator.xor, TAstN.BVMUL: operator.mul, TAstN.BVNAND: lambda x, y: ~(x & y), TAstN.BVNOR: lambda x, y: ~(x | y), TAstN.BVXNOR: lambda x, y: ~(x ^ y), TAstN.BVUDIV: lambda x, y: x.udiv(y), TAstN.BVSDIV: lambda x, y: x.sdiv(y), TAstN.LAND: operator.and_, TAstN.LOR: operator.or_ } binop = binops.get(Ty, None) if binop != None: return reduce(binop, children) # Logical op lops = { TAstN.EQUAL: lambda x, y: EX.ExprCmpEq(x, y), TAstN.DISTINCT: lambda x, y: EX.ExprCmpNeq(x, y), TAstN.BVUGE: lambda x, y: EX.ExprCmpGte(x, y, False), TAstN.BVUGT: lambda x, y: EX.ExprCmpGt(x, y, False), TAstN.BVULE: lambda x, y: EX.ExprCmpLte(x, y, False), TAstN.BVULT: lambda x, y: EX.ExprCmpLt(x, y, False), TAstN.BVSGE: lambda x, y: EX.ExprCmpGte(x, y, True), TAstN.BVSGT: lambda x, y: EX.ExprCmpGt(x, y, True), TAstN.BVSLE: lambda x, y: EX.ExprCmpLte(x, y, True), TAstN.BVSLT: lambda x, y: EX.ExprCmpLt(x, y, True) } lop = lops.get(Ty, None) if lop != None: return reduce(lop, children) # Conditional if Ty != TAstN.ITE: raise ValueError("unsupported node type %s" % str(Ty)) return EX.ExprCond(next(children), next(children), next(children))
def test_leaves(self): self.exprEqual(self.x4_expr, self.x4) self.exprEqual(EX.ExprCst(0xff, 4), self.mba4.from_cst(0xff))
def test_extract_contract(self): self.exprEqual(EX.ExprSlice(self.x8_expr, slice(0, 4)), self.x4) self.exprEqual(EX.ExprConcat(EX.ExprCst(0xf, 4), EX.ExprCst(0, 4)), self.mba8.from_cst(0x0f))
def test_zx_sx(self): self.exprEqual(EX.ExprZX(EX.ExprCst(0xf, 4), 8), self.mba8.from_cst(0x0f)) self.exprEqual(EX.ExprSX(EX.ExprCst(0x8, 4), 8), self.mba8.from_cst(0xf8))
def test_shifts(self): for op in (EX.ExprShl,EX.ExprLShr,EX.ExprRor,EX.ExprRol): for n in range(8): e = op(self.ex, EX.ExprCst(n, 8)) self.check_expr(e, [self.x])
def test_identify_xor_and(self): e = (self.x&0x7F)^0xAA self.check(e, EX.ExprXor(EX.ExprAnd(self.ex, EX.ExprCst(0x7F, 8)), EX.ExprCst(0xAA,8)))
def test_identify_xor(self): e = self.x&0xAA self.check(e, EX.ExprAnd(self.ex, EX.ExprCst(0xAA, 8)))