├── .dockerignore ├── .gitignore ├── Dockerfile ├── run.sh ├── run.py └── README.md /.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | 3 | !run.py 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iso 2 | .*sw* 3 | 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM pandare/panda:latest 2 | 3 | COPY run.py . 4 | 5 | ENTRYPOINT ["python3", "run.py"] 6 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Usage ./run.sh [arch] [copydir] [target] (args) 4 | # usage message + validation handled by run.py 5 | 6 | # Simple script to run with provided copydir mounted at same location in container 7 | 8 | set -eu 9 | copydir=$(realpath $2) 10 | 11 | docker build -t tenet_tracer . 12 | 13 | set -x 14 | docker run --rm -v $copydir:$copydir tenet_tracer $1 $copydir ${@:3} 15 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | import os 2 | from shutil import copy 3 | from sys import argv, exit, stderr 4 | try: 5 | from pandare import Panda 6 | except ImportError: 7 | print("Error, could not load pandare package - are you running inside the container?") 8 | 9 | SUPPORTED_ARCHES = ["x86", "x86_64"] 10 | 11 | def usage(): 12 | print(f"USAGE {argv[0]} [arch] [copydir] [target] (args)") 13 | print(f"\tarch: " + " ".join(SUPPORTED_ARCHES)) 14 | print(f"\tcopydir: path to directory (inside container) that will be copied into the guest") 15 | print(f"\ttarget: path (relative to copydir) to the binary to execute") 16 | print(f"\targs: optional arguments to the binary to execute") 17 | exit(1) 18 | 19 | if len(argv) < 4: 20 | usage() 21 | 22 | arch = argv[1] 23 | copydir = argv[2] 24 | target = argv[3] 25 | args = [] 26 | if len(argv) > 4: 27 | args = argv[4:] 28 | 29 | if arch not in SUPPORTED_ARCHES: 30 | print("Unsupported architecture") 31 | usage() 32 | 33 | full_targ = f"./{copydir}/{target}" if not copydir.startswith("/") else f"{copydir}/{target}" 34 | target_name = target.split("/")[-1] 35 | 36 | if not os.path.isfile(full_targ): 37 | print(f"No such file {full_targ}") 38 | usage() 39 | 40 | panda = Panda(generic=arch) 41 | 42 | # Drive guest such that it executs our target 43 | @panda.queue_blocking 44 | def driver(): 45 | panda.revert_sync("root") 46 | panda.copy_to_guest(copydir, absolute_paths=True) 47 | panda.run_serial_cmd(f"chmod +x {full_targ}") 48 | panda.run_serial_cmd(f"cd {copydir}") 49 | panda.load_plugin("trace", {"target": target_name, 'log': "trace.log"}) 50 | print(panda.run_serial_cmd(f"./{target} {' '.join(args)}")) 51 | 52 | panda.end_analysis() 53 | 54 | # Extra information: print the base address target is loaded at to stderr 55 | @panda.ppp("proc_start_linux", "on_rec_auxv") 56 | def proc_start(cpu, tb, auxv): 57 | procname = panda.ffi.string(auxv.argv[0]).decode(errors='ignore') if auxv.argv[0] != panda.ffi.NULL else "(error)" 58 | 59 | if target_name in procname: 60 | print(f"{procname} loaded at 0x{auxv.program_header:x}") 61 | 62 | 63 | panda.run() 64 | copy("trace.log", full_targ+".log") 65 | print(f"\nTrace collection finished. Log is at {full_targ}.log") 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TENET Tracer 2 | ---- 3 | 4 | Simple container to run [PANDA](https://panda.re)s' [Tenet](https://github.com/gaasedelen/tenet) trace collection [plugin](https://github.com/panda-re/panda/tree/master/panda/plugins/trace) on a target program and also log the load address of your target program. 5 | 6 | 7 | ## Example usage. 8 | If you want to trace the program `ls` running with arguments `-al` and inside a directory with a file called `foo`: 9 | ``` 10 | mkdir testdir 11 | cp /bin/ls ./testdir 12 | touch ./testdir/foo 13 | 14 | ./run.sh x86_64 ./testdir ls -al 15 | ``` 16 | 17 | Output: 18 | ``` 19 | Sending build context to Docker daemon 5.632kB 20 | Step 1/5 : FROM pandare/pandadev:latest 21 | ... 22 | Successfully tagged tenet_tracer:latest 23 | + docker run --rm -v /home/user/git/tenet_trace/testdir:/home/user/git/tenet_trace/testdir tenet_tracer x86_64 /home/user/git/tenet_trace/testdir ls -al 24 | PANDA[core]:... 25 | using generic 86_64 26 | Qcow bionic-server-cloudimg-amd64-noaslr-nokaslr.qcow2 doesn't exist. Downloading from https://panda-re.mit.edu. Thanks MIT! 27 | ... 28 | ./ls loaded at 0x7ffff7dd6090 29 | total 12036 30 | drwxr-xr-x 2 root root 4096 Apr 10 19:33 . 31 | drwxr-xr-x 4 root root 4096 Apr 10 19:33 .. 32 | -rw-r--r-- 1 root root 0 Apr 10 19:33 foo 33 | -rwxr-xr-x 1 root root 133792 Apr 10 19:33 ls 34 | 35 | Trace saved to testdir/ls.log 36 | ``` 37 | 38 | The results are then available in `testdir/ls.log`: 39 | ``` 40 | rip=0x7ffff7dd6ea0,rax=0x0,rdx=0x0,rbx=0x0,rsp=0x7fffffffeb88,rbp=0x0,rsi=0x0,rdi=0x7fffffffeb90,r8=0x0,r9=0x0,r10=0x0,r11=0x0,r12=0x0,r13=0x0,r14=0x0,r15=0x0 41 | rip=0x7ffff7dd6ea1,mw=7fffffffeb80:0000000000000000,rsp=0x7fffffffeb80 42 | ... 43 | ``` 44 | 45 | 46 | ## Supported architectures 47 | Just `x86` / `x86_64` for now. It would be pretty easy to expand the PANDA plugin and this repo to support additional architectures if you want to submit a PR. 48 | 49 | ## Implementation Overview 50 | We use PANDA's generic qcows to fetch a virtual machine of the requested archtiecture. Then we use PANDA's `copy_to_guest` 51 | functionality to copy a directory from our container into the guest and run the target program with the trace collection plugin loaded. 52 | The only tricky thing here is mapping host directories into the container and then copying those into the guest virtual machine. 53 | 54 | ## Current status 55 | The dockerfile building will go much faster once the tracer plugin is merged into PANDA's main branch. The outputs from the PANDA tracing plugin haven't yet been tested extensively with TENET. 56 | --------------------------------------------------------------------------------