Ты наверняка не раз пользовался услугами сайта virustotal.com, чтобы проверить, не содержат ли бинарники вредоносных функций, либо протестировать собственные наработки. У этого сервиса есть бесплатный API, работу с которым на Python мы и разберем в этой статье.
Сайт virustotal.com
Сайт virustotal.com

Чтобы пользоваться программными интерфейсами VirusTotal без ограничений, нужно получить ключ, который обходится в серьезную сумму — цены начинаются с 700 евро в месяц. Причем частному лицу даже при готовности платить ключ не дадут.

Однако отчаиваться не стоит, поскольку основные функции сервис предоставляет бесплатно и ограничивает нас лишь по числу запросов — не более двух в минуту. Что ж, придется с этим мириться.

WARNING

API VirusTotal нельзя использовать в коммерческих продуктах или услугах и в проектах, которые могут нанести прямой либо косвенный ущерб антивирусной индустрии.

 

Получаем API Key

Итак, первым делом нам нужна регистрация на сайте. Тут проблем никаких — я уверен, что ты справишься. После регистрации берем ключ доступа, перейдя в пункт меню API key.

Вот здесь лежит ключ доступа к API VirusTotal
Вот здесь лежит ключ доступа к API VirusTotal
 

Версии API

Сейчас актуальная версия API имеет номер 2. Но при этом уже существует и новый вариант — номер 3. Эта версия API пока еще находится в стадии беты, но ее уже вполне можно использовать, тем более что возможности, которые она предоставляет, гораздо шире.

Разработчики пока что рекомендуют применять третью версию только для экспериментов либо для некритичных проектов. Мы же разберем обе версии. Ключ доступа для них одинаков.

 

API VirusTotal. Версия 2

Как и в случае с другими популярными веб-сервисами, работа с API заключается в пересылке запросов по HTTP и получении ответов.

API второй версии позволяет:

  • отправлять файлы на проверку;
  • получать отчет по проверенным ранее файлам, с использованием идентификатора файла (хеш файла SHA-256, SHA-1 или MD5 либо значение scan_id из ответа, полученного после отправки файла);
  • отправлять URL для сканирования на сервер;
  • получать отчет по проверенным ранее адресам с использованием либо непосредственно URL, либо значения scan_id из ответа, полученного после отправки URL на сервер;
  • получать отчет по IP-адресу;
  • получать отчет по доменному имени.

Ошибки

Если запрос был правильно обработан и ошибок не возникло, будет возвращен код 200 (OK).

Если же произошла ошибка, то могут быть такие варианты:

  • 204 — ошибка типа Request rate limit exceeded. Возникает, когда превышена квота допустимого количества запросов (для бесплатного ключа квота составляет четыре запроса в минуту);
  • 400 — ошибка типа Bad request. Возникает, когда некорректно сформирован запрос, например если нет нужных аргументов или у них недопустимые значения;
  • 403 — ошибка типа Forbidden. Возникает, если пытаться использовать функции API, доступные только с платным ключом, когда его нет.

При правильном формировании запроса (код состояния HTTP — 200) ответ будет представлять собой объект JSON, в теле которого присутствуют как минимум два поля:

  • response_code — если запрашиваемый объект (файл, URL, IP-адрес или имя домена) есть в базе VirusTotal (то есть проверялся раньше) и информация об этом объекте может быть получена, то значение этого поля будет равно единице; если запрашиваемый объект находится в очереди на анализ, значение поля будет -2; если запрашиваемый объект отсутствует в базе VirusTotal — равно нулю;
  • verbose_msg предоставляет более подробное описание значения response_code (например, Scan finished, information embedded после отправки файла на сканирование).

Остальная информация, содержащаяся в ответном объекте JSON, зависит от того, какая функция API была использована.

Отправка файла на сервер для сканирования

Для отправки файла на сканирование необходимо сформировать POST-запрос на адрес https://www.virustotal.com/vtapi/v2, при этом в запросе нужно указать ключ доступа к API и передать сам файл (здесь есть ограничение на размер файла — не более 32 Мбайт). Это может выглядеть следующим образом (используем Python):

import json
import requests
...
api_url = 'https://www.virustotal.com/vtapi/v2/file/scan'
params = dict(apikey='<ключ доступа>')
with open('<путь к файлу>', 'rb') as file:
  files = dict(file=('<путь к файлу>', file))
  response = requests.post(api_url, files=files, params=params)
if response.status_code == 200:
  result=response.json()
  print(json.dumps(result, sort_keys=False, indent=4))
...

Здесь вместо строки <ключ доступа> необходимо вставить свой ключ доступа к API, а вместо <путь к файлу> — путь к файлу, который ты будешь отправлять в VirusTotal. Если у тебя нет библиотеки requests, то поставь ее командой pip install requests.

В ответ, если все прошло успешно и код состояния HTTP равен 200, мы получим примерно вот такую картину:

{
  "response_code": 1,
  "verbose_msg": "Scan request successfully queued, come back later for the report",
  "scan_id": "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f-1577043276",
  "resource": "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f",
  "sha1": "3395856ce81f2b7382dee72602f798b642f14140",
  "md5": "44d88612fea8a8f36de82e1278abb02f",
  "sha256": "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f",
  "permalink": "https://www.virustotal.com/file/275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f/analysis/1577043276/"  
}

Здесь мы видим значения response_code и verbose_msg, а также хеши файла SHA-256, SHA-1 и MD5, ссылку на результаты сканирования файла на сайте permalink и идентификатор файла scan_id.

INFO

В приведенных в статье примерах кода опущена обработка ошибок. Помни, что в ходе открытия файла или отправки запросов на сервер могут возникать исключения: FileNotFoundError, если файла нет, requests.ConnectionError, requests.Timeout при ошибках соединения и так далее.

Получение отчета о последнем сканировании файла

Используя какой-либо из хешей или значение scan_id из ответа, можно получить отчет по последнему сканированию файла (если файл уже загружался на VirusTotal). Для этого нужно сформировать GET-запрос и в запросе указать ключ доступа и идентификатор файла. Например, если у нас есть scan_id из предыдущего примера, то запрос будет выглядеть так:

import json
import requests
...
api_url = 'https://www.virustotal.com/vtapi/v2/file/report'
params = dict(apikey='<ключ доступа>', resource='275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f-1577043276')
response = requests.get(api_url, params=params)
if response.status_code == 200:
  result=response.json()
  print(json.dumps(result, sort_keys=False, indent=4))
...

В случае успеха в ответ мы увидим следующее:

{
  "response_code": 1,
  "verbose_msg": "Scan finished, information embedded",
  "resource": "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f",
  "sha1": "3395856ce81f2b7382dee72602f798b642f14140",
  "md5": "44d88612fea8a8f36de82e1278abb02f",
  "sha256": "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f",
  "scan_date": "2019-11-27 08:06:03",
  "permalink": "https://www.virustotal.com/file/275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f/analysis/1577043276/",
  "positives": 59,
  "total": 69,
  "scans": {
    "Bkav": {
      "detected": true,
      "version": "1.3.0.9899",
      "result": "DOS.EiracA.Trojan",
      "update": "20191220"
    },
    "DrWeb": {
      "detected": true,
      "version": "7.0.42.9300",
      "result": "EICAR Test File (NOT a Virus!)",
       "update": "20191222"
    },
    "MicroWorld-eScan": {
      "detected": true,
      "version": "14.0.297.0",
      "result": "EICAR-Test-File",
      "update": "20191222"
    },
    ...
  ...
  "Panda": {
    "detected": true,
    "version": "4.6.4.2",
    "result": "EICAR-AV-TEST-FILE",
    "update": "20191222"
  },
  "Qihoo-360": {
    "detected": true,
    "version": "1.0.0.1120",
    "result": "qex.eicar.gen.gen",
    "update": "20191222"
  }
}

Здесь, как и в первом примере, получаем значения хешей файла, scan_id, permalink, значения response_code и verbose_msg. Также видим результаты сканирования файла антивирусами и общие результаты оценки total — сколько всего антивирусных движков было задействовано в проверке и positives — сколько антивирусов дали положительный вердикт.

Чтобы вывести результаты сканирования всеми антивирусами в удобоваримом виде, можно, например, написать что-то в таком роде:

import requests
...
api_url = 'https://www.virustotal.com/vtapi/v2/file/report'
params = dict(apikey='<ключ доступа>', resource='275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f-1577043276')
response = requests.get(api_url, params=params)
if response.status_code == 200:
  result=response.json()
  for key in result['scans']:
    print(key)
    print('  Detected: ', result['scans'][key]['detected'])
    print('  Version: ', result['scans'][key]['version'])
    print('  Update: ', result['scans'][key]['update'])
    print('  Result: ', 'result['scans'][key]['result'])
...
Вывод на экран информации о результатах сканирования файла на VirusTotal с использованием разных антивирусных движков
Вывод на экран информации о результатах сканирования файла на VirusTotal с использованием разных антивирусных движков

Отправка URL на сервер для сканирования

Чтобы отправить URL для сканирования, нам необходимо сформировать и послать POST-запрос, содержащий ключ доступа и сам URL:

import json
import requests
...
api_url = 'https://www.virustotal.com/vtapi/v2/url/scan'
params = dict(apikey='<ключ доступа>', url='https://xakep.ru/author/drobotun/')
response = requests.post(api_url, data=params)
if response.status_code == 200:
  result=response.json()
  print(json.dumps(result, sort_keys=False, indent=4))
...

В ответ мы получим примерно то же, что и при отправке файла, за исключением значений хеша. Содержимое поля scan_id можно использовать для получения отчета о сканировании данного URL.

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


1 комментарий

  1. Аватар

    Laglag

    20.01.2020 в 13:08

    круто теперь можно написать примитивный антивирус) спасибо

Оставить мнение