Post

Tracer is suddenly acting so strange

Why not working tracer

Tracer is suddenly acting so strange

Introduction

I recently use tools from linux to windows.

sometimes it has been and show me the very strange workflow.

like it.

1
2
3
4
5
6
7
8
9
10
180 ms  fopen()
180 ms  fopen()
181 ms  fopen()
181 ms  fopen()
181 ms  fopen()
181 ms  fopen()
182 ms  fopen()
182 ms  fopen()
183 ms  fopen()
184 ms  fopen()

I expect like..

1
2
3
4
5
6
7
8
9
10
180 ms  fopen(path="path/to/file", mode="rb")
180 ms  fopen(path="path/to/file", mode="rb")
181 ms  fopen(path="path/to/file", mode="rb")
181 ms  fopen(path="path/to/file", mode="rb")
181 ms  fopen(path="path/to/file", mode="rb")
181 ms  fopen(path="path/to/file", mode="rb")
182 ms  fopen(path="path/to/file", mode="rb")
182 ms  fopen(path="path/to/file", mode="rb")
183 ms  fopen(path="path/to/file", mode="rb")
184 ms  fopen(path="path/to/file", mode="rb")

So I check repository commit of tool and binary diff and check a update option list.. but i have no idea..

so I just reverse it for issue tracking :) I do not explain this feature archtecture, I just say code flow of tool.

What is that

it is very strong dynamic tracer for reverse.

sometime I use it. for develop and research.

Exploring Different Perspectives

Here we go.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    def _create_stub_native_handler(self, target: TraceTarget, decorate: bool) -> str:
        if target.flavor == "objc":
            ...
        elif target.flavor == "swift":
            ...
        else:
            log_str = self._create_cstyle_logging_code(target, decorate)
        return """\
defineHandler({
  onEnter(log, args, state) {
    log(%(log_str)s);
  },

  onLeave(log, retval, state) {
  }
});
""" % {
            "display_name": target.display_name,
            "log_str": log_str,
        }

here is generate code snippet.

Check a language from if condition.

so check a function of _create_cstyle_logging_code().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    def _create_cstyle_logging_code(self, target: TraceTarget, decorate: bool) -> str:
        if decorate:
            module_string = f" [{Path(target.scope).name}]"
        else:
            module_string = ""

        args = self._generate_cstyle_argument_logging_code(target)
        if len(args) == 0:
            code = "'%(name)s()%(module_string)s'" % {"name": target.name, "module_string": module_string}
        else:
            code = "`%(name)s(%(args)s)%(module_string)s`" % {
                "name": target.name,
                "args": ", ".join(args),
                "module_string": module_string,
            }

        return code

I think it is check a decorate option and check a number of args.

And go to function of _generate_cstyle_argument_logging_code().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
    def _generate_cstyle_argument_logging_code(self, target: TraceTarget) -> List[str]:
        if self._manpages is None:
            self._manpages = {}
            try:
                manroots = [
                    Path(d)
                    for d in subprocess.run(["manpath"], stdout=subprocess.PIPE, encoding="utf-8",   check=True)
                    .stdout.strip()
                    .split(":")
                ]
                for section in (2, 3):
                    for manroot in manroots:
                        mandir = manroot / f"man{section}"
                        if not mandir.exists():
                            continue
                        raw_section = str(section)
                        for entry in mandir.iterdir():
                            tokens = entry.name.split(".")
                            if len(tokens) < 2:
                                continue
                            if not tokens[1].startswith(raw_section):
                                continue
                            name = tokens[0]
                            if name in self._manpages:
                                continue
                            self._manpages[name] = (entry, section)
            except:
                return []

        man_entry = self._manpages.get(target.name)
        if man_entry is None:
            return []
        man_location, man_section = man_entry

        try:
            args = []
            cfunc = next(f for f in self._read_manpage(man_location) if f.name == target.name)
            for arg in cfunc.arguments:
                if arg == "void":
                    continue
                if arg.startswith("..."):
                    args.append("...")
                    continue

                tokens = arg.split(" ")

                arg_type = "".join(tokens[:-1])

                arg_name = tokens[-1]
                if arg_name.startswith("*"):
                    arg_type += "*"
                    arg_name = arg_name[1:]
                elif arg_name.endswith("]"):
                    arg_type += "*"
                    arg_name = arg_name[: arg_name.index("[")]

                read_ops = ""
                annotate_pre = ""
                annotate_post = ""

                if arg_type.endswith("*restrict"):
                    arg_type = arg_type[:-8]
                if arg_type in ("char*", "constchar*"):
                    read_ops = ".readUtf8String()"
                    annotate_pre = '"'
                    annotate_post = '"'

                arg_index = len(args)

                args.append(
                    "%(arg_name)s=%(annotate_pre)s${args[%(arg_index)s]%(read_ops)s}%(annotate_post)s"
                    % {
                        "arg_name": arg_name,
                        "arg_index": arg_index,
                        "read_ops": read_ops,
                        "annotate_pre": annotate_pre,
                        "annotate_post": annotate_post,
                    }
                )
            return args
        except Exception:
            return []

Yeah, it is parse API and generate args string like:

1
fopen(const char* file, int mode)

to

1
fopen(path="path/to/file", mode="rb")

We need check a this line.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
try:
    manroots = [
        Path(d)
        for d in subprocess.run(["manpath"], stdout=subprocess.PIPE, encoding="utf-8",   check=True) # <=== Yeah, this is our troubleshooting point.
        .stdout.strip()
        .split(":")
    ]
    for section in (2, 3):
        for manroot in manroots:
            mandir = manroot / f"man{section}"
            if not mandir.exists():
                continue
            raw_section = str(section)
            for entry in mandir.iterdir():
                tokens = entry.name.split(".")
                if len(tokens) < 2:
                    continue
                if not tokens[1].startswith(raw_section):
                    continue
                name = tokens[0]
                if name in self._manpages:
                    continue
                self._manpages[name] = (entry, section)
except:
    return []

what is that?

First it is use ‘manpath’ from subprocess.

it is only use unix style.

and if it is appear exception go to except point from arch of try-catch.

so how to fix it? hahahaha

windows is just show me blank API

1
2
3
4
5
6
7
8
9
10
180 ms  fopen()
180 ms  fopen()
181 ms  fopen()
181 ms  fopen()
181 ms  fopen()
181 ms  fopen()
182 ms  fopen()
182 ms  fopen()
183 ms  fopen()
184 ms  fopen()

May be I think, we have a 2 way solution.

1.Use a declared API list.

like it.

1
2
3
4
5
6
FUNC_SIGNATURES = {
    "write": ["int fd", "const void *buf", "size_t count"],
    "open": ["const char *pathname", "int flags", "mode_t mode"],
    "read": ["int fd", "void *buf", "size_t count"],
    ...
}

It is not good..

2.Parse Header libraries.

like it.

1
2
3
from pycparser import parse_file

ast = parse_file("/path/to/unistd.h", use_cpp=True)

it is not bad..but I can’t it. anyway it used other file and not automation script.

So.. how to contribute?

This post is licensed under CC BY 4.0 by the author.
If you find any errors, please let me know by comment or email. Thank you.

© Ruffalo. Some rights reserved.

I'm

Using the Chirpy theme for Jekyll.