示例#1
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]
示例#2
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), )
示例#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(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]), 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
        return True

    return False

def to_while(trace, jd, path = None):
    path = path or []

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

        if (line ~ ('if', :cond, :if_true, :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 line ~ ('goto', _, :svs):
示例#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
            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 exp ~ ('require', :cond):
        yield ' '*indent + 'require ' + prettify(exp[1], add_color=True, parentheses=False, rem_bool=True) + ''

    elif exp ~ ('if', :cond, :if_true): # one-sided ifs, only after folding
        if len(if_true) == 1 and (first := if_true[0]) and \
            ((first == ('revert', 0)) or (first ~ ('invalid', ...))):
                yield ' '*indent + 'require '+prettify(is_zero(exp[1]), add_color=True, parentheses=False, rem_bool=True)
        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


    elif exp ~ ('if', :cond, :if_true, :if_false):
        if len(if_false) == 1 and (first := if_false[0]) and \
            ((first == ('revert', 0)) or \
            (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
示例#8
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:
示例#9
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 == 'jump':
            target = stack.pop()

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

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

        if 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 if_condition ~ ('eq', int:fx_hash, :is_cd) and str(('cd', 0)) in str(is_cd):
                    n_true.trace=[('funccall', fx_hash, target)]
                if if_condition ~ ('eq', :is_cd, int:fx_hash) and str(('cd', 0)) in str(is_cd):
                    n_true.trace=[('funccall', fx_hash, target)]
示例#10
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}"