Trace symbol coverage
Purpose
Display a list of executed binaries and symbols in a REVEN scenario, indicating how many transitions where spent in each symbol/binary.
How to use
usage: trace_coverage.py [-h] [--host HOST] [-p PORT] [-m MAX_TRANSITION]
optional arguments:
-h, --help show this help message and exit
--host HOST Reven host, as a string (default: "localhost")
-p PORT, --port PORT Reven port, as an int (default: 13370)
-m MAX_TRANSITION, --max-transition MAX_TRANSITION
Maximum number of transitions
Known limitations
N/A
Supported versions
REVEN 2.2+
Supported perimeter
Any REVEN scenario.
Dependencies
None.
Source
import argparse
import reven2 as reven
"""
# Trace symbol coverage
## Purpose
Display a list of executed binaries and symbols in a REVEN scenario,
indicating how many transitions where spent in each symbol/binary.
## How to use
```bash
usage: trace_coverage.py [-h] [--host HOST] [-p PORT] [-m MAX_TRANSITION]
optional arguments:
-h, --help show this help message and exit
--host HOST Reven host, as a string (default: "localhost")
-p PORT, --port PORT Reven port, as an int (default: 13370)
-m MAX_TRANSITION, --max-transition MAX_TRANSITION
Maximum number of transitions
```
# Known limitations
N/A
## Supported versions
REVEN 2.2+
## Supported perimeter
Any REVEN scenario.
## Dependencies
None.
"""
def trace_coverage(reven_server, max_transition=None):
if max_transition is None:
max_transition = reven_server.trace.transition_count
else:
max_transition = min(max_transition, reven_server.trace.transition_count)
transition_id = 0
coverages = {}
while transition_id < max_transition:
ctx = reven_server.trace.context_before(transition_id)
transition_id += 1
asid = ctx.read(reven.arch.x64.cr3)
loc = ctx.ossi.location()
unknown = True if loc is None else False
binary = "unknown" if unknown else loc.binary.path
symbol = "unknown" if unknown or loc.symbol is None else loc.symbol.name
try:
asid_coverage = coverages[asid]
except KeyError:
coverages[asid] = {}
asid_coverage = coverages[asid]
try:
binary_coverage = asid_coverage[binary]
binary_coverage[0] += 1
if binary == "unknown":
continue
except KeyError:
if binary == "unknown":
asid_coverage[binary] = [1, None]
continue
asid_coverage[binary] = [1, {}]
binary_coverage = asid_coverage[binary]
try:
binary_coverage[1][symbol] += 1
except KeyError:
binary_coverage[1][symbol] = 1
return coverages
def print_coverages(coverages):
for (asid, asid_coverage) in coverages.items():
print("***** Coverage for CR3 = {:#x} *****\n".format(asid))
for (binary, binary_coverage) in asid_coverage.items():
print("- {}: {}".format(binary, binary_coverage[0]))
if binary_coverage[1] is None:
continue
for (symbol, symbol_coverage) in binary_coverage[1].items():
print(" - {}: {}".format(symbol, symbol_coverage))
print("\n")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--host", type=str, default="localhost", help='Reven host, as a string (default: "localhost")')
parser.add_argument("-p", "--port", type=int, default="13370", help="Reven port, as an int (default: 13370)")
parser.add_argument("-m", "--max-transition", type=int, help="Maximum number of transitions")
args = parser.parse_args()
reven_server = reven.RevenServer(args.host, args.port)
coverages = trace_coverage(reven_server, args.max_transition)
print_coverages(coverages)