reait 1.1.0__py3-none-any.whl → 1.2.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/api.py CHANGED
@@ -10,12 +10,12 @@ import tomli
10
10
  from datetime import datetime
11
11
  from hashlib import sha256
12
12
  from lief import parse, Binary, ELF, PE, MachO
13
- from numpy import array, vstack, dot, arccos, pi
13
+ from numpy import array, vstack
14
14
  from pandas import DataFrame
15
15
  from requests import request, Response, HTTPError
16
16
  from sklearn.metrics.pairwise import cosine_similarity
17
17
 
18
- __version__ = "1.1.0"
18
+ __version__ = "1.2.0"
19
19
 
20
20
  re_conf = {
21
21
  "apikey": environ.get("REAI_API_KEY", ""),
@@ -32,7 +32,8 @@ class ReaitError(HTTPError):
32
32
 
33
33
  response.reason = reason
34
34
  response.status_code = 404
35
- response._content = b'{"success": false, "error": "' + reason.encode() + b'"}'
35
+ response._content = b'{"success": false, "error": "' + \
36
+ reason.encode() + b'"}'
36
37
  response.url = (
37
38
  f"{re_conf['host']}/{end_point if end_point[0] != '/' else end_point[1:]}"
38
39
  if end_point
@@ -243,6 +244,9 @@ def RE_analyse(
243
244
  symbols: dict = None,
244
245
  debug_fpath: str = None,
245
246
  skip_scraping: bool = False,
247
+ skip_capabilities: bool = False,
248
+ skip_sbom: bool = False,
249
+ advanced_analysis: bool = False
246
250
  ) -> Response:
247
251
  """
248
252
  Start analysis job for binary file
@@ -302,6 +306,9 @@ def RE_analyse(
302
306
  "priority",
303
307
  "symbols",
304
308
  "skip_scraping",
309
+ "skip_capabilities",
310
+ "skip_sbom",
311
+ "advanced_analysis"
305
312
  ):
306
313
  p_value = locals()[p_name]
307
314
 
@@ -315,7 +322,8 @@ def RE_analyse(
315
322
  )
316
323
  elif res.status_code == 400:
317
324
  if "error" in res.json().keys():
318
- logger.warning("Error analysing %s - %s", fpath, res.json()["error"])
325
+ logger.warning("Error analysing %s - %s",
326
+ fpath, res.json()["error"])
319
327
 
320
328
  res.raise_for_status()
321
329
  return res
@@ -330,7 +338,8 @@ def RE_upload(fpath: str) -> Response:
330
338
  result = re_hash_check(bin_id)
331
339
 
332
340
  if result:
333
- logger.info("File %s - %s already uploaded. Skipping upload...", fpath, bin_id)
341
+ logger.info(
342
+ "File %s - %s already uploaded. Skipping upload...", fpath, bin_id)
334
343
 
335
344
  res = Response()
336
345
  res.status_code = 200
@@ -346,7 +355,8 @@ def RE_upload(fpath: str) -> Response:
346
355
  )
347
356
  else:
348
357
  with open(fpath, "rb") as fd:
349
- res: Response = reveng_req(requests.post, "v1/upload", files={"file": fd})
358
+ res: Response = reveng_req(
359
+ requests.post, "v1/upload", files={"file": fd})
350
360
 
351
361
  if res.ok:
352
362
  logger.info(
@@ -354,7 +364,8 @@ def RE_upload(fpath: str) -> Response:
354
364
  )
355
365
  elif res.status_code == 400:
356
366
  if "error" in res.json().keys():
357
- logger.warning("Error uploading %s - %s", fpath, res.json()["error"])
367
+ logger.warning("Error uploading %s - %s",
368
+ fpath, res.json()["error"])
358
369
  elif res.status_code == 413:
359
370
  logger.warning("File too large. Please upload files under 10MB.")
360
371
  elif res.status_code == 500:
@@ -511,7 +522,8 @@ def RE_compute_distance(embedding: list, embeddings: list, nns: int = 5) -> list
511
522
  def RE_nearest_symbols_batch(
512
523
  function_ids: list[int],
513
524
  nns: int = 5,
514
- collections: list[str] = None,
525
+ collections: list[int] = None,
526
+ binaries: list[int] = None,
515
527
  distance: float = 0.1,
516
528
  debug_enabled: bool = False,
517
529
  ) -> Response:
@@ -531,10 +543,13 @@ def RE_nearest_symbols_batch(
531
543
  }
532
544
 
533
545
  if collections:
534
- # api param is collection, not collections
535
- params["collection"] = collections
546
+ params["collection_search_list"] = collections
547
+
548
+ if binaries:
549
+ params["binaries_search_list"] = binaries
536
550
 
537
- res: Response = reveng_req(requests.post, "v1/ann/symbol/batch", json_data=params)
551
+ res: Response = reveng_req(
552
+ requests.post, "v1/ann/symbol/batch", json_data=params)
538
553
 
539
554
  res.raise_for_status()
540
555
  return res
@@ -655,9 +670,11 @@ def RE_functions_rename(function_id: int, new_name: str) -> Response:
655
670
  )
656
671
 
657
672
  if res.ok:
658
- logger.info("FunctionId %d has been renamed with '%s'.", function_id, new_name)
673
+ logger.info("FunctionId %d has been renamed with '%s'.",
674
+ function_id, new_name)
659
675
  else:
660
- logger.warning("Error, cannot rename FunctionId %d. %s", function_id, res.text)
676
+ logger.warning("Error, cannot rename FunctionId %d. %s",
677
+ function_id, res.text)
661
678
 
662
679
  res.raise_for_status()
663
680
  return res
@@ -742,7 +759,9 @@ def RE_functions_list(
742
759
  params["max_v_address"] = max_v_address
743
760
 
744
761
  res: Response = reveng_req(
745
- requests.get, f"v2/analyses/{analysis_id}/info/functions/list", params=params
762
+ requests.get,
763
+ f"v2/analyses/{analysis_id}/info/functions/list",
764
+ params=params
746
765
  )
747
766
 
748
767
  res.raise_for_status()
@@ -755,7 +774,8 @@ def RE_function_callers_callees(function: int) -> Response:
755
774
  Get the callers and callees of a functions
756
775
  :param function: Function ID
757
776
  """
758
- res: Response = reveng_req(requests.get, f"v2/functions/{function}/callees_callers")
777
+ res: Response = reveng_req(
778
+ requests.get, f"v2/functions/{function}/callees_callers")
759
779
 
760
780
  res.raise_for_status()
761
781
  return res
@@ -766,7 +786,8 @@ def RE_analysis_info(analysis_id: int) -> Response:
766
786
  Get the analysis information
767
787
  :param analysis_id: Analysis ID
768
788
  """
769
- res: Response = reveng_req(requests.get, f"v2/analyses/{analysis_id}/info/basic")
789
+ res: Response = reveng_req(
790
+ requests.get, f"v2/analyses/{analysis_id}/info/basic")
770
791
 
771
792
  res.raise_for_status()
772
793
  return res
@@ -847,10 +868,12 @@ def _binary_format(binary: Binary) -> str:
847
868
  return "Mach-O"
848
869
 
849
870
  logger.error(
850
- "Error, could not determine or unsupported" f" binary format: {binary.format}."
871
+ "Error, could not determine or unsupported"
872
+ f" binary format: {binary.format}."
851
873
  )
852
874
  raise RuntimeError(
853
- "Error, could not determine or " f"unsupported binary format: {binary.format}"
875
+ "Error, could not determine or "
876
+ f"unsupported binary format: {binary.format}"
854
877
  )
855
878
 
856
879
 
@@ -914,12 +937,47 @@ def RE_analysis_id(fpath: str, binary_id: int = 0) -> Response:
914
937
  return res
915
938
 
916
939
 
917
- def RE_generate_data_types(analysis_id: int, function_ids: list[int]) -> Response:
940
+ def RE_functions_data_types(
941
+ function_ids: list[int],
942
+ ) -> Response:
943
+ """
944
+ Get data types for the functions
945
+ :param functions_ids: List of function IDs
946
+ :return: Response object
947
+ """
948
+ endpoint = "/v2/functions/data_types"
949
+ res: Response = reveng_req(
950
+ requests.post, endpoint, json_data={"function_ids": function_ids}
951
+ )
952
+ res.raise_for_status()
953
+ return res
954
+
955
+
956
+ def RE_functions_data_types_poll(
957
+ function_ids: list[int],
958
+ ) -> Response:
959
+ """
960
+ Poll data types for the functions
961
+ :param functions_ids: List of function IDs
962
+ :return: Response object
963
+ """
964
+ endpoint = "/v2/functions/data_types"
965
+ res: Response = reveng_req(
966
+ requests.get, endpoint, params={"function_ids": function_ids}
967
+ )
968
+ res.raise_for_status()
969
+ return res
970
+
971
+
972
+ def RE_generate_data_types(
973
+ analysis_id: int,
974
+ function_ids: list[int]
975
+ ) -> Response:
918
976
  """
919
977
  Generate data types for the analysis
920
978
  :param aid: Analysis ID
921
979
  """
922
- end_point = f"/v2/analyses/{analysis_id}/info/functions/data_types"
980
+ end_point = f"/v2/analyses/{analysis_id}/functions/data_types"
923
981
 
924
982
  res: Response = reveng_req(
925
983
  requests.post, end_point, json_data={"function_ids": function_ids}
@@ -928,13 +986,28 @@ def RE_generate_data_types(analysis_id: int, function_ids: list[int]) -> Respons
928
986
  return res
929
987
 
930
988
 
989
+ def RE_poll_data_types(
990
+ analysis_id: int,
991
+ function_id: int,
992
+ ) -> Response:
993
+ """
994
+ Poll data types for the analysis
995
+ :param aid: Analysis ID
996
+ """
997
+ end_point = f"/v2/analyses/{analysis_id}/functions/{function_id}/data_types"
998
+
999
+ res: Response = reveng_req(requests.get, end_point)
1000
+ res.raise_for_status()
1001
+ return res
1002
+
1003
+
931
1004
  def RE_list_data_types(analysis_id: int, function_ids: list[int]) -> Response:
932
1005
  """
933
1006
  List data types for the analysis
934
1007
  :param aid: Analysis ID
935
1008
  :param function_ids: List of function IDs
936
1009
  """
937
- end_point = f"/v2/analyses/{analysis_id}/info/functions/data_types"
1010
+ end_point = f"/v2/analyses/{analysis_id}/functions/data_types"
938
1011
 
939
1012
  res: Response = reveng_req(
940
1013
  requests.get, end_point, json_data={"function_ids": function_ids}
@@ -959,16 +1032,25 @@ def RE_begin_ai_decompilation(function_id: int) -> Response:
959
1032
  return res
960
1033
 
961
1034
 
962
- def RE_poll_ai_decompilation(function_id: int) -> Response:
1035
+ def RE_poll_ai_decompilation(
1036
+ function_id: int,
1037
+ summarise: bool = False
1038
+ ) -> Response:
963
1039
  """
964
1040
  Poll AI decompilation for the function
965
1041
  :param function_id: Function ID
966
1042
  """
967
1043
  end_point = f"/v2/functions/{function_id}/ai-decompilation"
968
1044
 
1045
+ params = {}
1046
+
1047
+ if summarise:
1048
+ params["summarise"] = summarise
1049
+
969
1050
  res: Response = reveng_req(
970
1051
  requests.get,
971
1052
  end_point,
1053
+ params=params,
972
1054
  )
973
1055
  res.raise_for_status()
974
1056
  return res
@@ -988,20 +1070,80 @@ def RE_analysis_lookup(binary_id: int) -> Response:
988
1070
  def RE_collections_search(
989
1071
  page: int = 1,
990
1072
  page_size: int = 10,
991
- partial_collection_name: str = "",
992
- partial_binary_name: str = "",
993
- partial_binary_sha256: str = "",
994
- tags: list[str] | str = "",
995
- model_name: str = "",
1073
+ query: dict = {},
996
1074
  ) -> Response:
997
1075
  """
1076
+ Search for collections in the database
998
1077
  """
999
1078
  end_point = "/v2/search/collections"
1000
- res: Response = reveng_req(requests.get, end_point, params={
1079
+ params = {
1001
1080
  "page": page,
1002
1081
  "page_size": page_size,
1003
- "partial_collection_name": partial_collection_name,
1004
- })
1082
+ }
1083
+
1084
+ # this api support:
1085
+ # partial_collection_name
1086
+ # partial_binary_name
1087
+ # partial_binary_sha256
1088
+ # model_name
1089
+ # tags
1090
+
1091
+ def exist_and_populated(key: str) -> bool:
1092
+ return key in query and query[key] is not None and len(query[key]) > 0
1093
+
1094
+ if exist_and_populated("collection_name"):
1095
+ params["partial_collection_name"] = query["collection_name"]
1096
+ elif exist_and_populated("binary_name"):
1097
+ params["partial_binary_name"] = query["binary_name"]
1098
+ elif exist_and_populated("sha_256_hash"):
1099
+ params["partial_binary_sha256"] = query["sha_256_hash"]
1100
+ elif exist_and_populated("tags"):
1101
+ params["tags"] = query["tags"]
1102
+ elif exist_and_populated("model_name"):
1103
+ params["model_name"] = query["model_name"]
1104
+ elif exist_and_populated("query"):
1105
+ params["partial_collection_name"] = query["query"]
1106
+
1107
+ res: Response = reveng_req(requests.get, end_point, params=params)
1108
+ res.raise_for_status()
1109
+ return res
1110
+
1111
+
1112
+ def RE_binaries_search(
1113
+ page: int = 1,
1114
+ page_size: int = 10,
1115
+ query: dict = {},
1116
+ ) -> Response:
1117
+ """
1118
+ Search for binaries in the database
1119
+ """
1120
+ end_point = "/v2/search/binaries"
1121
+ params = {
1122
+ "page": page,
1123
+ "page_size": page_size,
1124
+ }
1125
+
1126
+ # this api support:
1127
+ # partial_name
1128
+ # partial_sha256
1129
+ # tags
1130
+ # model_name
1131
+
1132
+ def exist_and_populated(key: str) -> bool:
1133
+ return key in query and query[key] is not None and len(query[key]) > 0
1134
+
1135
+ if exist_and_populated("binary_name"):
1136
+ params["partial_name"] = query["binary_name"]
1137
+ elif exist_and_populated("sha_256_hash"):
1138
+ params["partial_sha256"] = query["sha_256_hash"]
1139
+ elif exist_and_populated("tags"):
1140
+ params["tags"] = query["tags"]
1141
+ elif exist_and_populated("model_name"):
1142
+ params["model_name"] = query["model_name"]
1143
+ elif exist_and_populated("query"):
1144
+ params["partial_name"] = query["query"]
1145
+
1146
+ res: Response = reveng_req(requests.get, end_point, params=params)
1005
1147
  res.raise_for_status()
1006
1148
  return res
1007
1149
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reait
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: RevEng.AI Toolkit and Python API
5
5
  Home-page: https://github.com/RevEng-AI/reait
6
6
  Author: James Patrick-Evans
@@ -0,0 +1,9 @@
1
+ reait/__init__.py,sha256=EoVCKwQwWxEBfwe-iEE5rFKvhi1gPEA8NPhnzXJTb2Y,42
2
+ reait/api.py,sha256=OzRPRgXAfOUmdPWx7b7_CwKfZ6OoT1VK07VYTSmWnB4,36646
3
+ reait/main.py,sha256=rSzEowDrK2KFmmLdbRNVsfVpvMLZNXA3fQOrBw03T4Y,20396
4
+ reait-1.2.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
5
+ reait-1.2.0.dist-info/METADATA,sha256=AQusdz1uqsRJ1qdlnlV10OlEKGlaR0n-L5vk1pt8_u4,47663
6
+ reait-1.2.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
7
+ reait-1.2.0.dist-info/entry_points.txt,sha256=8Ek11o7a6O8hjBFw6-1vmkBfbv_45O2vOKj5CDUB1e4,42
8
+ reait-1.2.0.dist-info/top_level.txt,sha256=EnJssmctKe3Ugjcmu66L9_Q4elLdAwaXK6M8E6E8f_M,6
9
+ reait-1.2.0.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- reait/__init__.py,sha256=EoVCKwQwWxEBfwe-iEE5rFKvhi1gPEA8NPhnzXJTb2Y,42
2
- reait/api.py,sha256=gYF4K9fns47bkIUu9_ZV1glRBqEP-J1OaIn99prRugE,33128
3
- reait/main.py,sha256=rSzEowDrK2KFmmLdbRNVsfVpvMLZNXA3fQOrBw03T4Y,20396
4
- reait-1.1.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
5
- reait-1.1.0.dist-info/METADATA,sha256=ULUT4H4-BSwIOVl9_cn51PwU7D_2U7qnlgT6nWAEjG0,47663
6
- reait-1.1.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
7
- reait-1.1.0.dist-info/entry_points.txt,sha256=8Ek11o7a6O8hjBFw6-1vmkBfbv_45O2vOKj5CDUB1e4,42
8
- reait-1.1.0.dist-info/top_level.txt,sha256=EnJssmctKe3Ugjcmu66L9_Q4elLdAwaXK6M8E6E8f_M,6
9
- reait-1.1.0.dist-info/RECORD,,
File without changes