Traces

Note

The CLIs documented below are part of the legacy mate CLI, which is in the process of being removed. Everything below is kept for posterity, but may no longer be functional.

MATE has the ability to collect block-level execution traces. This is useful because this enables some analyses that aren’t otherwise possible.

Mate first compiles an instrumented binary. In the instrumented binary each basic block has an extra function call to a logging function, so that when that basic block is executed, it logs its uuid to stdout. Mate can then run this instrumented binary and log the collected traces.

Collecting Traces

You can collect traces by running mate trace collect:

mate trace collect --source [-s] <Path to .ll file> --label [-l] <label> --output-filename [-o] <output.trace> --target-args [-a] "<arg0> <arg1> ..."

This will build an instrumented binary, save it to a workspace (it uses the same default workspace behavior as mate build), and then run it. If there’s already an instrumented binary in that workspace it will use it instead of rebuilding (yay, workspaces!).

The --label command line argument gets saved along with the collected trace. The label is intended to describe the execution trace, and may be specific to a given analysis. For instance, an analysis may wish to process traces which are labeled as either authenticated or unauthenticated.

The --target-args command line argument takes a string containing arguments for the instrumented binary, and passes them to the instrumented binary.

Example: tracing example_1

Collect traces for example_1:

mate -v trace collect -s <path_to_example_1.ll>/example_1.ll -l authenticated -o test.trace -a "hello world"

To generate an interesting trace, you’ll need to send inputs to the running binary. First start the instrumented binary running by executing the above command.

To interact with example_1, and likely all other programs, you need to open another shell into the same docker image and use netcat. You can do this by doing docker ps, finding the image name (ie, it’ll be something like musing-jackson), and then doing docker exec -it <NAME> /bin/bash. Once in the docker image, use netcat:

root@28bed379fb65:/builds/mate/MATE/# netcat -v localhost 8081
localhost [127.0.0.1] 8081 (tproxy) open
Enter Information: <-- netcat wrote that
hello there <-- I typed that and hit enter; it's the input that example_1 expects
world <-- example_1 server wrote that; it's what happens when you authenticate

Once you’ve finished interacting with the running binary, you can stop it by typing control+c in the shell running mate traces. This will stop the running binary and write the collected trace to the specified output file.

The output file produced from running example_1 has a JSON object and looks like:

$ cat submodules/mate-tests/tests/example_1/challenge_bin/example_1.bin.workspace/test.trace
{"label": "example_label", "trace": ["<block>:@main:%i0", "<block>:@main:%i2", "<block>:@main:%i3", "<block>:@main:%i5", "<block>:@setupServer:%i0", "<block>:@setupServer:%i2", "<block>:@setupServer:%i4", "Listening on port 8081...", "<block>:@setupServer:%i5", "<block>:@main:%i7", "<block>:@runServer:%i0", "<block>:@runServer:%i1"]}

Instrumenting Binaries

It’s also possible to build an instrumented binary without running it with mate trace instrument.

To build an instrumented binary of example_1 but not collect traces, run:

mate trace instrument submodules/mate-tests/tests/example_1/challenge_bin/example_1.bin.ll