Skip to content

Commit 5623be1

Browse files
author
martijn
committed
Bug fixes and other improvements
1 parent 9e4cf2a commit 5623be1

File tree

1 file changed

+170
-24
lines changed

1 file changed

+170
-24
lines changed

Diff for: dxltieclient/client.py

+170-24
Original file line numberDiff line numberDiff line change
@@ -341,29 +341,96 @@ def get_file_info(self, hashes):
341341
342342
.. code-block:: python
343343
344-
# Determine reputations for file (identified by hashes)
344+
# Retrieve information for file (identified by hashes)
345345
file_info_dict = \\
346346
tie_client.get_file_info({
347347
HashType.MD5: "f2c7bb8acc97f92e987a2d4087d021b1",
348348
HashType.SHA1: "7eb0139d2175739b3ccb0d1110067820be6abd29",
349349
HashType.SHA256: "142e1d688ef0568370c37187fd9f2351d7ddeda574f8bfa9b0fa4ef42db85aa2"
350350
})
351351
352-
Sample output + info
352+
**File**
353+
354+
The file that matches one of the hashes is returned as a Python ``dictionary``.
355+
356+
An example ``list`` is shown below:
357+
358+
.. code-block:: python
359+
{
360+
"atdReputation": null,
361+
"atdReputationLastRefresh": null,
362+
"badRepCount": null,
363+
"certEnterpriseReputation": 0,
364+
"certGtiReputation": 99,
365+
"certSha1": "49da9a5e21edc4682ad0211c85d552c86c422f13",
366+
"comment": null,
367+
"company": null,
368+
"compositeReputation": " 099|2",
369+
"ctdReputation": null,
370+
"ctdReputationLastRefresh": null,
371+
"detectionCount": null,
372+
"enterpriseCount": 1,
373+
"enterpriseReputation": null,
374+
"enterpriseReputationLastRefresh": null,
375+
"fileNameCount": null,
376+
"fileParents": null,
377+
"filePathCount": null,
378+
"filePaths": null,
379+
"fileRules": null,
380+
"fileType": 16,
381+
"firstContact": "2016-12-13 15:50:43",
382+
"firstReference": null,
383+
"goodRepCount": null,
384+
"gtiReputation": null,
385+
"gtiReputationLastRefresh": null,
386+
"lastAccess": "2017-01-23 15:09:24",
387+
"lastDetectionName": null,
388+
"lastUpdate": null,
389+
"latestRuleId": null,
390+
"localRepCount": null,
391+
"localRepLatest": null,
392+
"localRepMax": null,
393+
"localRepMin": null,
394+
"localRepSum": null,
395+
"md5": "b32189bdff6e577a92baa61ad49264e6",
396+
"mwgReputation": null,
397+
"mwgReputationLastRefresh": null,
398+
"names": [
399+
"NOTEPAD.EXE"
400+
],
401+
"parentRepCount": null,
402+
"parentRepMax": null,
403+
"parentRepMin": null,
404+
"parentRepSum": null,
405+
"prevalent": false,
406+
"productName": null,
407+
"productVersion": null,
408+
"profilerFlags": "",
409+
"promptRepCount": null,
410+
"promptRepMax": null,
411+
"promptRepMin": null,
412+
"promptRepSum": null,
413+
"sha1": "a7bbc4b4f781e04214ecebe69a766c76681aa7eb",
414+
"sha256": "933e1778b2760b3a9194c2799d7b76052895959c3caedefb4e9d764cbb6ad3b5",
415+
"signedBits": null,
416+
"size": null,
417+
"urlRep": null,
418+
"version": null
419+
}
353420
354421
:param hashes: A ``dict`` (dictionary) of hashes that identify the file to retrieve the info for.
355422
The ``key`` in the dictionary is the `hash type` and the ``value`` is the `hex` representation of the
356423
hash value. See the :class:`dxltieclient.constants.HashType` class for the list of `hash type`
357424
constants.
358-
:return:
425+
:return: a file info dict
359426
"""
360427
# Create the request message
361428
req = Request(TIE_GET_FILE_INFO_TOPIC)
362429

363430
# Create a dictionary for the payload
364431
payload_dict = {"hashes": []}
365432

366-
# This topic needs an extra list layer
433+
# This topic needs an extra list layer in the payload
367434
payload_dict["hashes"].append([])
368435

369436
for key, value in hashes.items():
@@ -378,8 +445,10 @@ def get_file_info(self, hashes):
378445
resp_dict = json.loads(response.payload.decode(encoding="UTF-8"))
379446

380447
# Transform reputations to be simpler to use
381-
if len(resp_dict) > 0:
382-
return TieClient._transform_file_info(resp_dict)
448+
if "results" in resp_dict and len(resp_dict["results"]) > 0:
449+
file_info = resp_dict["results"][0]
450+
TieClient._transform_file_info(file_info)
451+
return file_info
383452
else:
384453
return {}
385454

@@ -391,18 +460,87 @@ def search_files(self, search_string, query_limit=500):
391460
392461
.. code-block:: python
393462
394-
# Determine reputations for file (identified by hashes)
463+
# Retrieve information for files (identified by (a part of) its name)
395464
file_search_dict = \\
396465
tie_client.search_files(
397466
"bad_file.exe",
398467
100
399468
)
400469
401-
Sample output + info
470+
**Files**
471+
472+
The files that match the search string are returned as a Python ``list``.
473+
474+
An example ``list`` is shown below:
475+
476+
.. code-block:: python
477+
[
478+
{
479+
"atdReputation": null,
480+
"atdReputationLastRefresh": null,
481+
"badRepCount": null,
482+
"certEnterpriseReputation": 0,
483+
"certGtiReputation": 99,
484+
"certSha1": "49da9a5e21edc4682ad0211c85d552c86c422f13",
485+
"comment": null,
486+
"company": null,
487+
"compositeReputation": " 099|2",
488+
"ctdReputation": null,
489+
"ctdReputationLastRefresh": null,
490+
"detectionCount": null,
491+
"enterpriseCount": 1,
492+
"enterpriseReputation": null,
493+
"enterpriseReputationLastRefresh": null,
494+
"fileNameCount": null,
495+
"fileParents": null,
496+
"filePathCount": null,
497+
"filePaths": null,
498+
"fileRules": null,
499+
"fileType": 16,
500+
"firstContact": "2016-12-13 15:50:43",
501+
"firstReference": null,
502+
"goodRepCount": null,
503+
"gtiReputation": null,
504+
"gtiReputationLastRefresh": null,
505+
"lastAccess": "2017-01-23 15:09:24",
506+
"lastDetectionName": null,
507+
"lastUpdate": null,
508+
"latestRuleId": null,
509+
"localRepCount": null,
510+
"localRepLatest": null,
511+
"localRepMax": null,
512+
"localRepMin": null,
513+
"localRepSum": null,
514+
"md5": "b32189bdff6e577a92baa61ad49264e6",
515+
"mwgReputation": null,
516+
"mwgReputationLastRefresh": null,
517+
"names": [
518+
"NOTEPAD.EXE"
519+
],
520+
"parentRepCount": null,
521+
"parentRepMax": null,
522+
"parentRepMin": null,
523+
"parentRepSum": null,
524+
"prevalent": false,
525+
"productName": null,
526+
"productVersion": null,
527+
"profilerFlags": "",
528+
"promptRepCount": null,
529+
"promptRepMax": null,
530+
"promptRepMin": null,
531+
"promptRepSum": null,
532+
"sha1": "a7bbc4b4f781e04214ecebe69a766c76681aa7eb",
533+
"sha256": "933e1778b2760b3a9194c2799d7b76052895959c3caedefb4e9d764cbb6ad3b5",
534+
"signedBits": null,
535+
"size": null,
536+
"urlRep": null,
537+
"version": null
538+
}
539+
]
402540
403541
:param search_string: A ``string`` that contains a (part of) the filename to search for
404542
:param query_limit: The maximum number of results to return
405-
:return:
543+
:return: a list of file info dicts
406544
"""
407545
# Create the request message
408546
req = Request(TIE_SEARCH_FILE_BY_NAME)
@@ -419,9 +557,11 @@ def search_files(self, search_string, query_limit=500):
419557
resp_dict = json.loads(response.payload.decode(encoding="UTF-8"))
420558

421559
if "results" in resp_dict:
422-
return TieClient._transform_reputations(resp_dict["results"])
560+
file_infos = resp_dict["results"]
561+
TieClient._transform_file_infos(file_infos)
562+
return file_infos
423563
else:
424-
return {}
564+
return []
425565

426566
def get_file_first_references(self, hashes, query_limit=500):
427567
"""
@@ -834,10 +974,9 @@ def _transform_reputations(reputations):
834974
@staticmethod
835975
def _transform_file_infos(file_infos):
836976
"""
837-
Transforms a dictionary of file info objects from the standard TIE format to a simplified
977+
Transforms a list of file info objects from the standard TIE format to a simplified
838978
form (hex vs base64 hashes, timestamps, etc.)
839-
:param file_infos: The dictionary of file info objects in the standard TIE format
840-
:return: A dictionary file info objects in a simplified form
979+
:param file_infos: The list of file info objects in the standard TIE format
841980
"""
842981
for file_info in file_infos:
843982
TieClient._transform_file_info(file_info)
@@ -848,22 +987,29 @@ def _transform_file_info(file_info):
848987
Transforms a file info object from the standard TIE format to a simplified
849988
form (hex vs base64 hashes, timestamps, etc.)
850989
:param file_info: File info in the standard TIE format
851-
:return: The file info in a simplified form
852990
"""
853991
# Transform hash values to readable
854-
file_info[HashType.MD5] = TieClient._base64_to_hex(file_info[HashType.MD5])
855-
file_info[HashType.SHA256] = TieClient._base64_to_hex(file_info[HashType.SHA256])
856-
file_info[HashType.SHA1] = TieClient._base64_to_hex(file_info[HashType.SHA1])
992+
hash_fields = [HashType.MD5, HashType.SHA256, HashType.SHA1, "certSha1"]
857993

858-
# Transform Unix timestamp to readable
859-
file_info["firstContact"] = TieClient._transform_unix_to_datetime(file_info["firstContact"])
860-
file_info["lastAccess"] = TieClient._transform_unix_to_datetime(file_info["lastAccess"])
994+
for hash_field in hash_fields:
995+
file_info[hash_field] = TieClient._base64_to_hex(file_info[hash_field])
996+
997+
# Transform Unix timestamp to human readable
998+
timestamp_fields = ["firstContact", "lastAccess", "firstReference", "lastUpdate", "enterpriseReputationLastRefresh",
999+
"mwgReputationLastRefresh", "gtiReputationLastRefresh", "atdReputationLastRefresh",
1000+
"ctdReputationLastRefresh"]
1001+
1002+
for timestamp_field in timestamp_fields:
1003+
file_info[timestamp_field] = TieClient._transform_unix_to_datetime(file_info[timestamp_field])
8611004

8621005
@staticmethod
8631006
def _transform_unix_to_datetime(unix_timestamp):
8641007
"""
865-
Transforms a unix timestamp into a python datetime object
1008+
Transforms a unix timestamp into a human readable string
8661009
:param unix_timestamp: The dictionary of reputation in the standard TIE format
867-
:return: The timestamp as a python datetime object
1010+
:return: The timestamp as a string
8681011
"""
869-
return datetime.fromtimestamp(int(str(unix_timestamp)[:-3])).strftime('%Y-%m-%d %H:%M:%S')
1012+
if unix_timestamp is not None:
1013+
return datetime.fromtimestamp(unix_timestamp/1000).strftime('%Y-%m-%d %H:%M:%S')
1014+
else:
1015+
return None

0 commit comments

Comments
 (0)