-
Notifications
You must be signed in to change notification settings - Fork 5
/
inspectre
executable file
·108 lines (84 loc) · 4.36 KB
/
inspectre
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#!/usr/bin/env python3
import argparse
import csv
import subprocess
import os
from analyzer import analyzer
from reasoner import reasoner
def parse_gadget_list(filename):
file = open(filename, "r")
data = list(csv.reader(file, delimiter=","))
file.close()
if len(data[0]) != 2:
print("Invalid CSV: gadgets should be in the form of <hex_address>,<name")
exit(-1)
return data
def run_analyzer(args):
# No support for mutually exclusivity between a group of 1 and 2 arguments
# so we check manually for this
if args.address_list and args.name:
arg_parser.error("--name: not allowed with argument --address-list")
# Parse entrypoint list.
entrypoints = []
if args.address != "":
entrypoints = [[args.address, args.name if args.name != "" else os.path.basename(args.binary)]]
elif args.address_list != "":
entrypoints = parse_gadget_list(args.address_list)
parsed_entrypoints = [[int(x[0], 16), str(x[1]).strip()] for x in entrypoints]
# Base address is by default the address of the first entrypoint.
if args.base_address == "":
base_address = 0x0
else:
base_address = int(args.base_address, 16)
analyzer.run(binary=args.binary,
config_file=args.config,
base_address=base_address,
gadgets=parsed_entrypoints,
cache_project=args.cache_project,
csv_filename=args.output,
tfp_csv_filename=args.tfp_output,
asm_folder=args.asm,
symbol_binary=args.symbol_binary)
def run_reasoner(args):
reasoner.run(args.csv_in, args.csv_out)
def run_viewer(args):
asm_files = os.listdir(args.folder)
asm = [ f"{args.folder}/{x}" for x in asm_files if args.id in x ]
if len(asm) == 0:
print("Not found")
exit()
subprocess.run(["batcat"] + asm)
if __name__ == '__main__':
arg_parser = argparse.ArgumentParser(description='An inspector for Spectre gadgets')
subparsers = arg_parser.add_subparsers(dest='command', help='command to run', required=True)
# ----------- Analyzer
analyzer_args = subparsers.add_parser('analyze', help='Extract a list of transmission gadgets from a binary')
# Required args.
analyzer_args.add_argument('binary')
analyzer_args.add_argument('--config', type=str, required=True, help='which configuration file to use')
group = analyzer_args.add_mutually_exclusive_group(required=True)
group.add_argument('--address', default='', help='inspect a single entrypoint at the given (hex) address')
analyzer_args.add_argument('--name', default='', help='give a name to the single entrypoint to analyze (you can choose any name)')
group.add_argument('--address-list', default='', help='read entrypoints from a file with the format <HEX_ADDRESS>,<NAME> (you can choose any name)')
# Optional args.
analyzer_args.add_argument('--cache-project', action='store_true', help='load the angr project from a pickle named <BINARY>.angr, or create one if it does not exist')
analyzer_args.add_argument('--base-address', required=False, default='', help='base address of the binary to analyze')
analyzer_args.add_argument("--symbol-binary", default='', help='binary that contains function symbols')
# Outputs.
analyzer_args.add_argument('--output', required=False, default='', help='output all found gadgets to a CSV')
analyzer_args.add_argument('--tfp-output', required=False, default='', help='output all found dispatch gadgets to a CSV')
analyzer_args.add_argument('--asm', required=False, default='', help='output an annotated ASM file for each gadget to the specified folder')
# Run.
analyzer_args.set_defaults(func=run_analyzer)
# ----------- Reasoner
reasoner_args = subparsers.add_parser('reason', help='Reason about gadget exploitability')
reasoner_args.add_argument('csv_in')
reasoner_args.add_argument('csv_out')
reasoner_args.set_defaults(func=run_reasoner)
# ----------- Viewer
viewer_args = subparsers.add_parser('show', help='Inspect a specific gadget')
viewer_args.add_argument('folder', help='folder containing the annotated assembly files')
viewer_args.add_argument('id', help='uuid or pc reported by the analyzer (in hex)')
viewer_args.set_defaults(func=run_viewer)
args = arg_parser.parse_args()
args.func(args)