def AryboSimplify(bitnum, sourceExpreStr): """simplify the expression by arybo Args: bitnum: the number of the bit of the variables. sourceExpreStr: expression is simplified. Returns: result: the result after simplification. Raise: None. """ mba = MBA(bitnum) x = mba.var("x") y = mba.var("y") z = mba.var("z") t = mba.var("t") a = mba.var("a") b = mba.var("b") c = mba.var("c") d = mba.var("d") e = mba.var("e") f = mba.var("f") res = eval(sourceExpreStr) fio = io.StringIO() print(res, file=fio) result = fio.getvalue() fio.close() return result
def setUp(self): mba6 = MBA(6) mba6.use_esf = False mba8 = MBA(8) mba8.use_esf = False self.X6 = mba6.var('X') self.Y6 = mba6.var('Y') self.X8 = mba8.var('X')
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 app_inverse(A): M = A.matrix() NL = A.nl() V = A.cst() Minv = M.inverse() if Minv.ncols() == 0: return None N = V.size() mba = MBA(N) Y = mba.var('Y') G0 = Minv * Y.vec + Minv * V G1nl = simplify_inplace(Minv * NL(Y.vec)) # Check if G1 is inversible through a dependency graph DG = nx.DiGraph() idx_base = Y[0].sym_idx() for i, e in enumerate(G1nl): for d in get_depends_as_set(e): DG.add_edge(Y[i].sym_idx() - idx_base, d.sym_idx() - idx_base) if not nx.is_directed_acyclic_graph(DG): return None # Use the graph to get the inverse of G1 X = mba.var('X') resolve_order = nx.topological_sort(DG, reverse=True) solved = dict() for i in resolve_order: e = G1nl[i] if e.is_imm() and e.imm_value() == 0: solved[i] = X[i] else: # Doing this in the reversed topological order should make this always work! solved[i] = simplify_inplace(X[i] + simplify_inplace( subs_exprs(G1nl[i], [Y[j] for j in six.iterkeys(solved)], list(six.itervalues(solved))))) G1inv = Vector(N) for i in range(N): G1inv[i] = solved.get(i, X[i]) G1inv = MBAVariable(mba, G1inv) Finv = G1inv.eval({X: G0}) Finv = MBAVariable(mba, Finv) return Finv.vectorial_decomp([Y])
class IdentifyTest(unittest.TestCase): def setUp(self): self.mba8 = MBA(8) self.x = self.mba8.var('x') self.ex = EX.ExprBV(self.mba8.var('x')) def check(self, e, ref): app = e.vectorial_decomp([self.x]) eid = identify(app,"x") self.assertEqual(EX.eval_expr(eid), EX.eval_expr(ref)) def test_identify_xor(self): e = self.x^0xAA self.check(e, EX.ExprXor(self.ex, EX.ExprCst(0xAA, 8))) def test_identify_xor(self): e = self.x&0xAA self.check(e, EX.ExprAnd(self.ex, EX.ExprCst(0xAA, 8))) 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 is_app_inversible(A): M = A.matrix() NL = A.nl() V = A.cst() Minv = M.inverse() if Minv.ncols() == 0: return False N = V.size() mba = MBA(N) Y = mba.var('Y') G0 = Minv*Y.vec + Minv*V G1nl = Minv*NL(Y.vec) # Check if G1 is inversible through a dependency graph DG = nx.DiGraph() for i,e in enumerate(G1nl): for d in get_depends_as_set(e): DG.add_edge(Y[i].sym_idx(), d.sym_idx()) return nx.is_directed_acyclic_graph(DG)
from arybo.lib import MBA mba32 = MBA(32) X = mba32.var('X') Y = mba32.var('Y') X.always_simplify() Y.always_simplify() op = (((X | 0xFDFFDBF3) - ((X | 0x7C5F9972) & 0x0248AD2E)) + 0x248AD36) print(hex(op.to_cst())) op = ((~X | 0x7AFAFA69) & 0xA061440) + (X & 0x1050504 | 0x101890D) print(hex(op.to_cst())) op = ((~X | 0x3BBDA8B5) & 0xB21C528) + (X & 0x4040474A | 0x40C00A46) print(hex(op.to_cst())) op = (X & 0xD281D094) - 1461583213 - (X | 0x2D7E2F6B) print(hex(op.to_cst()))
b = step(b) return b def xor(a, b): return [a[i] ^ b[i] for i in range(16)] def even_mansour(block, key): block = xor(block, key[:16]) block = f(block) block = xor(block, key[16:]) return block block = [mba8.var('b%d' % i) for i in range(16)] key_zero = [mba8.from_cst(0)] * 32 cipher = even_mansour(block, key_zero) cipher = flatten_vec(cipher) CZ = mba128.from_vec(cipher).vectorial_decomp(block) Minv = CZ.matrix().inverse() def recover(plaintext, cipher_plaintext, cipher_unk): plaintext = mba128.from_bytes(plaintext) cipher_plaintext = mba128.from_bytes(cipher_plaintext) cipher_unk = mba128.from_bytes(cipher_unk) tmp = mba128.from_vec( simplify(Minv * ((cipher_plaintext ^ cipher_unk).vec)))
from arybo.lib import MBA, boolean_expr_solve mba = MBA(64) x = mba.var('x') def f(X): T = ((X+1)&(~X)) C = ((T | 0x7AFAFA697AFAFA69) & 0x80A061440A061440)\ + ((~T & 0x10401050504) | 0x1010104) return C r = f(x) sols = boolean_expr_solve(r[63], x, 1) C0 = sols[0].get_int_be() print(hex(C0)) print(hex(f(0))) print(hex(f(C0)))
class MBAExprsTest: def setUp(self): self.mba1 = MBA(1) self.mba4 = MBA(4) self.mba4.use_esf = False self.mba8 = MBA(8) self.mba8.use_esf = False self.x4 = self.mba4.var('x') self.y4 = self.mba4.var('y') self.z4 = self.mba4.var('z') self.x4_expr = EX.ExprBV(self.x4) self.y4_expr = EX.ExprBV(self.y4) self.z4_expr = EX.ExprBV(self.z4) self.x8 = self.mba8.var('x') self.y8 = self.mba8.var('y') self.z8 = self.mba8.var('z') self.x8_expr = EX.ExprBV(self.x8) self.y8_expr = EX.ExprBV(self.y8) self.z8_expr = EX.ExprBV(self.z8) def exprEqual(self, expr, e): expr = EX.eval_expr(expr, self.use_esf) if self.use_esf: expand_esf_inplace(expr.vec) simplify_inplace(expr.vec) simplify_inplace(e.vec) simplify_inplace(expr.vec) self.assertEqual(expr, e) def test_leaves(self): self.exprEqual(self.x4_expr, self.x4) self.exprEqual(EX.ExprCst(0xff, 4), self.mba4.from_cst(0xff)) 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 test_unaryops(self): ops = ( (EX.ExprXor, operator.xor), (EX.ExprAnd, operator.and_), (EX.ExprOr, operator.or_), ) args_expr = (self.x4_expr, self.y4_expr, self.z4_expr) args = (self.x4, self.y4, self.z4) for op in ops: self.exprEqual(op[0](*args_expr), reduce(op[1], args)) 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 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_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_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_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)
from arybo.lib import MBA import sys m = MBA(int(sys.argv[1])) X = m.var('X') Y = m.var('Y') res = (X + Y) - (X | Y) print(res)
class TritonTest(): def setUp(self): # Initialize the engine TT.setArchitecture(TT.ARCH.X86) self.mba8 = MBA(8) self.mba16 = MBA(16) self.mba8.use_esf = True self.mba16.use_esf = True # Useful variables using duringtests self.x8_t = TAst.variable(TT.newSymbolicVariable(8)) self.y8_t = TAst.variable(TT.newSymbolicVariable(8)) self.x16_t = TAst.variable(TT.newSymbolicVariable(16)) self.y16_t = TAst.variable(TT.newSymbolicVariable(16)) self.x8 = self.mba8.var(self.x8_t.getValue()) self.y8 = self.mba8.var(self.y8_t.getValue()) self.x16 = self.mba16.var(self.x16_t.getValue()) self.y16 = self.mba16.var(self.y16_t.getValue()) # Helpers def astEquals(self, ast, v): if self.use_expr: e = tritonast2arybo(ast, use_exprs=True, use_esf=False) e = eval_expr(e, use_esf=False) v = expand_esf_inplace(v) v = simplify_inplace(v) else: e = tritonast2arybo(ast, use_exprs=False, use_esf=True) self.assertEqual(e, v) # Tests def test_leaves(self): c = random.choice(range(0xff)) self.astEquals(TAst.bv(c, 8), self.mba8.from_cst(c)) self.astEquals(self.x8_t, self.x8) def test_zx_sx(self): self.astEquals(TAst.zx(8, TAst.bv(0xff, 8)), self.mba16.from_cst(0x00ff)) self.astEquals(TAst.sx(8, TAst.bv(0xff, 8)), self.mba16.from_cst(0xffff)) def test_extract_contract(self): self.astEquals(TAst.extract(7, 0, TAst.bv(0xffff, 16)), self.mba8.from_cst(0xff)) self.astEquals(TAst.concat([TAst.bv(0xff, 8), TAst.bv(0x00, 8)]), self.mba16.from_cst(0xff00)) def test_unaryops(self): self.astEquals(TAst.bvnot(self.x8_t), ~self.x8) self.astEquals(TAst.bvneg(self.x8_t), -self.x8) def test_binaryops(self): ops = ((TAst.bvadd, operator.add), (TAst.bvsub, operator.sub), (TAst.bvand, operator.and_), (TAst.bvor, operator.or_), (TAst.bvxor, operator.xor), (TAst.bvmul, operator.mul), (TAst.bvnand, lambda x, y: ~(x & y)), (TAst.bvnor, lambda x, y: ~(x | y)), (TAst.bvxnor, lambda x, y: ~(x ^ y))) for op in ops: self.astEquals(op[0](self.x8_t, self.y8_t), op[1](self.x8, self.y8)) # One udiv test because it can take a lot of time... e = TAst.bvudiv(self.x8_t, TAst.bv(15, 8)) self.astEquals(e, self.x8.udiv(15)) def test_shifts(self): # Triton interface is not consistant between sh{r,l} and ro{l,r}. # For the first kind, it can take any AstNode. For the second one, an # integer is forced. ops = ( (TAst.bvlshr, operator.rshift), (TAst.bvshl, operator.lshift), ) for op in ops: for s in range(9): self.astEquals(op[0](self.x8_t, TAst.bv(s, 8)), op[1](self.x8, s)) ops = ((TAst.bvrol, lambda x, n: x.rol(n)), (TAst.bvror, lambda x, n: x.ror(n))) for op in ops: for s in range(9): self.astEquals(op[0](s, self.x8_t), op[1](self.x8, s)) def test_mba(self): # x^y = (x+y) - ((x&y)<<1) e = TAst.bvsub( TAst.bvadd(self.x8_t, self.y8_t), TAst.bvshl(TAst.bvand(self.x8_t, self.y8_t), TAst.bv(1, 8))) ea = tritonast2arybo(e, use_exprs=False, use_esf=True) simplify_inplace(expand_esf_inplace(ea)) self.assertEqual(ea, self.x8 ^ self.y8) def test_logical(self): e = TAst.equal(self.x8_t, self.y8_t) ea = tritonast2arybo(e, use_exprs=True, use_esf=False) ea = eval_expr(ea, use_esf=False) self.assertEqual(ea.nbits, 1) def test_exprs_xor_5C(self): # Based on djo's example # This is the xor_5C example compiled with optimisations for x86-4 code = [ "\x41\xB8\xE5\xFF\xFF\xFF", "\x89\xF8", "\xBA\x26\x00\x00\x00", "\x41\x0F\xAF\xC0", "\xB9\xED\xFF\xFF\xFF", "\x89\xC7", "\x89\xD0", "\x83\xEF\x09", "\x0F\xAF\xC7", "\x89\xC2", "\x89\xF8", "\x0F\xAF\xC1", "\xB9\x4B\x00\x00\x00", "\x8D\x44\x02\x2A", "\x0F\xB6\xC0", "\x89\xC2", "\xF7\xDA", "\x8D\x94\x12\xFF\x00\x00\x00", "\x81\xE2\xFE\x00\x00\x00", "\x01\xD0", "\x8D\x14\x00", "\x8D\x54\x02\x4D", "\x0F\xB6\xF2", "\x6B\xF6\x56", "\x83\xC6\x24", "\x83\xE6\x46", "\x89\xF0", "\x0F\xAF\xC1", "\xB9\xE7\xFF\xFF\xFF", "\x89\xC6", "\x89\xD0", "\xBA\x3A\x00\x00\x00", "\x0F\xAF\xC1", "\x89\xC1", "\x89\xD0", "\x8D\x4C\x0E\x76", "\xBE\x63\x00\x00\x00", "\x0F\xAF\xC1", "\x89\xC2", "\x89\xC8", "\x0F\xAF\xC6", "\x83\xEA\x51", "\xBE\x2D\x00\x00\x00", "\x83\xE2\xF4", "\x89\xC1", "\x8D\x4C\x0A\x2E", "\x89\xC8", "\x25\x94\x00\x00\x00", "\x01\xC0", "\x29\xC8", "\xB9\x67\x00\x00\x00", "\x0F\xAF\xC1", "\x8D\x48\x0D", "\x0F\xB6\xD1", "\x69\xD2\xAE\x00\x00\x00", "\x83\xCA\x22", "\x89\xD0", "\x41\x0F\xAF\xC0", "\x89\xC2", "\x89\xC8", "\x0F\xAF\xC6", "\x8D\x44\x02\xC2", "\x0F\xB6\xC0", "\x2D\xF7\x00\x00\x00", "\x69\xC0\xED\x00\x00\x00", "\x0F\xB6\xC0", ] TT.setArchitecture(TT.ARCH.X86_64) rdi = TT.convertRegisterToSymbolicVariable(TT.REG.RDI) rdi = tritonast2arybo(TAst.variable(rdi), use_exprs=False) for opcodes in code: inst = TT.Instruction(opcodes) TT.processing(inst) rax_ast = TT.buildSymbolicRegister(TT.REG.RAX) rax_ast = TT.getFullAst(rax_ast) rax_ast = TT.simplify(rax_ast, True) # Check that this gives a xor 5C e = tritonast2arybo(rax_ast, use_exprs=self.use_expr, use_esf=False) if self.use_expr: e = eval_expr(e) self.assertEqual(e, ((rdi & 0xff) ^ 0x5C).vec)
def setUp(self): mba = MBA(4) mba.use_esf = False self.X = mba.var('X')
class LLVMTest(unittest.TestCase): def setUp(self): self.mba = MBA(8) self.x = self.mba.var('x') self.y = self.mba.var('y') self.ex = EX.ExprBV(self.x) self.ey = EX.ExprBV(self.y) self.args = [self.x,self.y] self.eargs = [EX.ExprBV(self.x),EX.ExprBV(self.y)] self.func_name = "__arybo" self.llvm_target = llvm_get_target() self.machine = self.llvm_target.create_target_machine() self.engine = llvm.create_mcjit_compiler(llvm.parse_assembly(""), self.machine) def get_c_func(self, e, args): # Get the llvm function M = to_llvm_function(e,self.args,self.func_name) # JIT the function, and compare random values M = llvm.parse_assembly(str(M)) M.verify() self.engine.add_module(M) self.engine.finalize_object() func_ptr = self.engine.get_function_address(self.func_name) cfunc_type = (int_size_to_type(e.nbits),) + tuple(int_size_to_type(a.nbits) for a in args) cfunc = CFUNCTYPE(*cfunc_type)(func_ptr) return M,cfunc def check_expr(self, e, args): M,cfunc = self.get_c_func(e, args) # Eval 'e' evale = EX.eval_expr(e) for n in range(100): args_v = [random.getrandbits(a.nbits) for a in args] self.assertEqual(cfunc(*args_v), evale.eval({a: args_v[i] for i,a in enumerate(args)})) self.engine.remove_module(M) def test_tree(self): e0 = EX.ExprXor(self.ex, self.ey) e = EX.ExprAdd(e0,e0) self.check_expr(e, self.args) def test_binops(self): for op in (EX.ExprAdd,EX.ExprSub,EX.ExprMul,EX.ExprOr,EX.ExprXor,EX.ExprAnd): e = op(*self.eargs) self.check_expr(e, self.args) 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_concat_slice(self): e = EX.ExprConcat(self.ex[:4], self.ey[:4]) self.check_expr(e, self.args) e = EX.ExprConcat(self.ex[:2], self.ey[2:8]) self.check_expr(e, self.args) def test_broadcast(self): for nbits in (8,16): for i in range(8): e = EX.ExprBroadcast(self.ex, i, nbits) self.check_expr(e, [self.x]) def test_not(self): e = EX.ExprNot(self.ex) self.check_expr(e, [self.x]) 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)
from arybo.lib import MBA mba = MBA(4) p = mba.var('X') v0 = (p + 2) & 15 bp = (v0 >> 1) & 1 cp = (v0 >> 2) & 1 b = (p >> 1) & 1 v1 = v0 ^ ((bp << 2) | ((b & (bp ^ cp)) << 3)) v2 = v1 ^ (b << 3) VD = v2.vectorial_decomp([p]) print(v2) print("====") print("Cst = " + hex(VD.cst().get_int_be()))
use_exprs = int(sys.argv[1]) def f(x): v0 = x * 0xe5 + 0xF7 v0 = v0 & 0xFF v3 = (((((v0 * 0x26) + 0x55) & 0xFE) + (v0 * 0xED) + 0xD6) & 0xFF) v4 = ((((((-(v3 * 0x2)) + 0xFF) & 0xFE) + v3) * 0x03) + 0x4D) v5 = (((((v4 * 0x56) + 0x24) & 0x46) * 0x4B) + (v4 * 0xE7) + 0x76) v7 = ((((v5 * 0x3A) + 0xAF) & 0xF4) + (v5 * 0x63) + 0x2E) v6 = (v7 & 0x94) v8 = ((((v6 + v6 + (-(v7 & 0xFF))) * 0x67) + 0xD)) res = ((v8 * 0x2D) + (((v8 * 0xAE) | 0x22) * 0xE5) + 0xC2) & 0xFF return (0xed * (res - 0xF7)) & 0xff mba8 = MBA(8) X = mba8.var('X') if use_exprs: X = EX.ExprBV(X) res = f(X) if use_exprs: res = EX.eval_expr(res, use_esf=False) print(res) if use_exprs: X = X.v VD = res.vectorial_decomp([X]) print("====") print("Cst = " + hex(VD.cst().get_int_be()))