reait 1.0.0__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/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 typing import Optional
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 os
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 glob import iglob
18
- import numpy as np
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
- Display program version
27
+ Display program version
29
28
  """
30
- rout.print(f"""[bold blue] :::::::: ::::::::
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(fpath: str, embeddings: list, confidence: float = 0.95, deviation: float = 0.1) -> None:
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(f"Matching symbols from '{fpath}' with a confidence {confidence:.02f} and up to "
105
- f"{nns} result{'' if nns == 1 else 's'} per function")
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(fpath, nns=nns, distance=1 - confidence).json()["function_matches"]
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(f"[bold red]No matches found for a confidence of [/bold red] {confidence:.02f}")
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(filter(lambda x: function["function_id"] == x["origin_function_id"], function_matches))
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(f"[bold green]Found {len(matches)} match{'' if len(matches) == 1 else 'es'} for "
118
- f"[/bold green][blue]{function['function_name']}: {function['function_vaddr']:#x}[/blue]")
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(f"\t[yellow]Confidence: {match['confidence']:.05f}[/yellow]"
122
- f"\t[blue]{match['nearest_neighbor_function_name']}"
123
- f" ({match['nearest_neighbor_binary_name']})[/blue]")
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(f"[bold red]No matches found for[/bold red] "
126
- f"[blue]{function['function_name']}: {function['function_vaddr']:#x}[/blue]")
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("-b", "--binary", type=validate_file,
167
- help="Path of binary to analyse, use ./path:{exec_format} to specify executable format e.g. ./path:raw-x86_64")
168
- parser.add_argument("-B", "--binary-hash", default="", help="Hex-encoded SHA-256 hash of the binary to use")
169
- parser.add_argument("-D", "--dir", type=validate_dir, help="Path of directory to recursively analyse")
170
- parser.add_argument("-a", "--analyse", action="store_true",
171
- help="Perform a full analysis and generate embeddings for every symbol")
172
- parser.add_argument("--base-address", help="Image base of the executable image to map for remote analysis")
173
- parser.add_argument("-A", action="store_true", help="Upload and Analyse a new binary")
174
- parser.add_argument("-u", "--upload", action="store_true", help="Upload a new binary to remote server")
175
- parser.add_argument("--duplicate", default=False, action="store_true", help="Duplicate an existing binary")
176
- parser.add_argument("-e", "--embedding", help="Path of JSON file containing a BinNet embedding")
177
- parser.add_argument("--nns", default="5", help="Number of approximate nearest neighbors to fetch", type=int)
178
- parser.add_argument("--collections", default=None,
179
- help="Comma Seperated Value of collections to search from e.g. libxml2,libpcap. Used to select RevEng.AI collections for filtering search results")
180
- parser.add_argument("--found-in", help="ANN flag to limit to embeddings returned to those found in specific binary")
181
- parser.add_argument("--from-file",
182
- help="ANN flag to limit to embeddings returned to those found in JSON embeddings file")
183
- parser.add_argument("-c", "--cves", action="store_true", help="Check for CVEs found inside binary")
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("-m", "--model", default=None, help="AI model used to generate embeddings")
186
- parser.add_argument("-x", "--extract", action="store_true", help="Fetch embeddings for binary")
187
- parser.add_argument("-M", "--match", action="store_true",
188
- help="Match functions in binary file. Can be used with --confidence, --deviation, --from-file, --found-in.")
189
- parser.add_argument("--confidence", default="high", choices=["high", "medium", "low", "partial", "all"],
190
- help="Confidence threshold used to match symbols. Valid values are 'all', 'medium', 'low', 'partial' or 'high'[DEFAULT]")
191
- parser.add_argument("--deviation", default=0.1, type=float,
192
- help="Deviation in prediction confidence between outlier and next highest symbol. Use if confident symbol is present in binary but not matching.")
193
- parser.add_argument("-l", "--logs", action="store_true", help="Fetch analysis log file for binary")
194
- parser.add_argument("-d", "--delete", action="store_true", help="Delete all metadata associated with binary")
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("-v", "--version", action="store_true", help="Display version information")
198
- parser.add_argument("--help", action="help", default=argparse.SUPPRESS,
199
- help=argparse._("Show this help message and exit"))
200
- parser.add_argument("--isa", default=None, help="Override executable ISA. Valid values are x86, x86_64, ARMv7")
201
- parser.add_argument("--exec-format", default=None,
202
- help="Override executable format. Valid values are pe, elf, macho, raw")
203
- parser.add_argument("--platform", default=None,
204
- help="Override OS platform. Valid values are Windows, Linux, OSX, OpenBSD")
205
- parser.add_argument("--dynamic-execution", default=False, action="store_true",
206
- help="Enable dynamic execution in sandbox during analysis. Analysis will include any auto unpacked malware samples")
207
- parser.add_argument("--cmd-line-args", default="",
208
- help="Command line arguments to pass when running binary sample in the sandbox. Only used when run with --dynamic-execution")
209
- parser.add_argument("--scope", default="private", choices=["public", "private"],
210
- help="Override analysis visibility (scope). Valid values are 'public' or 'private'[DEFAULT]")
211
- parser.add_argument("--tags", default=None, type=str,
212
- help="Assign tags to an analysis. Valid responses are tag1,tag2,tag3.")
213
- parser.add_argument("--priority", default=0, type=int, help="Add priority to processing queue.")
214
- parser.add_argument("--verbose", default=False, action="store_true", help="Set verbose output.")
215
- parser.add_argument("--debug", default=None, help="Debug file path to write pass with analysis")
216
- parser.add_argument("-s", "--status", action="store_true", help="Ongoing status of the provided binary")
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 ("apikey", "host", "model",):
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
- ## perform operation on all files inside directory
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(f"[red bold][!] Error, binary exec type could not be verified:[/red bold] {file}")
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(file, model_name=api.re_conf["model"], isa_options=args.isa,
266
- platform_options=args.platform, dynamic_execution=args.dynamic_execution,
267
- command_line_args=args.cmd_line_args, file_options=args.exec_format,
268
- binary_scope=args.scope.upper(), tags=tags, priority=args.priority,
269
- duplicate=args.duplicate, debug_fpath=args.debug)
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(f"[green bold]Deleting analyses for:[/green bold] {file}")
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(f"[red bold][!] Error, could not delete analysis for:[/red bold] {file}")
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(f"Error, '-D' flag only supports upload, analyse, or delete.")
477
+ rerr.print(
478
+ f"Error, '-D' flag only supports upload, analyse, or delete."
479
+ )
281
480
  return -1
282
- elif args.analyse or args.extract or args.logs or args.delete or \
283
- args.upload or args.match or args.cves or args.sbom or args.status:
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("[bold red][!] Error, please supply a valid binary file using '-b' flag.[/bold red]")
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(f"[bold red][!] Error, binary exec type could not be verified:[/bold red] {args.binary}")
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(args.binary, model_name=api.re_conf["model"], isa_options=args.isa,
306
- platform_options=args.platform, dynamic_execution=args.dynamic_execution,
307
- command_line_args=args.cmd_line_args, file_options=args.exec_format,
308
- binary_scope=args.scope.upper(), tags=tags, priority=args.priority,
309
- duplicate=args.duplicate, debug_fpath=args.debug)
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(args.from_file, os.R_OK):
331
- rerr.print("[bold red][!] Error, '--from-file' flag requires a path to a JSON embeddings file.[/bold red]")
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(f"[+] Searching for symbols similar to embedding in binary: {args.from_file}")
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(args.found_in, os.R_OK):
337
- rerr.print("[bold red][!] Error, '--found-in' flag requires a path to a binary to search from.[/bold red]")
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(f"[+] Matching symbols between {args.binary} and {args.found_in}.")
340
- embeddings = api.RE_embeddings(args.found_in).json()["data"]["embedding"]
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(args.binary, embeddings, confidence=confidence, deviation=float(args.deviation))
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)