def operators_test(): solver = claripy.Solver() sym_one = claripy.BVS("one", 32) sym_uone = claripy.BVS("uone", 8) sym_zero = claripy.BVS("zero", 32) sym_neg_one = claripy.BVS("neg_one", 32) sym_uint_max = claripy.BVS("uint_max", 32) solver.add(sym_one == 1) solver.add(sym_uone == 1) solver.add(sym_zero == 0) solver.add(sym_neg_one == -1) solver.add(sym_uint_max == (2**32) - 1) one_node = ASTNode(Operator.LITERAL, [sym_one, ExprType(Type.BV32, signed=True)]) uone_node = ASTNode(Operator.LITERAL, [sym_uone, ExprType(Type.BV8, signed=False)]) zero_node = ASTNode(Operator.LITERAL, [sym_zero, ExprType(Type.BV32, signed=True)]) neg_one_node = ASTNode( Operator.LITERAL, [sym_neg_one, ExprType(Type.BV32, signed=True)]) uint_max_node = ASTNode( Operator.LITERAL, [sym_uint_max, ExprType(Type.BV32, signed=False)]) one_eq_zero_node = ASTNode(Operator.NEQ, [one_node, zero_node]) check(solver, one_eq_zero_node.get_sym(None)) neg_one_eq_uint_max_node = ASTNode(Operator.NEQ, [neg_one_node, uint_max_node]) check(solver, neg_one_eq_uint_max_node.get_sym(None)) uone_eq_one_node = ASTNode(Operator.EQ, [one_node, uone_node]) check(solver, uone_eq_one_node.get_sym(None)) sum_node = ASTNode(Operator.PLUS, [one_node, neg_one_node]) sum_zero_node = ASTNode(Operator.EQ, [sum_node, zero_node]) check(solver, sum_zero_node.get_sym(None)) sub_node = ASTNode(Operator.MINUS, [zero_node, neg_one_node]) sub_one_node = ASTNode(Operator.EQ, [sub_node, one_node]) check(solver, sub_one_node.get_sym(None)) mul_node = ASTNode(Operator.MUL, [neg_one_node, neg_one_node]) mul_one_node = ASTNode(Operator.EQ, [mul_node, one_node]) check(solver, mul_one_node.get_sym(None)) xor_node = ASTNode(Operator.BXOR, [uint_max_node, neg_one_node]) xor_zero_node = ASTNode(Operator.EQ, [xor_node, zero_node]) check(solver, xor_zero_node.get_sym(None))
def calls_test(): os.system("gcc ../tests/simple_cond_call_cond.c -o ../test -O0 -g") proj = angr.Project("../test") testscope = GlobalScope(proj) # General condition allowed = ASTNode(Operator.VAR, ["allowed", ExprType(Type.BV8, 0), testscope]) one_node = ASTNode(Operator.LITERAL, [1, ExprType(Type.BV8, 0)]) cond = ASTNode(Operator.EQ, [allowed, one_node]) evt = CallEvent(proj.loader.find_symbol("special"), testscope, cond, "CALL(special) -> allowed == 1") return Engine(proj, [evt])
def return_test(): os.system("gcc ../tests/return.c -o ../test -O0 -g") proj = angr.Project("../test") testscope = GlobalScope(proj) # General Condition retn_node = ASTNode(Operator.RETN, [ExprType(Type.BV32, 0)]) val_node = ASTNode(Operator.VAR, ["val", ExprType(Type.BV32, 0), testscope]) cond = ASTNode(Operator.GT, [retn_node, val_node]) evt = ReturnEvent( proj.loader.find_symbol("main").rebased_addr, testscope, cond, "RETURN() -> RETURN_VAL() > val") return Engine(proj, [evt])
def locals_test(): os.system("gcc ../tests/locals.c -o ../test -O0 -g") proj = angr.Project("../test") testscope = GlobalScope(proj) funcscope = FunctionScope(proj, "func") # General Condition local_node = ASTNode( Operator.VAR, ["local", ExprType(Type.BV32, signed=True), funcscope]) arg_node = ASTNode( Operator.VAR, ["arg", ExprType(Type.BV32, signed=True), funcscope]) next_node = ASTNode(Operator.NEXT, [local_node]) cond = ASTNode(Operator.GT, [local_node, arg_node]) evt = ReturnEvent( proj.loader.find_symbol("func").rebased_addr, funcscope, cond, "WRITE(local) -> NEXT(local) > arg") return Engine(proj, [evt])
def get_type_from_str(type): expr_type = None bool_reg = "bool(\**)" bool_match = re.match(bool_reg, type) num_reg = "(u?)num(8|16|32|64)(\**)" num_match = re.match(num_reg, type) if bool_match is not None: expr_type = ExprType(Type.BOOL, pointers=len(bool_match.group(1))) elif num_match is not None: signed = len(num_match.group(1)) == 0 size = int(num_match.group(2)) pointers = len(num_match.group(3)) if size == 8: expr_type = ExprType(Type.BV8, pointers=pointers, signed=signed) elif size == 16: expr_type = ExprType(Type.BV16, pointers=pointers, signed=signed) elif size == 32: expr_type = ExprType(Type.BV32, pointers=pointers, signed=signed) else: expr_type = ExprType(Type.BV64, pointers=pointers, signed=signed) else: # TODO: Handle errors better assert False return expr_type
def arrays_test(): os.system("gcc ../tests/arrays.c -o ../test -O0 -g") proj = angr.Project("../test") testscope = GlobalScope(proj) # # General Condition arr_node = ASTNode(Operator.VAR, ["arr", ExprType(Type.BV32, 0), testscope]) idx_node = ASTNode(Operator.VAR, ["idx", ExprType(Type.BV32, 0), testscope]) two_node = ASTNode(Operator.LITERAL, [2, ExprType(Type.BV32, 0)]) arr_index_two_node = ASTNode(Operator.INDEX, [arr_node, two_node]) arr_index_idx_node = ASTNode(Operator.INDEX, [arr_node, idx_node]) next_node = ASTNode(Operator.NEXT, [arr_index_two_node]) cond = ASTNode(Operator.LE, [arr_index_idx_node, next_node]) print("General Constraint: " + cond.stringify()) evt = WriteEvent(arr_index_two_node, testscope, cond, "WRITE(arr[2]) -> arr[idx] <= NEXT(arr[2])") return Engine(proj, [evt])
def write_next_test(): os.system("gcc ../tests/next_definition.c -o ../test -O0 -g") proj = angr.Project("../test") testscope = GlobalScope(proj) # General condition var_name = "pUID" var_type = ExprType(Type.BV32, 1) var_scope = testscope var_node = ASTNode(Operator.VAR, [var_name, var_type, var_scope]) deref_node = ASTNode(Operator.DEREF, [var_node]) next_node = ASTNode(Operator.NEXT, [deref_node]) cond = ASTNode(Operator.GE, [next_node, deref_node]) print("General Contraint: " + cond.stringify()) # Create the event evt = WriteEvent(deref_node, testscope, cond, "WRITE(*pUID) -> NEXT(*pUID) >= *pUID") return Engine(proj, [evt])
def parse_tree(tree, variables): if isinstance(tree, InvariantParser.FunAppExprContext): func_tok = tree.getChild(0) if func_tok.getChild(0) is None: func_name = func_tok.symbol.text else: func_name = func_tok.getChild(0).symbol.text assert(func_name == "NEXT" or func_name == "RETURN_VAL") if func_name == "NEXT": operand_one = parse_tree(tree.getChild(2), variables) return ASTNode(Operator.NEXT, [operand_one]) else: type_tok = tree.getChild(2) if type_tok.getChild(0) is None: type_name = type_tok.symbol.text else: type_name = type_tok.getChild(0).symbol.text operand_one = get_type_from_str(type_name) return ASTNode(Operator.RETN, [operand_one]) elif isinstance(tree, InvariantParser.IndexExprContext): operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) return ASTNode(Operator.INDEX, [operand_one, operand_two]) op = int((tree.getChildCount() - 1) / 2) token = tree.getChild(op) if token is None: if re.fullmatch('[0-9]+', tree.symbol.text): return ASTNode(Operator.LITERAL, [int(tree.symbol.text), ExprType(Type.BV64, pointers=0, signed=int(tree.symbol.text) <= 2 ** 63 - 1)]) else: if tree.symbol.text == "true" or tree.symbol.text == "false": return ASTNode(Operator.LITERAL, [tree.symbol.text == "true", ExprType(Type.BOOL, 0)]) assert(tree.symbol.text in variables) return ASTNode(Operator.VAR, [tree.symbol.text, variables[tree.symbol.text][0], variables[tree.symbol.text][1]]) if token.symbol.text == "+": operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.PLUS return ASTNode(operator, [operand_one, operand_two]) elif token.symbol.text == "-": if tree.getChildCount == 3: operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.MINUS return ASTNode(operator, [operand_one, operand_two]) else: operand_one = ASTNode(Operator.LITERAL, ['0', ExprType(Type.BV64, 0)]) operand_two = parse_tree(tree.getChild(1), variables) operator = Operator.MINUS return ASTNode(operator, [operand_one, operand_two]) elif token.symbol.text == '*': if tree.getChildCount() == 3: operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.TIMES return ASTNode(operator, [operand_one, operand_two]) else: operand_one = parse_tree(tree.getChild(1), variables) operator = Operator.DEREF return ASTNode(operator, [operand_one]) elif token.symbol.text == '/': operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.DIVIDE return ASTNode(operator, [operand_one, operand_two]) elif token.symbol.text == '&': operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.BAND return ASTNode(operator, [operand_one, operand_two]) elif token.symbol.text == '|': operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.BOR return ASTNode(operator, [operand_one, operand_two]) elif token.symbol.text == '^': operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.BXOR return ASTNode(operator, [operand_one, operand_two]) elif token.symbol.text == '==': operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.EQ return ASTNode(operator, [operand_one, operand_two]) elif token.symbol.text == '!=': operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.NEQ return ASTNode(operator, [operand_one, operand_two]) elif token.symbol.text == '>': operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.GT return ASTNode(operator, [operand_one, operand_two]) elif token.symbol.text == '<': operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.LT return ASTNode(operator, [operand_one, operand_two]) elif token.symbol.text == '>=': operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.GE return ASTNode(operator, [operand_one, operand_two]) elif token.symbol.text == '<=': operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.LE return ASTNode(operator, [operand_one, operand_two]) elif token.symbol.text == '&&': operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.LAND return ASTNode(operator, [operand_one, operand_two]) elif token.symbol.text == '||': operand_one = parse_tree(tree.getChild(0), variables) operand_two = parse_tree(tree.getChild(2), variables) operator = Operator.LOR return ASTNode(operator, [operand_one, operand_two]) elif token.symbol.text == '!': operand_one = parse_tree(tree.getChild(1), variables) operator = Operator.LNOT return ASTNode(operator, [operand_one]) elif token.symbol.text == '~': operand_one = parse_tree(tree.getChild(1), variables) operator = Operator.BNOT return ASTNode(operator, [operand_one]) elif re.fullmatch('[0-9]+', token.symbol.text): return ASTNode(Operator.LITERAL, [int(token.symbol.text), ExprType(Type.BV64, pointers=0, signed=int(token.symbol.text) <= 2 ** 63 - 1)]) else: if token.symbol.text == "true" or token.symbol.text == "false": return ASTNode(Operator.LITERAL, [token.symbol.text == "true", ExprType(Type.BOOL, 0)]) assert (token.symbol.text in variables) return ASTNode(Operator.VAR, [token.symbol.text, variables[token.symbol.text][0], variables[token.symbol.text][1]])