예제 #1
0
def as_paths(trace, path=None):
    assert type(trace) == list

    path = path or tuple()

    #    self.find_offsets()

    trace = replace_f(trace, make_fands)

    for line in trace:
        if opcode(line) == "if":
            # assumes 'ifs' end trace
            cond, if_true, if_false = line[1], line[2], line[3]
            return as_paths(if_true, path + (cond,)) + as_paths(
                if_false, path + (is_zero(cond),)
            )

        if opcode(line) == "LOOP":
            path += (("LOOP", line[2]),)
            return as_paths(line[1], path)

        path += (line,)

    #    pprint_logic()

    return (list(path),)
예제 #2
0
def to_while(trace, jd, path=None):
    path = path or []

    while True:
        if trace == []:
            raise
        line = trace[0]
        trace = trace[1:]

        if m := match(line, ("if", ":cond", ":if_true", ":if_false")):
            cond, if_true, if_false = m.cond, m.if_true, m.if_false
            if is_revert(if_true):
                path.append(("require", is_zero(cond)))
                trace = if_false
                continue

            if is_revert(if_false):
                path.append(("require", cond))
                trace = if_true
                continue

            jds_true = find_f_list(if_true, get_jds)
            jds_false = find_f_list(if_false, get_jds)

            assert (jd in jds_true) != (jd in jds_false), (jds_true, jds_false)

            def add_path(line):
                if m := match(line, ("goto", Any, ":svs")):
                    path2 = path
                    for _, v_idx, v_val in m.svs:
                        path2 = replace(path2, ("var", v_idx), v_val)

                    return path2 + [line]
                else:
                    return [line]
예제 #3
0
def cleanup_ors(path):
    assert type(path) == list
    ret = []

    idx = 0
    while idx < len(path):
        if type(path[idx]) == list:

            path = path[:idx] + path[idx] + path[idx + 1 :]

        line = path[idx]

        if opcode(line) != "or":
            ret.append(line)

        elif len(line) == 2:  # one-sided or
            # clean up the inside, skip the next line in the main path
            condition = line[1][0]
            line = ("or", cleanup_ors(line[1]))
            ret.append(line)
            idx += 1

        elif len(line) == 3:  # two-sided or
            if len(line[1]) == 1:
                assert comp_bool(simplify_bool(line[1][0]), is_zero(line[2][0]))
                line = ("or", cleanup_ors(line[2]))
                ret.append(line)
            else:
                assert comp_bool(is_zero(line[1][0]), simplify_bool(line[2][0]))
                line = ("or", cleanup_ors(line[1]), cleanup_ors(line[2][1:]))
                ret.append(line)

        else:  # three-sided ors? madness!
            assert False

        idx += 1

    return ret
예제 #4
0
def pprint_logic(exp, indent=2):
    INDENT_LEN = 4

    if opcode(exp) == "while":
        if len(exp) == 5:
            cond, path, jd, vars = exp[1], exp[2], exp[3], exp[4]
        else:
            cond, path = exp[1], exp[2]
            vars = []

        for v in vars:
            yield " " * indent + list(
                pretty_line(("setvar", v[1], v[2]), add_color=True))[0]

        yield " " * indent + COLOR_GREEN + "while " + ENDC + prettify(
            cond, add_color=True, parentheses=False, rem_bool=True
        ) + COLOR_GREEN + ":" + ENDC  # +COLOR_GREEN+':  # '+str(jd)+ENDC
        if type(path) != list:
            path = path.trace

        for l in pprint_logic(path, indent + INDENT_LEN):
            yield l

    elif opcode(exp) == "require":
        _, cond = exp
        yield " " * indent + "require " + prettify(
            exp[1], add_color=True, parentheses=False, rem_bool=True) + ""

    elif m := match(
            exp,
        ("if", ":cond", ":if_true")):  # one-sided ifs, only after folding
        cond, if_true = m.cond, m.if_true
        if (len(if_true) == 1 and (first := if_true[0])
                and ((first == ("revert", 0)) or opcode(first) == "invalid")):
            yield " " * indent + "require " + prettify(is_zero(exp[1]),
                                                       add_color=True,
                                                       parentheses=False,
                                                       rem_bool=True)
예제 #5
0
                path.append(("require", cond))
                trace = if_true
                continue

            jds_true = find_f_list(if_true, get_jds)
            jds_false = find_f_list(if_false, get_jds)

            assert (jd in jds_true) != (jd in jds_false), (jds_true, jds_false)

            def add_path(line):
                if m := match(line, ("goto", Any, ":svs")):
                    path2 = path
                    for _, v_idx, v_val in m.svs:
                        path2 = replace(path2, ("var", v_idx), v_val)

                    return path2 + [line]
                else:
                    return [line]

            if jd in jds_true:
                if_true = rewrite_trace(if_true, add_path)
                return path, if_true, if_false, cond
            else:
                if_false = rewrite_trace(if_false, add_path)
                return path, if_false, if_true, is_zero(cond)

        else:
            path.append(line)

    assert False, f"no if after label?{jd}"
예제 #6
0
    def handle_jumps(self, trace, line, condition):

        i, op = line[0], line[1]
        stack = self.stack

        if "--explain" in sys.argv and op in (
            "jump",
            "jumpi",
            "selfdestruct",
            "stop",
            "return",
            "invalid",
            "assert_fail",
            "revert",
        ):
            trace.append(C.asm(f"       {stack}"))
            trace.append("")
            trace.append(f"[{line[0]}] {C.asm(op)}")

        if op in (
            "jump",
            "jumpi",
            "selfdestruct",
            "stop",
            "return",
            "invalid",
            "assert_fail",
            "revert",
        ):
            logger.debug("[%s] %s", i, op)

        if op == "jump":
            target = stack.pop()

            n = Node(
                self,
                start=target,
                safe=False,
                stack=tuple(self.stack.stack),
                condition=condition,
            )

            trace.append(("jump", n))
            return trace

        elif op == "jumpi":
            target = stack.pop()
            if_condition = simplify_bool(stack.pop())

            tuple_stack = tuple(self.stack.stack)
            n_true = Node(
                self,
                start=target,
                safe=False,
                stack=tuple_stack,
                condition=if_condition,
            )
            n_false = Node(
                self,
                start=self.loader.next_line(i),
                safe=True,
                stack=tuple_stack,
                condition=is_zero(if_condition),
            )

            if self.just_fdests:
                if (
                    (m := match(if_condition, ("eq", ":fx_hash", ":is_cd")))
                    and str(("cd", 0)) in str(m.is_cd)
                    and isinstance(m.fx_hash, int)
                ):
                    n_true.trace = [("funccall", m.fx_hash, target, tuple_stack)]
                if (
                    (m := match(if_condition, ("eq", ":is_cd", ":fx_hash")))
                    and str(("cd", 0)) in str(m.is_cd)
                    and isinstance(m.fx_hash, int)
                ):
                    n_true.trace = [("funccall", m.fx_hash, target, tuple_stack)]
예제 #7
0
            for l in pprint_logic(if_true, indent + INDENT_LEN):
                yield l

    elif m := match(exp, ("if", ":cond", ":if_true", ":if_false")):
        cond, if_true, if_false = m.cond, m.if_true, m.if_false
        if (len(if_false) == 1 and (first := if_false[0])
                and (first == ("revert", 0) or opcode(first) == "invalid")):
            yield " " * indent + "require " + prettify(
                exp[1], add_color=True, parentheses=False, rem_bool=True)

            for l in pprint_logic(exp[2], indent):
                yield l

        elif (len(if_true) == 1 and (first := if_true[0])
              and ((first == ("revert", 0)) or opcode(first) == "invalid")):
            yield " " * indent + "require " + prettify(is_zero(exp[1]),
                                                       add_color=True,
                                                       parentheses=False,
                                                       rem_bool=True)

            for l in pprint_logic(exp[3], indent):
                yield l

        else:
            yield " " * indent + "if " + prettify(
                exp[1], add_color=True, parentheses=False, rem_bool=True) + ":"

            for l in pprint_logic(if_true, indent + INDENT_LEN):
                yield l
            """
            while len(if_false) == 1 and opcode(if_false) == 'if' and len(if_false) == 4: