6
\$\begingroup\$

I am utilizing an API module for interacting with virustotal.com in order to get AntiVirus results based of SHA256 hashes. The code I have is working but I feel like it can be improved greatly. I think that I am brute forcing my way to some of the text fields I am looking for. Any suggestions on optimization would be greatly appreciated.

Python Code:

import csv
import time

def virustotal(hashvalue):
    from virus_total_apis import PublicApi as VirusTotalPublicApi

    API_KEY = 'deadbeef12345facefaceface555555555555555555555555555555555555555'
    vt = VirusTotalPublicApi(API_KEY)
    response = vt.get_file_report(hashvalue)
    return response

with open('C://SHA256.csv') as csvfile:
    readCSV = csv.reader(csvfile, delimiter=',')
    for row in readCSV:
        tempString = str(row)
        tempIndex = tempString.index(',')
        filename = tempString[2:tempIndex-1]
        filehash = tempString[tempIndex+3:-2]
        results = str(virustotal(filehash))
        try:
            tempposit1 = results.index('positives')
            tempposit2 = results.index(',', tempposit1)
            positive = results[tempposit1 + 11:tempposit2]
            temptotal = results.index("'total':")
            temptotal2 = results.index(',', temptotal)
            total = results[temptotal+8:temptotal2]
            finalresults = positive.strip() + "/" + total.strip()
        except ValueError:
            finalresults = "Not_Found"
        print(filename + "," + filehash + "," + finalresults)
        time.sleep(15) #needed delay due to API restrictions

SHA256.csv - example (input data that is being read)

hplgtv_enxml.dll,DDBC281FFE95DDCBE1CC67DF475BC4D553C27306CF978108DE4B6E6ECCF87B69
nsi.dll,732F77DC897A423AFC2A7502D2E103829A3960656A103A2243B52A7F00A40556
hplgtv_timages.dll,DF00AB06ACE714D31C9B592798C3359174198C0D0FB022889F2736F28F7E17C2

Results for hplgtv_enxml.dll from Virustotal.com:

{
  "response_code": 200,
  "results": {
    "scan_id": "ddbc281ffe95ddcbe1cc67df475bc4d553c27306cf978108de4b6e6eccf87b69-1284841383",
    "verbose_msg": "Scan finished, information embedded",
    "sha1": "4b57042dd08dbca1de775f56dc8ff3939e6dc1e2",
    "total": 43,
    "positives": 0,
    "sha256": "ddbc281ffe95ddcbe1cc67df475bc4d553c27306cf978108de4b6e6eccf87b69",
    "scan_date": "2010-09-18 20:23:03",
    "resource": "DDBC281FFE95DDCBE1CC67DF475BC4D553C27306CF978108DE4B6E6ECCF87B69",
    "permalink": "https://www.virustotal.com/file/ddbc281ffe95ddcbe1cc67df475bc4d553c27306cf978108de4b6e6eccf87b69/analysis/1284841383/",
    "scans": {
      "AhnLab-V3": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "2010.09.19.00"
      },
      "eTrust-Vet": {
        "result": "None",
        "detected": false,
        "update": "20100917",
        "version": "36.1.7862"
      },
      "nProtect": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "2010-09-18.01"
      },
      "AntiVir": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "8.2.4.58"
      },
      "Norman": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "6.06.06"
      },
      "TrendMicro-HouseCall": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "9.120.0.1004"
      },
      "Sophos": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "4.57.0"
      },
      "McAfee-GW-Edition": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "2010.1C"
      },
      "PCTools": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "7.0.3.5"
      },
      "F-Secure": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "9.0.15370.0"
      },
      "GData": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "21"
      },
      "Authentium": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "5.2.0.5"
      },
      "CAT-QuickHeal": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "11.00"
      },
      "Prevx": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "3.0"
      },
      "Microsoft": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "1.6201"
      },
      "Jiangmin": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "13.0.900"
      },
      "McAfee": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "5.400.0.1158"
      },
      "ClamAV": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "0.96.2.0-git"
      },
      "DrWeb": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "5.0.2.03300"
      },
      "ViRobot": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "2010.9.18.4048"
      },
      "Rising": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "22.65.05.00"
      },
      "Sunbelt": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "6894"
      },
      "TheHacker": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "6.7.0.0.023"
      },
      "AVG": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "9.0.0.851"
      },
      "VirusBuster": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "12.65.13.0"
      },
      "Antiy-AVL": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "2.0.3.7"
      },
      "K7AntiVirus": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "9.63.2552"
      },
      "Comodo": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "6121"
      },
      "Fortinet": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "4.1.143.0"
      },
      "BitDefender": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "7.2"
      },
      "Symantec": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "20101.1.1.7"
      },
      "Avast": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "4.8.1351.0"
      },
      "SUPERAntiSpyware": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "4.40.0.1006"
      },
      "Avast5": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "5.0.594.0"
      },
      "eSafe": {
        "result": "None",
        "detected": false,
        "update": "20100917",
        "version": "7.0.17.0"
      },
      "F-Prot": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "4.6.1.107"
      },
      "Emsisoft": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "5.0.0.37"
      },
      "Ikarus": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "T3.1.1.88.0"
      },
      "Panda": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "10.0.2.7"
      },
      "TrendMicro": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "9.120.0.1004"
      },
      "Kaspersky": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "7.0.0.125"
      },
      "NOD32": {
        "result": "None",
        "detected": false,
        "update": "20100918",
        "version": "5460"
      },
      "VBA32": {
        "result": "None",
        "detected": false,
        "update": "20100917",
        "version": "3.12.14.0"
      }
    },
    "md5": "c5de5387228d0d71152d62a9fd1b7a66",
    "response_code": 1
  }
}
\$\endgroup\$
3
\$\begingroup\$

I think that I am brute forcing my way to some of the text fields I am looking for.

Indeed.

csv.reader()

Each row returned by csv.reader(0) is a list of strings. So your line

    tempString = str(row)

is undoing the work csv did for you (which is the entire reason for using csv). Instead, you should do this:

    readCSV = csv.reader(csvfile, delimiter=',')
    for row in readCSV:
        filename = row[0]
        filehash = row[1]

Use the dict returned by vt.get_file_report()

Edit: my original response directed the OP to use json library to parse JSON-formatted text. That was incorrect, as the returned data was already parsed by json library.

The response returned from your virustotal() function is a dict of the key-value data shown in your "Results for hplgtv_enxml.dll from Virustotal.com" section.

Thus, you just need to access the appropriate key of the dict (specifically, the keys in the results dict of the returned data). To access the "positives" and "total" fields you were looking for, they are under the "results" key:

        results = virustotal(filehash)
        positive = results['results']['positives']
        total = results['results']['total']

Because everything you want is under the "results" subdictionary, I would just reference it (['results']) at the end of the virustotal() call).

Here are the combined suggested modifications (using the list that csv.reader() returns, and using json.loads()):

    for row in readCSV:
        filename = row[0]
        filehash = row[1]
        try:
            results = virustotal(filehash)['results']
            positive = results['positives']
            total = results['total']
            finalresults = "{}/{}".format(positive, total)
        except ValueError:
            finalresults = "Not_Found"
        print "{},{},{}".format(filename, filehash, finalresults)
\$\endgroup\$
  • \$\begingroup\$ Hi scottbb, I am utilizing your suggestions, but getting json error: Traceback (most recent call last): File "C:/vtscript.py", line 19, in <module> results = json.loads(virustotal(filehash))['results'] File "C:\Python35-32\lib\json_init_.py", line 312, in loads s.__class__.__name__)) TypeError: the JSON object must be str, not 'dict' \$\endgroup\$ – evilmonkey2148 Aug 3 '16 at 20:29
  • \$\begingroup\$ My apologies. I didn't use the virus_total_apis library that you included. I made the invalid assumption that vt.get_file_report() returned JSON-formatted text. It returns the parsed dict of the JSON. So you don't even need the json library. Instead, just use results = virustotal(filehash)['results']. \$\endgroup\$ – scottbb Aug 3 '16 at 20:45
  • 1
    \$\begingroup\$ You could utilize format syntax further: finalresults = "{positives}/{total}".format(**virustotal(filehash)['results']) \$\endgroup\$ – Graipher Aug 4 '16 at 10:02
1
\$\begingroup\$

Simplifying @scottbb's answer even further:

You could use tuple unpacking to read the filename and filehash and make use of formats syntax to use a dictionary for its values:

for row in readCSV:
    filename, filehash = row
    try:
        results = virustotal(filehash)['results']
        finalresults = "{positives}/{total}".format(**results)
    except ValueError:
        finalresults = "Not_Found"
    print "{},{},{}".format(filename, filehash, finalresults)

Or:

for row in readCSV:
    try:
        results = virustotal(row[1])['results']
        finalresults = "{positives}/{total}".format(**results)
    except ValueError:
        finalresults = "Not_Found"
    print "{},{},{result}".format(*row, result=finalresults)

Or:

    print "{1},{2},{0}".format(finalresults, *row)
\$\endgroup\$
  • \$\begingroup\$ I had never really considered using tuple unpacking with format(), but it makes perfect sense. Nice! \$\endgroup\$ – scottbb Aug 4 '16 at 11:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.