reait 1.0.1__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- reait/__init__.py +0 -1
- reait/api.py +594 -105
- reait/main.py +353 -109
- {reait-1.0.1.dist-info → reait-1.1.0.dist-info}/METADATA +18 -13
- reait-1.1.0.dist-info/RECORD +9 -0
- {reait-1.0.1.dist-info → reait-1.1.0.dist-info}/WHEEL +1 -1
- reait-1.0.1.dist-info/RECORD +0 -9
- {reait-1.0.1.dist-info → reait-1.1.0.dist-info}/entry_points.txt +0 -0
- {reait-1.0.1.dist-info → reait-1.1.0.dist-info/licenses}/LICENSE +0 -0
- {reait-1.0.1.dist-info → reait-1.1.0.dist-info}/top_level.txt +0 -0
reait/main.py
CHANGED
@@ -1,23 +1,22 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
|
-
# -*- coding: utf-8 -*-
|
3
2
|
from __future__ import print_function
|
4
3
|
|
4
|
+
from sys import exit, stdout, stderr
|
5
|
+
|
6
|
+
import argparse
|
7
|
+
import json
|
5
8
|
import logging
|
9
|
+
import numpy as np
|
10
|
+
import os
|
11
|
+
from glob import iglob
|
6
12
|
from pathlib import Path
|
7
|
-
from
|
8
|
-
|
13
|
+
from requests import HTTPError
|
9
14
|
from rich import print_json
|
10
|
-
from rich.progress import track
|
11
15
|
from rich.console import Console
|
12
|
-
import
|
13
|
-
import argparse
|
14
|
-
import json
|
15
|
-
from sys import exit, stdout, stderr
|
16
|
+
from rich.progress import track
|
16
17
|
from scipy.spatial import distance
|
17
|
-
from
|
18
|
-
|
19
|
-
|
20
|
-
import api
|
18
|
+
from typing import Optional
|
19
|
+
from reait import api
|
21
20
|
|
22
21
|
rerr = Console(file=stderr, width=180)
|
23
22
|
rout = Console(file=stdout, width=180)
|
@@ -25,9 +24,10 @@ rout = Console(file=stdout, width=180)
|
|
25
24
|
|
26
25
|
def version() -> int:
|
27
26
|
"""
|
28
|
-
|
27
|
+
Display program version
|
29
28
|
"""
|
30
|
-
rout.print(
|
29
|
+
rout.print(
|
30
|
+
f"""[bold blue] :::::::: ::::::::
|
31
31
|
:: :::: ::: :::
|
32
32
|
::::::::::::::::::::
|
33
33
|
::::: ::: ::::::
|
@@ -38,7 +38,8 @@ def version() -> int:
|
|
38
38
|
:: ::::: :::: :::
|
39
39
|
:::::::: :::::::: [/bold blue]
|
40
40
|
[bold red]reait[/bold red] [bold bright_green]v{api.__version__}[/bold bright_green]
|
41
|
-
"""
|
41
|
+
"""
|
42
|
+
)
|
42
43
|
rout.print("[yellow]Config:[/yellow]")
|
43
44
|
print_json(data=api.re_conf)
|
44
45
|
return 0
|
@@ -52,7 +53,9 @@ def verify_binary(fpath_fmt: str) -> tuple[str, str, str]:
|
|
52
53
|
return fpath, exec_format, exec_isa
|
53
54
|
|
54
55
|
|
55
|
-
def match(
|
56
|
+
def match(
|
57
|
+
fpath: str, embeddings: list, confidence: float = 0.95, deviation: float = 0.1
|
58
|
+
) -> None:
|
56
59
|
"""
|
57
60
|
Match embeddings in fpath from a list of embeddings
|
58
61
|
"""
|
@@ -60,7 +63,7 @@ def match(fpath: str, embeddings: list, confidence: float = 0.95, deviation: flo
|
|
60
63
|
sink_embed_mat = np.vstack(list(map(lambda x: x["embedding"], embeddings)))
|
61
64
|
b_embeds = api.RE_embeddings(fpath).json()["data"]
|
62
65
|
source_embed_mat = np.vstack(list(map(lambda x: x["embedding"], b_embeds)))
|
63
|
-
# angular distance over cosine
|
66
|
+
# angular distance over cosine
|
64
67
|
# closest = 1.0 - distance.cdist(source_embed_mat, sink_embed_mat, 'cosine')
|
65
68
|
closest = distance.cdist(source_embed_mat, sink_embed_mat, api.angular_distance)
|
66
69
|
# rescale to separate high end of (-1, 1.0)
|
@@ -81,17 +84,20 @@ def match(fpath: str, embeddings: list, confidence: float = 0.95, deviation: flo
|
|
81
84
|
rout.print(
|
82
85
|
f"[bold green]Found match![/bold green][yellow]\tConfidence: {m_confidence:.05f}[/yellow]\t"
|
83
86
|
f"[blue]{source_symb['name']}:{source_symb['vaddr']}[/blue]\t->\t"
|
84
|
-
f"[blue]{sink_symb['name']}:{sink_symb['vaddr']}"
|
87
|
+
f"[blue]{sink_symb['name']}:{sink_symb['vaddr']}"
|
88
|
+
)
|
85
89
|
elif (m_confidence - s_confidence) > deviation:
|
86
90
|
rout.print(
|
87
91
|
f"[bold magenta]Possible match[/bold magenta][yellow]\t"
|
88
92
|
f"Confidence: {m_confidence:.05f}/{s_confidence:.05f}[/yellow]\t"
|
89
93
|
f"[blue]{source_symb['name']}:{source_symb['vaddr']}[/blue]\t->\t"
|
90
|
-
f"[blue]{sink_symb['name']}:{sink_symb['vaddr']}"
|
94
|
+
f"[blue]{sink_symb['name']}:{sink_symb['vaddr']}"
|
95
|
+
)
|
91
96
|
else:
|
92
97
|
rerr.print(
|
93
98
|
f"[bold red]No match for[/bold red]\t[blue]{source_symb['name']}:{source_symb['vaddr']}\t"
|
94
|
-
f"{sink_symb['name']} - {m_confidence:0.05f}[/blue]"
|
99
|
+
f"{sink_symb['name']} - {m_confidence:0.05f}[/blue]"
|
100
|
+
)
|
95
101
|
pass
|
96
102
|
|
97
103
|
|
@@ -101,29 +107,46 @@ def match_for_each(fpath: str, confidence: float = 0.9, nns: int = 1) -> int:
|
|
101
107
|
"""
|
102
108
|
nns = max(nns, 1)
|
103
109
|
|
104
|
-
rout.print(
|
105
|
-
|
110
|
+
rout.print(
|
111
|
+
f"Matching symbols from '{fpath}' with a confidence {confidence:.02f} and up to "
|
112
|
+
f"{nns} result{'' if nns == 1 else 's'} per function"
|
113
|
+
)
|
106
114
|
functions = api.RE_analyze_functions(fpath).json()["functions"]
|
107
|
-
function_matches = api.RE_nearest_functions(
|
115
|
+
function_matches = api.RE_nearest_functions(
|
116
|
+
fpath, nns=nns, distance=1 - confidence
|
117
|
+
).json()["function_matches"]
|
108
118
|
|
109
119
|
if len(function_matches) == 0:
|
110
|
-
rerr.print(
|
120
|
+
rerr.print(
|
121
|
+
f"[bold red]No matches found for a confidence of [/bold red] {confidence:.02f}"
|
122
|
+
)
|
111
123
|
return -1
|
112
124
|
else:
|
113
125
|
for function in functions:
|
114
|
-
matches = list(
|
126
|
+
matches = list(
|
127
|
+
filter(
|
128
|
+
lambda x: function["function_id"] == x["origin_function_id"],
|
129
|
+
function_matches,
|
130
|
+
)
|
131
|
+
)
|
115
132
|
|
116
133
|
if len(matches):
|
117
|
-
rout.print(
|
118
|
-
|
134
|
+
rout.print(
|
135
|
+
f"[bold green]Found {len(matches)} match{'' if len(matches) == 1 else 'es'} for "
|
136
|
+
f"[/bold green][blue]{function['function_name']}: {function['function_vaddr']:#x}[/blue]"
|
137
|
+
)
|
119
138
|
|
120
139
|
for match in matches:
|
121
|
-
rout.print(
|
122
|
-
|
123
|
-
|
140
|
+
rout.print(
|
141
|
+
f"\t[yellow]Confidence: {match['confidence']:.05f}[/yellow]"
|
142
|
+
f"\t[blue]{match['nearest_neighbor_function_name']}"
|
143
|
+
f" ({match['nearest_neighbor_binary_name']})[/blue]"
|
144
|
+
)
|
124
145
|
else:
|
125
|
-
rout.print(
|
126
|
-
|
146
|
+
rout.print(
|
147
|
+
f"[bold red]No matches found for[/bold red] "
|
148
|
+
f"[blue]{function['function_name']}: {function['function_vaddr']:#x}[/blue]"
|
149
|
+
)
|
127
150
|
return 0
|
128
151
|
|
129
152
|
|
@@ -158,67 +181,225 @@ def validate_dir(arg):
|
|
158
181
|
raise NotADirectoryError(f"Directory path {arg} does not exists.")
|
159
182
|
|
160
183
|
|
184
|
+
def report_api_error_message(f):
|
185
|
+
"""
|
186
|
+
Print message from API errors to console
|
187
|
+
"""
|
188
|
+
|
189
|
+
def decorate(f):
|
190
|
+
def applicator(*args, **kwargs):
|
191
|
+
try:
|
192
|
+
return f(*args, **kwargs)
|
193
|
+
except HTTPError as err:
|
194
|
+
content = err.response.json()
|
195
|
+
if "message" in content:
|
196
|
+
rerr.print(
|
197
|
+
f"[bold red]API Error[/bold red] [bold blue_violet]{err.response.status_code}[/bold blue_violet][bold red] to [/bold red][bold yellow]{err.response.url}[/bold yellow][bold red] {err.response.json()['message']}[/bold red]"
|
198
|
+
)
|
199
|
+
if "errors" in content:
|
200
|
+
for msg in content["errors"]:
|
201
|
+
rerr.print(f"[bold red]{msg['message']}[/bold red]")
|
202
|
+
|
203
|
+
exit()
|
204
|
+
|
205
|
+
return applicator
|
206
|
+
|
207
|
+
return decorate(f)
|
208
|
+
|
209
|
+
|
210
|
+
@report_api_error_message
|
161
211
|
def main() -> int:
|
162
212
|
"""
|
163
213
|
Tool entry
|
164
214
|
"""
|
165
215
|
parser = argparse.ArgumentParser(add_help=False)
|
166
|
-
parser.add_argument(
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
parser.add_argument(
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
parser.add_argument(
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
216
|
+
parser.add_argument(
|
217
|
+
"-b",
|
218
|
+
"--binary",
|
219
|
+
type=validate_file,
|
220
|
+
help="Path of binary to analyse, use ./path:{exec_format} to specify executable format e.g. ./path:raw-x86_64",
|
221
|
+
)
|
222
|
+
parser.add_argument(
|
223
|
+
"-B",
|
224
|
+
"--binary-hash",
|
225
|
+
default="",
|
226
|
+
help="Hex-encoded SHA-256 hash of the binary to use",
|
227
|
+
)
|
228
|
+
parser.add_argument(
|
229
|
+
"-D",
|
230
|
+
"--dir",
|
231
|
+
type=validate_dir,
|
232
|
+
help="Path of directory to recursively analyse",
|
233
|
+
)
|
234
|
+
parser.add_argument(
|
235
|
+
"-a",
|
236
|
+
"--analyse",
|
237
|
+
action="store_true",
|
238
|
+
help="Perform a full analysis and generate embeddings for every symbol",
|
239
|
+
)
|
240
|
+
parser.add_argument(
|
241
|
+
"--base-address",
|
242
|
+
help="Image base of the executable image to map for remote analysis",
|
243
|
+
)
|
244
|
+
parser.add_argument(
|
245
|
+
"-A", action="store_true", help="Upload and Analyse a new binary"
|
246
|
+
)
|
247
|
+
parser.add_argument(
|
248
|
+
"-u",
|
249
|
+
"--upload",
|
250
|
+
action="store_true",
|
251
|
+
help="Upload a new binary to remote server",
|
252
|
+
)
|
253
|
+
parser.add_argument(
|
254
|
+
"--duplicate",
|
255
|
+
default=False,
|
256
|
+
action="store_true",
|
257
|
+
help="Duplicate an existing binary",
|
258
|
+
)
|
259
|
+
parser.add_argument(
|
260
|
+
"--details",
|
261
|
+
default=False,
|
262
|
+
action="store_true",
|
263
|
+
help="Get binary additional details",
|
264
|
+
)
|
265
|
+
parser.add_argument(
|
266
|
+
"-e", "--embedding", help="Path of JSON file containing a BinNet embedding"
|
267
|
+
)
|
268
|
+
parser.add_argument(
|
269
|
+
"--nns",
|
270
|
+
default="5",
|
271
|
+
help="Number of approximate nearest neighbors to fetch",
|
272
|
+
type=int,
|
273
|
+
)
|
274
|
+
parser.add_argument(
|
275
|
+
"--collections",
|
276
|
+
default=None,
|
277
|
+
help="Comma Seperated Value of collections to search from e.g. libxml2,libpcap. Used to select RevEng.AI collections for filtering search results",
|
278
|
+
)
|
279
|
+
parser.add_argument(
|
280
|
+
"--found-in",
|
281
|
+
help="ANN flag to limit to embeddings returned to those found in specific binary",
|
282
|
+
)
|
283
|
+
parser.add_argument(
|
284
|
+
"--from-file",
|
285
|
+
help="ANN flag to limit to embeddings returned to those found in JSON embeddings file",
|
286
|
+
)
|
287
|
+
parser.add_argument(
|
288
|
+
"-c", "--cves", action="store_true", help="Check for CVEs found inside binary"
|
289
|
+
)
|
184
290
|
parser.add_argument("--sbom", action="store_true", help="Generate SBOM for binary")
|
185
|
-
parser.add_argument(
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
parser.add_argument(
|
192
|
-
|
193
|
-
|
194
|
-
|
291
|
+
parser.add_argument(
|
292
|
+
"-m", "--model", default=None, help="AI model used to generate embeddings"
|
293
|
+
)
|
294
|
+
parser.add_argument(
|
295
|
+
"-x", "--extract", action="store_true", help="Fetch embeddings for binary"
|
296
|
+
)
|
297
|
+
parser.add_argument(
|
298
|
+
"-M",
|
299
|
+
"--match",
|
300
|
+
action="store_true",
|
301
|
+
help="Match functions in binary file. Can be used with --confidence, --deviation, --from-file, --found-in.",
|
302
|
+
)
|
303
|
+
parser.add_argument(
|
304
|
+
"--confidence",
|
305
|
+
default="high",
|
306
|
+
choices=["high", "medium", "low", "partial", "all"],
|
307
|
+
help="Confidence threshold used to match symbols. Valid values are 'all', 'medium', 'low', 'partial' or 'high'[DEFAULT]",
|
308
|
+
)
|
309
|
+
parser.add_argument(
|
310
|
+
"--deviation",
|
311
|
+
default=0.1,
|
312
|
+
type=float,
|
313
|
+
help="Deviation in prediction confidence between outlier and next highest symbol. Use if confident symbol is present in binary but not matching.",
|
314
|
+
)
|
315
|
+
parser.add_argument(
|
316
|
+
"-l", "--logs", action="store_true", help="Fetch analysis log file for binary"
|
317
|
+
)
|
318
|
+
parser.add_argument(
|
319
|
+
"-d",
|
320
|
+
"--delete",
|
321
|
+
action="store_true",
|
322
|
+
help="Delete all metadata associated with binary",
|
323
|
+
)
|
195
324
|
parser.add_argument("-k", "--apikey", help="RevEng.AI Personal API key")
|
196
325
|
parser.add_argument("-h", "--host", help="Analysis Host (https://api.reveng.ai)")
|
197
|
-
parser.add_argument(
|
198
|
-
|
199
|
-
|
200
|
-
parser.add_argument(
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
parser.add_argument(
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
parser.add_argument(
|
326
|
+
parser.add_argument(
|
327
|
+
"-v", "--version", action="store_true", help="Display version information"
|
328
|
+
)
|
329
|
+
parser.add_argument(
|
330
|
+
"--help",
|
331
|
+
action="help",
|
332
|
+
default=argparse.SUPPRESS,
|
333
|
+
help=argparse._("Show this help message and exit"),
|
334
|
+
)
|
335
|
+
parser.add_argument(
|
336
|
+
"--isa",
|
337
|
+
default=None,
|
338
|
+
help="Override executable ISA. Valid values are x86, x86_64, ARMv7",
|
339
|
+
)
|
340
|
+
parser.add_argument(
|
341
|
+
"--exec-format",
|
342
|
+
default=None,
|
343
|
+
help="Override executable format. Valid values are pe, elf, macho, raw",
|
344
|
+
)
|
345
|
+
parser.add_argument(
|
346
|
+
"--platform",
|
347
|
+
default=None,
|
348
|
+
help="Override OS platform. Valid values are Windows, Linux, OSX, OpenBSD",
|
349
|
+
)
|
350
|
+
parser.add_argument(
|
351
|
+
"--dynamic-execution",
|
352
|
+
default=False,
|
353
|
+
action="store_true",
|
354
|
+
help="Enable dynamic execution in sandbox during analysis. Analysis will include any auto unpacked malware samples",
|
355
|
+
)
|
356
|
+
parser.add_argument(
|
357
|
+
"--cmd-line-args",
|
358
|
+
default="",
|
359
|
+
help="Command line arguments to pass when running binary sample in the sandbox. Only used when run with --dynamic-execution",
|
360
|
+
)
|
361
|
+
parser.add_argument(
|
362
|
+
"--scope",
|
363
|
+
default="private",
|
364
|
+
choices=["public", "private"],
|
365
|
+
help="Override analysis visibility (scope). Valid values are 'public' or 'private'[DEFAULT]",
|
366
|
+
)
|
367
|
+
parser.add_argument(
|
368
|
+
"--tags",
|
369
|
+
default=None,
|
370
|
+
type=str,
|
371
|
+
help="Assign tags to an analysis. Valid responses are tag1,tag2,tag3.",
|
372
|
+
)
|
373
|
+
parser.add_argument(
|
374
|
+
"--do-not-auto-tag",
|
375
|
+
default=False,
|
376
|
+
action="store_true",
|
377
|
+
help="Disable auto-tagging in API views",
|
378
|
+
)
|
379
|
+
parser.add_argument(
|
380
|
+
"--priority", default=0, type=int, help="Add priority to processing queue."
|
381
|
+
)
|
382
|
+
parser.add_argument(
|
383
|
+
"--verbose", default=False, action="store_true", help="Set verbose output."
|
384
|
+
)
|
385
|
+
parser.add_argument(
|
386
|
+
"--debug", default=None, help="Debug file path to write pass with analysis"
|
387
|
+
)
|
388
|
+
parser.add_argument(
|
389
|
+
"-s",
|
390
|
+
"--status",
|
391
|
+
action="store_true",
|
392
|
+
help="Ongoing status of the provided binary",
|
393
|
+
)
|
217
394
|
|
218
395
|
args = parser.parse_args()
|
219
396
|
|
220
397
|
# set re_conf args
|
221
|
-
for arg in (
|
398
|
+
for arg in (
|
399
|
+
"apikey",
|
400
|
+
"host",
|
401
|
+
"model",
|
402
|
+
):
|
222
403
|
if getattr(args, arg):
|
223
404
|
api.re_conf[arg] = getattr(args, arg)
|
224
405
|
|
@@ -243,7 +424,7 @@ def main() -> int:
|
|
243
424
|
|
244
425
|
if args.dir:
|
245
426
|
files = iglob(os.path.abspath(args.dir) + "/**/*", recursive=True)
|
246
|
-
|
427
|
+
# perform operation on all files inside directory
|
247
428
|
for file in track(files, description="Files in directory"):
|
248
429
|
if not os.path.isfile(file):
|
249
430
|
rerr.print(f"[blue]Skipping non-file:[/blue] {file}")
|
@@ -258,40 +439,72 @@ def main() -> int:
|
|
258
439
|
fpath, exec_fmt, exec_isa = verify_binary(file)
|
259
440
|
rout.print(f"Found {fpath}: {exec_fmt}-{exec_isa}")
|
260
441
|
except Exception as e:
|
261
|
-
rerr.print(
|
442
|
+
rerr.print(
|
443
|
+
f"[red bold][!] Error, binary exec type could not be verified:[/red bold] {file}"
|
444
|
+
)
|
262
445
|
rerr.print(f"[yellow] {e} [/yellow]")
|
263
446
|
|
264
447
|
rout.print(f"[green bold]Analysing:[/green bold] {file}")
|
265
|
-
api.RE_analyse(
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
448
|
+
api.RE_analyse(
|
449
|
+
file,
|
450
|
+
model_name=api.re_conf["model"],
|
451
|
+
isa_options=args.isa,
|
452
|
+
platform_options=args.platform,
|
453
|
+
dynamic_execution=args.dynamic_execution,
|
454
|
+
command_line_args=args.cmd_line_args,
|
455
|
+
file_options=args.exec_format,
|
456
|
+
binary_scope=args.scope.upper(),
|
457
|
+
tags=tags,
|
458
|
+
priority=args.priority,
|
459
|
+
duplicate=args.duplicate,
|
460
|
+
debug_fpath=args.debug,
|
461
|
+
skip_scraping=args.do_not_auto_tag,
|
462
|
+
)
|
270
463
|
|
271
464
|
if args.delete:
|
272
465
|
try:
|
273
|
-
rout.print(
|
466
|
+
rout.print(
|
467
|
+
f"[green bold]Deleting analyses for:[/green bold] {file}"
|
468
|
+
)
|
274
469
|
api.RE_delete(file)
|
275
470
|
except Exception as e:
|
276
|
-
rerr.print(
|
471
|
+
rerr.print(
|
472
|
+
f"[red bold][!] Error, could not delete analysis for:[/red bold] {file}"
|
473
|
+
)
|
277
474
|
rerr.print(f"[yellow] {e} [/yellow]")
|
278
475
|
|
279
476
|
if not (args.upload or args.analyse or args.delete):
|
280
|
-
rerr.print(
|
477
|
+
rerr.print(
|
478
|
+
f"Error, '-D' flag only supports upload, analyse, or delete."
|
479
|
+
)
|
281
480
|
return -1
|
282
|
-
elif
|
283
|
-
|
481
|
+
elif (
|
482
|
+
args.analyse
|
483
|
+
or args.extract
|
484
|
+
or args.logs
|
485
|
+
or args.delete
|
486
|
+
or args.details
|
487
|
+
or args.upload
|
488
|
+
or args.match
|
489
|
+
or args.cves
|
490
|
+
or args.sbom
|
491
|
+
or args.status
|
492
|
+
):
|
284
493
|
try:
|
285
494
|
fpath, exec_fmt, exec_isa = verify_binary(args.binary)
|
286
495
|
# keep stdout to data only
|
287
496
|
rout.print(f"Found {fpath}: {exec_fmt}-{exec_isa}")
|
288
497
|
args.binary = fpath
|
289
498
|
except TypeError as e:
|
290
|
-
rerr.print(
|
499
|
+
rerr.print(
|
500
|
+
"[bold red][!] Error, please supply a valid binary file using '-b' flag.[/bold red]"
|
501
|
+
)
|
291
502
|
rerr.print(f"[yellow] {e} [/yellow]")
|
292
503
|
return 0
|
293
504
|
except Exception as e:
|
294
|
-
rerr.print(
|
505
|
+
rerr.print(
|
506
|
+
f"[bold red][!] Error, binary exec type could not be verified:[/bold red] {args.binary}"
|
507
|
+
)
|
295
508
|
rerr.print(f"[yellow] {e} [/yellow]")
|
296
509
|
|
297
510
|
if args.upload:
|
@@ -302,11 +515,21 @@ def main() -> int:
|
|
302
515
|
|
303
516
|
# upload binary first, them carry out actions
|
304
517
|
if args.analyse:
|
305
|
-
api.RE_analyse(
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
518
|
+
api.RE_analyse(
|
519
|
+
args.binary,
|
520
|
+
model_name=api.re_conf["model"],
|
521
|
+
isa_options=args.isa,
|
522
|
+
platform_options=args.platform,
|
523
|
+
dynamic_execution=args.dynamic_execution,
|
524
|
+
command_line_args=args.cmd_line_args,
|
525
|
+
file_options=args.exec_format,
|
526
|
+
binary_scope=args.scope.upper(),
|
527
|
+
tags=tags,
|
528
|
+
priority=args.priority,
|
529
|
+
duplicate=args.duplicate,
|
530
|
+
debug_fpath=args.debug,
|
531
|
+
skip_scraping=args.do_not_auto_tag,
|
532
|
+
)
|
310
533
|
|
311
534
|
elif args.extract:
|
312
535
|
embeddings = api.RE_embeddings(args.binary).json()
|
@@ -321,27 +544,46 @@ def main() -> int:
|
|
321
544
|
"medium": 0.9,
|
322
545
|
"low": 0.7,
|
323
546
|
"partial": 0.5,
|
324
|
-
"all": 0.0
|
547
|
+
"all": 0.0,
|
325
548
|
}
|
326
549
|
if args.confidence in confidences.keys():
|
327
550
|
confidence = confidences[args.confidence]
|
328
551
|
|
329
552
|
if args.from_file:
|
330
|
-
if not os.path.isfile(args.from_file) and not os.access(
|
331
|
-
|
553
|
+
if not os.path.isfile(args.from_file) and not os.access(
|
554
|
+
args.from_file, os.R_OK
|
555
|
+
):
|
556
|
+
rerr.print(
|
557
|
+
"[bold red][!] Error, '--from-file' flag requires a path to a JSON embeddings file.[/bold red]"
|
558
|
+
)
|
332
559
|
return -1
|
333
|
-
rout.print(
|
560
|
+
rout.print(
|
561
|
+
f"[+] Searching for symbols similar to embedding in binary: {args.from_file}"
|
562
|
+
)
|
334
563
|
embeddings = json.load(open(args.from_file))
|
335
564
|
elif args.found_in:
|
336
|
-
if not os.path.isfile(args.found_in) and not os.access(
|
337
|
-
|
565
|
+
if not os.path.isfile(args.found_in) and not os.access(
|
566
|
+
args.found_in, os.R_OK
|
567
|
+
):
|
568
|
+
rerr.print(
|
569
|
+
"[bold red][!] Error, '--found-in' flag requires a path to a binary to search from.[/bold red]"
|
570
|
+
)
|
338
571
|
return -1
|
339
|
-
rout.print(
|
340
|
-
|
572
|
+
rout.print(
|
573
|
+
f"[+] Matching symbols between {args.binary} and {args.found_in}."
|
574
|
+
)
|
575
|
+
embeddings = api.RE_embeddings(args.found_in).json()["data"][
|
576
|
+
"embedding"
|
577
|
+
]
|
341
578
|
else:
|
342
579
|
return match_for_each(args.binary, confidence, args.nns)
|
343
580
|
|
344
|
-
match(
|
581
|
+
match(
|
582
|
+
args.binary,
|
583
|
+
embeddings,
|
584
|
+
confidence=confidence,
|
585
|
+
deviation=float(args.deviation),
|
586
|
+
)
|
345
587
|
|
346
588
|
elif args.logs:
|
347
589
|
api.RE_logs(args.binary)
|
@@ -354,6 +596,8 @@ def main() -> int:
|
|
354
596
|
|
355
597
|
elif args.cves:
|
356
598
|
api.RE_cves(args.binary)
|
599
|
+
elif args.details:
|
600
|
+
api.RE_binary_additonal_details(args.binary)
|
357
601
|
|
358
602
|
elif args.status:
|
359
603
|
api.RE_status(args.binary, console=True)
|