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 +172 -30
- {reait-1.1.0.dist-info → reait-1.2.0.dist-info}/METADATA +1 -1
- reait-1.2.0.dist-info/RECORD +9 -0
- reait-1.1.0.dist-info/RECORD +0 -9
- {reait-1.1.0.dist-info → reait-1.2.0.dist-info}/WHEEL +0 -0
- {reait-1.1.0.dist-info → reait-1.2.0.dist-info}/entry_points.txt +0 -0
- {reait-1.1.0.dist-info → reait-1.2.0.dist-info}/licenses/LICENSE +0 -0
- {reait-1.1.0.dist-info → reait-1.2.0.dist-info}/top_level.txt +0 -0
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
|
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.
|
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": "' +
|
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",
|
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(
|
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(
|
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",
|
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[
|
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
|
-
|
535
|
-
|
546
|
+
params["collection_search_list"] = collections
|
547
|
+
|
548
|
+
if binaries:
|
549
|
+
params["binaries_search_list"] = binaries
|
536
550
|
|
537
|
-
res: Response = reveng_req(
|
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'.",
|
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",
|
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,
|
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(
|
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(
|
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"
|
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 "
|
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
|
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}/
|
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}/
|
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(
|
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
|
-
|
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
|
-
|
1079
|
+
params = {
|
1001
1080
|
"page": page,
|
1002
1081
|
"page_size": page_size,
|
1003
|
-
|
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
|
|
@@ -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,,
|
reait-1.1.0.dist-info/RECORD
DELETED
@@ -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
|
File without changes
|
File without changes
|
File without changes
|